diff options
Diffstat (limited to 'git-stash.sh')
-rwxr-xr-x | git-stash.sh | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/git-stash.sh b/git-stash.sh index 5619da5c1..c76669284 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -7,7 +7,8 @@ USAGE="list [<options>] or: $dashless drop [-q|--quiet] [<stash>] or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>] or: $dashless branch <branchname> [<stash>] - or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] [<message>]] + or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet] + [-u|--include-untracked] [-a|--all] [<message>]] or: $dashless clear" SUBDIRECTORY_OK=Yes @@ -34,7 +35,14 @@ fi no_changes () { git diff-index --quiet --cached HEAD --ignore-submodules -- && - git diff-files --quiet --ignore-submodules + git diff-files --quiet --ignore-submodules && + (test -z "$untracked" || test -z "$(untracked_files)") +} + +untracked_files () { + excl_opt=--exclude-standard + test "$untracked" = "all" && excl_opt= + git ls-files -o -z $excl_opt } clear_stash () { @@ -50,6 +58,7 @@ clear_stash () { create_stash () { stash_msg="$1" + untracked="$2" git update-index -q --refresh if no_changes @@ -79,6 +88,25 @@ create_stash () { git commit-tree $i_tree -p $b_commit) || die "$(gettext "Cannot save the current index state")" + if test -n "$untracked" + then + # Untracked files are stored by themselves in a parentless commit, for + # ease of unpacking later. + u_commit=$( + untracked_files | ( + export GIT_INDEX_FILE="$TMPindex" + rm -f "$TMPindex" && + git update-index -z --add --remove --stdin && + u_tree=$(git write-tree) && + printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree && + rm -f "$TMPindex" + ) ) || die "Cannot save the untracked files" + + untracked_commit_option="-p $u_commit"; + else + untracked_commit_option= + fi + if test -z "$patch_mode" then @@ -123,13 +151,14 @@ create_stash () { stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg") fi w_commit=$(printf '%s\n' "$stash_msg" | - git commit-tree $w_tree -p $b_commit -p $i_commit) || - die "$(gettext "Cannot record working tree state")" + git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) || + die "$(gettext "Cannot record working tree state")" } save_stash () { keep_index= patch_mode= + untracked= while test $# != 0 do case "$1" in @@ -147,6 +176,12 @@ save_stash () { -q|--quiet) GIT_QUIET=t ;; + -u|--include-untracked) + untracked=untracked + ;; + -a|--all) + untracked=all + ;; --) shift break @@ -163,8 +198,8 @@ save_stash () { # $ git stash save --blah-blah 2>&1 | head -n 2 # error: unknown option for 'stash save': --blah-blah # To provide a message, use git stash save -- '--blah-blah' - eval_gettext "$("error: unknown option for 'stash save': \$option - To provide a message, use git stash save -- '\$option'")"; echo + eval_gettextln "$("error: unknown option for 'stash save': \$option + To provide a message, use git stash save -- '\$option'")" usage ;; *) @@ -174,6 +209,11 @@ save_stash () { shift done + if test -n "$patch_mode" && test -n "$untracked" + then + die "Can't use --patch and --include-untracked or --all at the same time" + fi + stash_msg="$*" git update-index -q --refresh @@ -185,7 +225,7 @@ save_stash () { test -f "$GIT_DIR/logs/$ref_stash" || clear_stash || die "$(gettext "Cannot initialize stash")" - create_stash "$stash_msg" + create_stash "$stash_msg" $untracked # Make sure the reflog for stash is kept. : >>"$GIT_DIR/logs/$ref_stash" @@ -197,6 +237,11 @@ save_stash () { if test -z "$patch_mode" then git reset --hard ${GIT_QUIET:+-q} + test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION= + if test -n "$untracked" + then + git clean --force --quiet -d $CLEAN_X_OPTION + fi if test "$keep_index" = "t" && test -n $i_tree then @@ -246,9 +291,11 @@ show_stash () { # w_commit is set to the commit containing the working tree # b_commit is set to the base commit # i_commit is set to the commit containing the index tree +# u_commit is set to the commit containing the untracked files tree # w_tree is set to the working tree # b_tree is set to the base tree # i_tree is set to the index tree +# u_tree is set to the untracked files tree # # GIT_QUIET is set to t if -q is specified # INDEX_OPTION is set to --index if --index is specified. @@ -273,9 +320,11 @@ parse_flags_and_rev() w_commit= b_commit= i_commit= + u_commit= w_tree= b_tree= i_tree= + u_tree= REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1 @@ -326,6 +375,9 @@ parse_flags_and_rev() IS_STASH_LIKE=t && test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && IS_STASH_REF=t + + u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null) && + u_tree=$(git rev-parse $REV^3: 2>/dev/null) } is_stash_like() @@ -374,6 +426,14 @@ apply_stash () { git reset fi + if test -n "$u_tree" + then + GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" && + GIT_INDEX_FILE="$TMPindex" git checkout-index --all && + rm -f "$TMPindex" || + die 'Could not restore untracked files from stash' + fi + eval " GITHEAD_$w_tree='Stashed changes' && GITHEAD_$c_tree='Updated upstream' && @@ -410,10 +470,7 @@ apply_stash () { status=$? if test -n "$INDEX_OPTION" then - ( - gettext "Index was not unstashed." && - echo - ) >&2 + gettextln "Index was not unstashed." >&2 fi exit $status fi |