packfile: allow reprepare_packed_git to handle arbitrary repositories
[git] / git-stash.sh
1 #!/bin/sh
2 # Copyright (c) 2007, Nanako Shiraishi
3
4 dashless=$(basename "$0" | sed -e 's/-/ /')
5 USAGE="list [<options>]
6    or: $dashless show [<stash>]
7    or: $dashless drop [-q|--quiet] [<stash>]
8    or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
9    or: $dashless branch <branchname> [<stash>]
10    or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
11                       [-u|--include-untracked] [-a|--all] [<message>]
12    or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]
13                        [-u|--include-untracked] [-a|--all] [-m <message>]
14                        [-- <pathspec>...]]
15    or: $dashless clear"
16
17 SUBDIRECTORY_OK=Yes
18 OPTIONS_SPEC=
19 START_DIR=$(pwd)
20 . git-sh-setup
21 require_work_tree
22 prefix=$(git rev-parse --show-prefix) || exit 1
23 cd_to_toplevel
24
25 TMP="$GIT_DIR/.git-stash.$$"
26 TMPindex=${GIT_INDEX_FILE-"$(git rev-parse --git-path index)"}.stash.$$
27 trap 'rm -f "$TMP-"* "$TMPindex"' 0
28
29 ref_stash=refs/stash
30
31 if git config --get-colorbool color.interactive; then
32        help_color="$(git config --get-color color.interactive.help 'red bold')"
33        reset_color="$(git config --get-color '' reset)"
34 else
35        help_color=
36        reset_color=
37 fi
38
39 no_changes () {
40         git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
41         git diff-files --quiet --ignore-submodules -- "$@" &&
42         (test -z "$untracked" || test -z "$(untracked_files)")
43 }
44
45 untracked_files () {
46         if test "$1" = "-z"
47         then
48                 shift
49                 z=-z
50         else
51                 z=
52         fi
53         excl_opt=--exclude-standard
54         test "$untracked" = "all" && excl_opt=
55         git ls-files -o $z $excl_opt -- "$@"
56 }
57
58 clear_stash () {
59         if test $# != 0
60         then
61                 die "$(gettext "git stash clear with parameters is unimplemented")"
62         fi
63         if current=$(git rev-parse --verify --quiet $ref_stash)
64         then
65                 git update-ref -d $ref_stash $current
66         fi
67 }
68
69 create_stash () {
70         stash_msg=
71         untracked=
72         while test $# != 0
73         do
74                 case "$1" in
75                 -m|--message)
76                         shift
77                         stash_msg=${1?"BUG: create_stash () -m requires an argument"}
78                         ;;
79                 -m*)
80                         stash_msg=${1#-m}
81                         ;;
82                 --message=*)
83                         stash_msg=${1#--message=}
84                         ;;
85                 -u|--include-untracked)
86                         shift
87                         untracked=${1?"BUG: create_stash () -u requires an argument"}
88                         ;;
89                 --)
90                         shift
91                         break
92                         ;;
93                 esac
94                 shift
95         done
96
97         git update-index -q --refresh
98         if no_changes "$@"
99         then
100                 exit 0
101         fi
102
103         # state of the base commit
104         if b_commit=$(git rev-parse --verify HEAD)
105         then
106                 head=$(git rev-list --oneline -n 1 HEAD --)
107         else
108                 die "$(gettext "You do not have the initial commit yet")"
109         fi
110
111         if branch=$(git symbolic-ref -q HEAD)
112         then
113                 branch=${branch#refs/heads/}
114         else
115                 branch='(no branch)'
116         fi
117         msg=$(printf '%s: %s' "$branch" "$head")
118
119         # state of the index
120         i_tree=$(git write-tree) &&
121         i_commit=$(printf 'index on %s\n' "$msg" |
122                 git commit-tree $i_tree -p $b_commit) ||
123                 die "$(gettext "Cannot save the current index state")"
124
125         if test -n "$untracked"
126         then
127                 # Untracked files are stored by themselves in a parentless commit, for
128                 # ease of unpacking later.
129                 u_commit=$(
130                         untracked_files -z "$@" | (
131                                 GIT_INDEX_FILE="$TMPindex" &&
132                                 export GIT_INDEX_FILE &&
133                                 rm -f "$TMPindex" &&
134                                 git update-index -z --add --remove --stdin &&
135                                 u_tree=$(git write-tree) &&
136                                 printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree  &&
137                                 rm -f "$TMPindex"
138                 ) ) || die "$(gettext "Cannot save the untracked files")"
139
140                 untracked_commit_option="-p $u_commit";
141         else
142                 untracked_commit_option=
143         fi
144
145         if test -z "$patch_mode"
146         then
147
148                 # state of the working tree
149                 w_tree=$( (
150                         git read-tree --index-output="$TMPindex" -m $i_tree &&
151                         GIT_INDEX_FILE="$TMPindex" &&
152                         export GIT_INDEX_FILE &&
153                         git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
154                         git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
155                         git write-tree &&
156                         rm -f "$TMPindex"
157                 ) ) ||
158                         die "$(gettext "Cannot save the current worktree state")"
159
160         else
161
162                 rm -f "$TMP-index" &&
163                 GIT_INDEX_FILE="$TMP-index" git read-tree HEAD &&
164
165                 # find out what the user wants
166                 GIT_INDEX_FILE="$TMP-index" \
167                         git add--interactive --patch=stash -- "$@" &&
168
169                 # state of the working tree
170                 w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
171                 die "$(gettext "Cannot save the current worktree state")"
172
173                 git diff-tree -p HEAD $w_tree -- >"$TMP-patch" &&
174                 test -s "$TMP-patch" ||
175                 die "$(gettext "No changes selected")"
176
177                 rm -f "$TMP-index" ||
178                 die "$(gettext "Cannot remove temporary index (can't happen)")"
179
180         fi
181
182         # create the stash
183         if test -z "$stash_msg"
184         then
185                 stash_msg=$(printf 'WIP on %s' "$msg")
186         else
187                 stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
188         fi
189         w_commit=$(printf '%s\n' "$stash_msg" |
190         git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||
191         die "$(gettext "Cannot record working tree state")"
192 }
193
194 store_stash () {
195         while test $# != 0
196         do
197                 case "$1" in
198                 -m|--message)
199                         shift
200                         stash_msg="$1"
201                         ;;
202                 -m*)
203                         stash_msg=${1#-m}
204                         ;;
205                 --message=*)
206                         stash_msg=${1#--message=}
207                         ;;
208                 -q|--quiet)
209                         quiet=t
210                         ;;
211                 *)
212                         break
213                         ;;
214                 esac
215                 shift
216         done
217         test $# = 1 ||
218         die "$(eval_gettext "\"$dashless store\" requires one <commit> argument")"
219
220         w_commit="$1"
221         if test -z "$stash_msg"
222         then
223                 stash_msg="Created via \"git stash store\"."
224         fi
225
226         git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
227         ret=$?
228         test $ret != 0 && test -z "$quiet" &&
229         die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
230         return $ret
231 }
232
233 push_stash () {
234         keep_index=
235         patch_mode=
236         untracked=
237         stash_msg=
238         while test $# != 0
239         do
240                 case "$1" in
241                 -k|--keep-index)
242                         keep_index=t
243                         ;;
244                 --no-keep-index)
245                         keep_index=n
246                         ;;
247                 -p|--patch)
248                         patch_mode=t
249                         # only default to keep if we don't already have an override
250                         test -z "$keep_index" && keep_index=t
251                         ;;
252                 -q|--quiet)
253                         GIT_QUIET=t
254                         ;;
255                 -u|--include-untracked)
256                         untracked=untracked
257                         ;;
258                 -a|--all)
259                         untracked=all
260                         ;;
261                 -m|--message)
262                         shift
263                         test -z ${1+x} && usage
264                         stash_msg=$1
265                         ;;
266                 -m*)
267                         stash_msg=${1#-m}
268                         ;;
269                 --message=*)
270                         stash_msg=${1#--message=}
271                         ;;
272                 --help)
273                         show_help
274                         ;;
275                 --)
276                         shift
277                         break
278                         ;;
279                 -*)
280                         option="$1"
281                         eval_gettextln "error: unknown option for 'stash push': \$option"
282                         usage
283                         ;;
284                 *)
285                         break
286                         ;;
287                 esac
288                 shift
289         done
290
291         eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
292
293         if test -n "$patch_mode" && test -n "$untracked"
294         then
295                 die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")"
296         fi
297
298         test -n "$untracked" || git ls-files --error-unmatch -- "$@" >/dev/null || exit 1
299
300         git update-index -q --refresh
301         if no_changes "$@"
302         then
303                 say "$(gettext "No local changes to save")"
304                 exit 0
305         fi
306
307         git reflog exists $ref_stash ||
308                 clear_stash || die "$(gettext "Cannot initialize stash")"
309
310         create_stash -m "$stash_msg" -u "$untracked" -- "$@"
311         store_stash -m "$stash_msg" -q $w_commit ||
312         die "$(gettext "Cannot save the current status")"
313         say "$(eval_gettext "Saved working directory and index state \$stash_msg")"
314
315         if test -z "$patch_mode"
316         then
317                 test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
318                 if test -n "$untracked"
319                 then
320                         git clean --force --quiet -d $CLEAN_X_OPTION -- "$@"
321                 fi
322
323                 if test $# != 0
324                 then
325                         git add -u -- "$@" |
326                         git checkout-index -z --force --stdin
327                         git diff-index -p --cached --binary HEAD -- "$@" | git apply --index -R
328                 else
329                         git reset --hard -q
330                 fi
331
332                 if test "$keep_index" = "t" && test -n "$i_tree"
333                 then
334                         git read-tree --reset $i_tree
335                         git ls-files -z --modified -- "$@" |
336                         git checkout-index -z --force --stdin
337                 fi
338         else
339                 git apply -R < "$TMP-patch" ||
340                 die "$(gettext "Cannot remove worktree changes")"
341
342                 if test "$keep_index" != "t"
343                 then
344                         git reset -q -- "$@"
345                 fi
346         fi
347 }
348
349 save_stash () {
350         push_options=
351         while test $# != 0
352         do
353                 case "$1" in
354                 --)
355                         shift
356                         break
357                         ;;
358                 -*)
359                         # pass all options through to push_stash
360                         push_options="$push_options $1"
361                         ;;
362                 *)
363                         break
364                         ;;
365                 esac
366                 shift
367         done
368
369         stash_msg="$*"
370
371         if test -z "$stash_msg"
372         then
373                 push_stash $push_options
374         else
375                 push_stash $push_options -m "$stash_msg"
376         fi
377 }
378
379 have_stash () {
380         git rev-parse --verify --quiet $ref_stash >/dev/null
381 }
382
383 list_stash () {
384         have_stash || return 0
385         git log --format="%gd: %gs" -g --first-parent -m "$@" $ref_stash --
386 }
387
388 show_stash () {
389         ALLOW_UNKNOWN_FLAGS=t
390         assert_stash_like "$@"
391
392         if test -z "$FLAGS"
393         then
394                 if test "$(git config --bool stash.showStat || echo true)" = "true"
395                 then
396                         FLAGS=--stat
397                 fi
398
399                 if test "$(git config --bool stash.showPatch || echo false)" = "true"
400                 then
401                         FLAGS=${FLAGS}${FLAGS:+ }-p
402                 fi
403
404                 if test -z "$FLAGS"
405                 then
406                         return 0
407                 fi
408         fi
409
410         git diff ${FLAGS} $b_commit $w_commit
411 }
412
413 show_help () {
414         exec git help stash
415         exit 1
416 }
417
418 #
419 # Parses the remaining options looking for flags and
420 # at most one revision defaulting to ${ref_stash}@{0}
421 # if none found.
422 #
423 # Derives related tree and commit objects from the
424 # revision, if one is found.
425 #
426 # stash records the work tree, and is a merge between the
427 # base commit (first parent) and the index tree (second parent).
428 #
429 #   REV is set to the symbolic version of the specified stash-like commit
430 #   IS_STASH_LIKE is non-blank if ${REV} looks like a stash
431 #   IS_STASH_REF is non-blank if the ${REV} looks like a stash ref
432 #   s is set to the SHA1 of the stash commit
433 #   w_commit is set to the commit containing the working tree
434 #   b_commit is set to the base commit
435 #   i_commit is set to the commit containing the index tree
436 #   u_commit is set to the commit containing the untracked files tree
437 #   w_tree is set to the working tree
438 #   b_tree is set to the base tree
439 #   i_tree is set to the index tree
440 #   u_tree is set to the untracked files tree
441 #
442 #   GIT_QUIET is set to t if -q is specified
443 #   INDEX_OPTION is set to --index if --index is specified.
444 #   FLAGS is set to the remaining flags (if allowed)
445 #
446 # dies if:
447 #   * too many revisions specified
448 #   * no revision is specified and there is no stash stack
449 #   * a revision is specified which cannot be resolve to a SHA1
450 #   * a non-existent stash reference is specified
451 #   * unknown flags were set and ALLOW_UNKNOWN_FLAGS is not "t"
452 #
453
454 parse_flags_and_rev()
455 {
456         test "$PARSE_CACHE" = "$*" && return 0 # optimisation
457         PARSE_CACHE="$*"
458
459         IS_STASH_LIKE=
460         IS_STASH_REF=
461         INDEX_OPTION=
462         s=
463         w_commit=
464         b_commit=
465         i_commit=
466         u_commit=
467         w_tree=
468         b_tree=
469         i_tree=
470         u_tree=
471
472         FLAGS=
473         REV=
474         for opt
475         do
476                 case "$opt" in
477                         -q|--quiet)
478                                 GIT_QUIET=-t
479                         ;;
480                         --index)
481                                 INDEX_OPTION=--index
482                         ;;
483                         --help)
484                                 show_help
485                         ;;
486                         -*)
487                                 test "$ALLOW_UNKNOWN_FLAGS" = t ||
488                                         die "$(eval_gettext "unknown option: \$opt")"
489                                 FLAGS="${FLAGS}${FLAGS:+ }$opt"
490                         ;;
491                         *)
492                                 REV="${REV}${REV:+ }'$opt'"
493                         ;;
494                 esac
495         done
496
497         eval set -- $REV
498
499         case $# in
500                 0)
501                         have_stash || die "$(gettext "No stash entries found.")"
502                         set -- ${ref_stash}@{0}
503                 ;;
504                 1)
505                         :
506                 ;;
507                 *)
508                         die "$(eval_gettext "Too many revisions specified: \$REV")"
509                 ;;
510         esac
511
512         case "$1" in
513                 *[!0-9]*)
514                         :
515                 ;;
516                 *)
517                         set -- "${ref_stash}@{$1}"
518                 ;;
519         esac
520
521         REV=$(git rev-parse --symbolic --verify --quiet "$1") || {
522                 reference="$1"
523                 die "$(eval_gettext "\$reference is not a valid reference")"
524         }
525
526         i_commit=$(git rev-parse --verify --quiet "$REV^2") &&
527         set -- $(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null) &&
528         s=$1 &&
529         w_commit=$1 &&
530         b_commit=$2 &&
531         w_tree=$3 &&
532         b_tree=$4 &&
533         i_tree=$5 &&
534         IS_STASH_LIKE=t &&
535         test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
536         IS_STASH_REF=t
537
538         u_commit=$(git rev-parse --verify --quiet "$REV^3") &&
539         u_tree=$(git rev-parse "$REV^3:" 2>/dev/null)
540 }
541
542 is_stash_like()
543 {
544         parse_flags_and_rev "$@"
545         test -n "$IS_STASH_LIKE"
546 }
547
548 assert_stash_like() {
549         is_stash_like "$@" || {
550                 args="$*"
551                 die "$(eval_gettext "'\$args' is not a stash-like commit")"
552         }
553 }
554
555 is_stash_ref() {
556         is_stash_like "$@" && test -n "$IS_STASH_REF"
557 }
558
559 assert_stash_ref() {
560         is_stash_ref "$@" || {
561                 args="$*"
562                 die "$(eval_gettext "'\$args' is not a stash reference")"
563         }
564 }
565
566 apply_stash () {
567
568         assert_stash_like "$@"
569
570         git update-index -q --refresh || die "$(gettext "unable to refresh index")"
571
572         # current index state
573         c_tree=$(git write-tree) ||
574                 die "$(gettext "Cannot apply a stash in the middle of a merge")"
575
576         unstashed_index_tree=
577         if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" &&
578                         test "$c_tree" != "$i_tree"
579         then
580                 git diff-tree --binary $s^2^..$s^2 | git apply --cached
581                 test $? -ne 0 &&
582                         die "$(gettext "Conflicts in index. Try without --index.")"
583                 unstashed_index_tree=$(git write-tree) ||
584                         die "$(gettext "Could not save index tree")"
585                 git reset
586         fi
587
588         if test -n "$u_tree"
589         then
590                 GIT_INDEX_FILE="$TMPindex" git read-tree "$u_tree" &&
591                 GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
592                 rm -f "$TMPindex" ||
593                 die "$(gettext "Could not restore untracked files from stash entry")"
594         fi
595
596         eval "
597                 GITHEAD_$w_tree='Stashed changes' &&
598                 GITHEAD_$c_tree='Updated upstream' &&
599                 GITHEAD_$b_tree='Version stash was based on' &&
600                 export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
601         "
602
603         if test -n "$GIT_QUIET"
604         then
605                 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
606         fi
607         if git merge-recursive $b_tree -- $c_tree $w_tree
608         then
609                 # No conflict
610                 if test -n "$unstashed_index_tree"
611                 then
612                         git read-tree "$unstashed_index_tree"
613                 else
614                         a="$TMP-added" &&
615                         git diff-index --cached --name-only --diff-filter=A $c_tree >"$a" &&
616                         git read-tree --reset $c_tree &&
617                         git update-index --add --stdin <"$a" ||
618                                 die "$(gettext "Cannot unstage modified files")"
619                         rm -f "$a"
620                 fi
621                 squelch=
622                 if test -n "$GIT_QUIET"
623                 then
624                         squelch='>/dev/null 2>&1'
625                 fi
626                 (cd "$START_DIR" && eval "git status $squelch") || :
627         else
628                 # Merge conflict; keep the exit status from merge-recursive
629                 status=$?
630                 git rerere
631                 if test -n "$INDEX_OPTION"
632                 then
633                         gettextln "Index was not unstashed." >&2
634                 fi
635                 exit $status
636         fi
637 }
638
639 pop_stash() {
640         assert_stash_ref "$@"
641
642         if apply_stash "$@"
643         then
644                 drop_stash "$@"
645         else
646                 status=$?
647                 say "$(gettext "The stash entry is kept in case you need it again.")"
648                 exit $status
649         fi
650 }
651
652 drop_stash () {
653         assert_stash_ref "$@"
654
655         git reflog delete --updateref --rewrite "${REV}" &&
656                 say "$(eval_gettext "Dropped \${REV} (\$s)")" ||
657                 die "$(eval_gettext "\${REV}: Could not drop stash entry")"
658
659         # clear_stash if we just dropped the last stash entry
660         git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
661         clear_stash
662 }
663
664 apply_to_branch () {
665         test -n "$1" || die "$(gettext "No branch name specified")"
666         branch=$1
667         shift 1
668
669         set -- --index "$@"
670         assert_stash_like "$@"
671
672         git checkout -b $branch $REV^ &&
673         apply_stash "$@" && {
674                 test -z "$IS_STASH_REF" || drop_stash "$@"
675         }
676 }
677
678 test "$1" = "-p" && set "push" "$@"
679
680 PARSE_CACHE='--not-parsed'
681 # The default command is "push" if nothing but options are given
682 seen_non_option=
683 for opt
684 do
685         case "$opt" in
686         --) break ;;
687         -*) ;;
688         *) seen_non_option=t; break ;;
689         esac
690 done
691
692 test -n "$seen_non_option" || set "push" "$@"
693
694 # Main command set
695 case "$1" in
696 list)
697         shift
698         list_stash "$@"
699         ;;
700 show)
701         shift
702         show_stash "$@"
703         ;;
704 save)
705         shift
706         save_stash "$@"
707         ;;
708 push)
709         shift
710         push_stash "$@"
711         ;;
712 apply)
713         shift
714         apply_stash "$@"
715         ;;
716 clear)
717         shift
718         clear_stash "$@"
719         ;;
720 create)
721         shift
722         create_stash -m "$*" && echo "$w_commit"
723         ;;
724 store)
725         shift
726         store_stash "$@"
727         ;;
728 drop)
729         shift
730         drop_stash "$@"
731         ;;
732 pop)
733         shift
734         pop_stash "$@"
735         ;;
736 branch)
737         shift
738         apply_to_branch "$@"
739         ;;
740 *)
741         case $# in
742         0)
743                 push_stash &&
744                 say "$(gettext "(To restore them type \"git stash apply\")")"
745                 ;;
746         *)
747                 usage
748         esac
749         ;;
750 esac