]> git.ipfire.org Git - thirdparty/git.git/blame - git-stash.sh
Merge branch 'maint' of git://github.com/git-l10n/git-po into maint
[thirdparty/git.git] / git-stash.sh
CommitLineData
f2c66ed1
NS
1#!/bin/sh
2# Copyright (c) 2007, Nanako Shiraishi
3
a5ab00c5
SB
4dashless=$(basename "$0" | sed -e 's/-/ /')
5USAGE="list [<options>]
fcdd0e92
SB
6 or: $dashless show [<stash>]
7 or: $dashless drop [-q|--quiet] [<stash>]
8 or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]
a5ab00c5 9 or: $dashless branch <branchname> [<stash>]
78751302
DC
10 or: $dashless [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]
11 [-u|--include-untracked] [-a|--all] [<message>]]
a5ab00c5 12 or: $dashless clear"
f2c66ed1 13
3cd2491a 14SUBDIRECTORY_OK=Yes
8f321a39 15OPTIONS_SPEC=
26b59b48 16START_DIR=`pwd`
f2c66ed1 17. git-sh-setup
8a583bec 18. git-sh-i18n
f2c66ed1 19require_work_tree
ceff079b 20cd_to_toplevel
f2c66ed1
NS
21
22TMP="$GIT_DIR/.git-stash.$$"
3ba2e865
JS
23TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$
24trap 'rm -f "$TMP-"* "$TMPindex"' 0
f2c66ed1
NS
25
26ref_stash=refs/stash
27
dda1f2a5
TR
28if git config --get-colorbool color.interactive; then
29 help_color="$(git config --get-color color.interactive.help 'red bold')"
30 reset_color="$(git config --get-color '' reset)"
31else
32 help_color=
33 reset_color=
34fi
35
f2c66ed1 36no_changes () {
6848d58c 37 git diff-index --quiet --cached HEAD --ignore-submodules -- &&
78751302
DC
38 git diff-files --quiet --ignore-submodules &&
39 (test -z "$untracked" || test -z "$(untracked_files)")
40}
41
42untracked_files () {
43 excl_opt=--exclude-standard
44 test "$untracked" = "all" && excl_opt=
45 git ls-files -o -z $excl_opt
f2c66ed1
NS
46}
47
48clear_stash () {
3023dc69
JH
49 if test $# != 0
50 then
b1440ce2 51 die "$(gettext "git stash clear with parameters is unimplemented")"
3023dc69 52 fi
0e32126f 53 if current=$(git rev-parse --verify $ref_stash 2>/dev/null)
7ab3cc70 54 then
a9ee9bf9 55 git update-ref -d $ref_stash $current
7ab3cc70 56 fi
f2c66ed1
NS
57}
58
bc9e7399 59create_stash () {
9f62e18a 60 stash_msg="$1"
78751302 61 untracked="$2"
9f62e18a 62
1eff26c0 63 git update-index -q --refresh
f2c66ed1
NS
64 if no_changes
65 then
f2c66ed1
NS
66 exit 0
67 fi
f12e925a 68
f2c66ed1 69 # state of the base commit
5be60078 70 if b_commit=$(git rev-parse --verify HEAD)
f2c66ed1 71 then
b0e621ad 72 head=$(git rev-list --oneline -n 1 HEAD --)
f2c66ed1 73 else
b1440ce2 74 die "$(gettext "You do not have the initial commit yet")"
f2c66ed1
NS
75 fi
76
5be60078 77 if branch=$(git symbolic-ref -q HEAD)
f2c66ed1
NS
78 then
79 branch=${branch#refs/heads/}
80 else
81 branch='(no branch)'
82 fi
83 msg=$(printf '%s: %s' "$branch" "$head")
84
85 # state of the index
5be60078 86 i_tree=$(git write-tree) &&
6143fa2c 87 i_commit=$(printf 'index on %s\n' "$msg" |
5be60078 88 git commit-tree $i_tree -p $b_commit) ||
b1440ce2 89 die "$(gettext "Cannot save the current index state")"
f2c66ed1 90
78751302
DC
91 if test -n "$untracked"
92 then
93 # Untracked files are stored by themselves in a parentless commit, for
94 # ease of unpacking later.
95 u_commit=$(
96 untracked_files | (
97 export GIT_INDEX_FILE="$TMPindex"
98 rm -f "$TMPindex" &&
99 git update-index -z --add --remove --stdin &&
100 u_tree=$(git write-tree) &&
101 printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree &&
102 rm -f "$TMPindex"
103 ) ) || die "Cannot save the untracked files"
104
105 untracked_commit_option="-p $u_commit";
106 else
107 untracked_commit_option=
108 fi
109
dda1f2a5
TR
110 if test -z "$patch_mode"
111 then
112
113 # state of the working tree
114 w_tree=$( (
3ba2e865
JS
115 git read-tree --index-output="$TMPindex" -m $i_tree &&
116 GIT_INDEX_FILE="$TMPindex" &&
dda1f2a5 117 export GIT_INDEX_FILE &&
44df2e29
JM
118 git diff --name-only -z HEAD -- >"$TMP-stagenames" &&
119 git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
dda1f2a5 120 git write-tree &&
3ba2e865 121 rm -f "$TMPindex"
dda1f2a5 122 ) ) ||
b1440ce2 123 die "$(gettext "Cannot save the current worktree state")"
dda1f2a5
TR
124
125 else
126
b24f56d6 127 rm -f "$TMP-index" &&
dda1f2a5
TR
128 GIT_INDEX_FILE="$TMP-index" git read-tree HEAD &&
129
130 # find out what the user wants
131 GIT_INDEX_FILE="$TMP-index" \
132 git add--interactive --patch=stash -- &&
133
134 # state of the working tree
135 w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
b1440ce2 136 die "$(gettext "Cannot save the current worktree state")"
f2c66ed1 137
44df2e29 138 git diff-tree -p HEAD $w_tree -- >"$TMP-patch" &&
dda1f2a5 139 test -s "$TMP-patch" ||
b1440ce2 140 die "$(gettext "No changes selected")"
dda1f2a5
TR
141
142 rm -f "$TMP-index" ||
b1440ce2 143 die "$(gettext "Cannot remove temporary index (can't happen)")"
dda1f2a5
TR
144
145 fi
146
f2c66ed1 147 # create the stash
9f62e18a
JH
148 if test -z "$stash_msg"
149 then
150 stash_msg=$(printf 'WIP on %s' "$msg")
151 else
152 stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
153 fi
154 w_commit=$(printf '%s\n' "$stash_msg" |
22f41286
JH
155 git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||
156 die "$(gettext "Cannot record working tree state")"
bc9e7399 157}
f2c66ed1 158
bd514cad
RR
159store_stash () {
160 while test $# != 0
161 do
162 case "$1" in
163 -m|--message)
164 shift
165 stash_msg="$1"
166 ;;
167 -q|--quiet)
168 quiet=t
169 ;;
170 *)
171 break
172 ;;
173 esac
174 shift
175 done
176 test $# = 1 ||
177 die "$(eval_gettext "\"$dashless store\" requires one <commit> argument")"
178
179 w_commit="$1"
180 if test -z "$stash_msg"
181 then
182 stash_msg="Created via \"git stash store\"."
183 fi
184
185 # Make sure the reflog for stash is kept.
186 : >>"$GIT_DIR/logs/$ref_stash"
187 git update-ref -m "$stash_msg" $ref_stash $w_commit
188 ret=$?
189 test $ret != 0 && test -z $quiet &&
190 die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
191 return $ret
192}
193
bc9e7399 194save_stash () {
7bedebca 195 keep_index=
dda1f2a5 196 patch_mode=
78751302 197 untracked=
fcdd0e92
SB
198 while test $# != 0
199 do
200 case "$1" in
ea41cfc4 201 -k|--keep-index)
fcdd0e92
SB
202 keep_index=t
203 ;;
dda1f2a5 204 --no-keep-index)
3a243f70 205 keep_index=n
dda1f2a5
TR
206 ;;
207 -p|--patch)
208 patch_mode=t
3a243f70
DM
209 # only default to keep if we don't already have an override
210 test -z "$keep_index" && keep_index=t
fcdd0e92
SB
211 ;;
212 -q|--quiet)
213 GIT_QUIET=t
214 ;;
78751302
DC
215 -u|--include-untracked)
216 untracked=untracked
217 ;;
218 -a|--all)
219 untracked=all
220 ;;
3c2eb80f
MM
221 --)
222 shift
223 break
224 ;;
225 -*)
eed10649
ÆAB
226 option="$1"
227 # TRANSLATORS: $option is an invalid option, like
228 # `--blah-blah'. The 7 spaces at the beginning of the
229 # second line correspond to "error: ". So you should line
230 # up the second line with however many characters the
231 # translation of "error: " takes in your language. E.g. in
232 # English this is:
233 #
234 # $ git stash save --blah-blah 2>&1 | head -n 2
235 # error: unknown option for 'stash save': --blah-blah
236 # To provide a message, use git stash save -- '--blah-blah'
ed3c400c
RL
237 eval_gettextln "error: unknown option for 'stash save': \$option
238 To provide a message, use git stash save -- '\$option'"
3c2eb80f
MM
239 usage
240 ;;
fcdd0e92
SB
241 *)
242 break
243 ;;
244 esac
7bedebca 245 shift
fcdd0e92 246 done
7bedebca 247
78751302
DC
248 if test -n "$patch_mode" && test -n "$untracked"
249 then
d88acc91 250 die "Can't use --patch and --include-untracked or --all at the same time"
78751302
DC
251 fi
252
47629dcf 253 stash_msg="$*"
bc9e7399 254
1eff26c0 255 git update-index -q --refresh
bc9e7399
JH
256 if no_changes
257 then
5a175871 258 say "$(gettext "No local changes to save")"
bc9e7399
JH
259 exit 0
260 fi
261 test -f "$GIT_DIR/logs/$ref_stash" ||
b1440ce2 262 clear_stash || die "$(gettext "Cannot initialize stash")"
bc9e7399 263
78751302 264 create_stash "$stash_msg" $untracked
bd514cad
RR
265 store_stash -m "$stash_msg" -q $w_commit ||
266 die "$(gettext "Cannot save the current status")"
fcdd0e92 267 say Saved working directory and index state "$stash_msg"
7bedebca 268
dda1f2a5 269 if test -z "$patch_mode"
7bedebca 270 then
dda1f2a5 271 git reset --hard ${GIT_QUIET:+-q}
78751302
DC
272 test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
273 if test -n "$untracked"
274 then
7474b8b4 275 git clean --force --quiet -d $CLEAN_X_OPTION
78751302 276 fi
dda1f2a5 277
3a243f70 278 if test "$keep_index" = "t" && test -n $i_tree
dda1f2a5
TR
279 then
280 git read-tree --reset -u $i_tree
281 fi
282 else
283 git apply -R < "$TMP-patch" ||
b1440ce2 284 die "$(gettext "Cannot remove worktree changes")"
dda1f2a5 285
3a243f70 286 if test "$keep_index" != "t"
dda1f2a5
TR
287 then
288 git reset
289 fi
7bedebca 290 fi
f2c66ed1
NS
291}
292
401de405 293have_stash () {
0e32126f 294 git rev-parse --verify $ref_stash >/dev/null 2>&1
401de405
JK
295}
296
f2c66ed1 297list_stash () {
401de405 298 have_stash || return 0
391c53bd 299 git log --format="%gd: %gs" -g "$@" $ref_stash --
f2c66ed1
NS
300}
301
302show_stash () {
a9bf09e1 303 assert_stash_like "$@"
14cd4581 304
a9bf09e1 305 git diff ${FLAGS:---stat} $b_commit $w_commit
f2c66ed1
NS
306}
307
ef763129
JS
308#
309# Parses the remaining options looking for flags and
310# at most one revision defaulting to ${ref_stash}@{0}
311# if none found.
312#
313# Derives related tree and commit objects from the
314# revision, if one is found.
315#
316# stash records the work tree, and is a merge between the
317# base commit (first parent) and the index tree (second parent).
318#
319# REV is set to the symbolic version of the specified stash-like commit
320# IS_STASH_LIKE is non-blank if ${REV} looks like a stash
321# IS_STASH_REF is non-blank if the ${REV} looks like a stash ref
322# s is set to the SHA1 of the stash commit
323# w_commit is set to the commit containing the working tree
324# b_commit is set to the base commit
325# i_commit is set to the commit containing the index tree
78751302 326# u_commit is set to the commit containing the untracked files tree
ef763129
JS
327# w_tree is set to the working tree
328# b_tree is set to the base tree
329# i_tree is set to the index tree
78751302 330# u_tree is set to the untracked files tree
ef763129
JS
331#
332# GIT_QUIET is set to t if -q is specified
333# INDEX_OPTION is set to --index if --index is specified.
334# FLAGS is set to the remaining flags
335#
336# dies if:
337# * too many revisions specified
338# * no revision is specified and there is no stash stack
339# * a revision is specified which cannot be resolve to a SHA1
340# * a non-existent stash reference is specified
341#
342
343parse_flags_and_rev()
344{
345 test "$PARSE_CACHE" = "$*" && return 0 # optimisation
346 PARSE_CACHE="$*"
347
348 IS_STASH_LIKE=
349 IS_STASH_REF=
350 INDEX_OPTION=
351 s=
352 w_commit=
353 b_commit=
354 i_commit=
78751302 355 u_commit=
ef763129
JS
356 w_tree=
357 b_tree=
358 i_tree=
78751302 359 u_tree=
ef763129 360
59d418fe 361 REV=$(git rev-parse --no-flags --symbolic "$@") || exit 1
ef763129
JS
362
363 FLAGS=
2bea593b 364 for opt
ef763129 365 do
2bea593b
JS
366 case "$opt" in
367 -q|--quiet)
368 GIT_QUIET=-t
369 ;;
ef763129
JS
370 --index)
371 INDEX_OPTION=--index
372 ;;
2bea593b
JS
373 -*)
374 FLAGS="${FLAGS}${FLAGS:+ }$opt"
ef763129
JS
375 ;;
376 esac
ef763129
JS
377 done
378
379 set -- $REV
380
381 case $# in
382 0)
b1440ce2 383 have_stash || die "$(gettext "No stash found.")"
ef763129
JS
384 set -- ${ref_stash}@{0}
385 ;;
386 1)
387 :
388 ;;
389 *)
33ceddcf 390 die "$(eval_gettext "Too many revisions specified: \$REV")"
ef763129
JS
391 ;;
392 esac
393
155da748
ÆAB
394 REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null) || {
395 reference="$1"
396 die "$(eval_gettext "\$reference is not valid reference")"
397 }
ef763129
JS
398
399 i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null) &&
400 set -- $(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null) &&
401 s=$1 &&
402 w_commit=$1 &&
403 b_commit=$2 &&
404 w_tree=$3 &&
405 b_tree=$4 &&
406 i_tree=$5 &&
407 IS_STASH_LIKE=t &&
408 test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" &&
409 IS_STASH_REF=t
78751302
DC
410
411 u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null) &&
412 u_tree=$(git rev-parse $REV^3: 2>/dev/null)
ef763129
JS
413}
414
415is_stash_like()
416{
417 parse_flags_and_rev "$@"
418 test -n "$IS_STASH_LIKE"
419}
420
421assert_stash_like() {
777b6f13
ÆAB
422 is_stash_like "$@" || {
423 args="$*"
424 die "$(eval_gettext "'\$args' is not a stash-like commit")"
425 }
ef763129
JS
426}
427
428is_stash_ref() {
429 is_stash_like "$@" && test -n "$IS_STASH_REF"
430}
431
432assert_stash_ref() {
777b6f13
ÆAB
433 is_stash_ref "$@" || {
434 args="$*"
435 die "$(eval_gettext "'\$args' is not a stash reference")"
436 }
ef763129
JS
437}
438
f2c66ed1 439apply_stash () {
fcdd0e92 440
064ed100 441 assert_stash_like "$@"
f2c66ed1 442
b1440ce2 443 git update-index -q --refresh || die "$(gettext "unable to refresh index")"
5fd448f1
OA
444
445 # current index state
446 c_tree=$(git write-tree) ||
b1440ce2 447 die "$(gettext "Cannot apply a stash in the middle of a merge")"
5fd448f1 448
cbeaccc3 449 unstashed_index_tree=
064ed100 450 if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" &&
7bedebca 451 test "$c_tree" != "$i_tree"
cbeaccc3 452 then
89d750bf 453 git diff-tree --binary $s^2^..$s^2 | git apply --cached
150937c4 454 test $? -ne 0 &&
b1440ce2 455 die "$(gettext "Conflicts in index. Try without --index.")"
52070790 456 unstashed_index_tree=$(git write-tree) ||
b1440ce2 457 die "$(gettext "Could not save index tree")"
150937c4 458 git reset
cbeaccc3 459 fi
150937c4 460
78751302
DC
461 if test -n "$u_tree"
462 then
463 GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" &&
464 GIT_INDEX_FILE="$TMPindex" git checkout-index --all &&
465 rm -f "$TMPindex" ||
466 die 'Could not restore untracked files from stash'
467 fi
468
f2c66ed1
NS
469 eval "
470 GITHEAD_$w_tree='Stashed changes' &&
471 GITHEAD_$c_tree='Updated upstream' &&
472 GITHEAD_$b_tree='Version stash was based on' &&
473 export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
474 "
475
fcdd0e92
SB
476 if test -n "$GIT_QUIET"
477 then
69ae92bd 478 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
fcdd0e92 479 fi
52070790 480 if git merge-recursive $b_tree -- $c_tree $w_tree
f2c66ed1
NS
481 then
482 # No conflict
cbeaccc3
JH
483 if test -n "$unstashed_index_tree"
484 then
485 git read-tree "$unstashed_index_tree"
83b3df7d
JH
486 else
487 a="$TMP-added" &&
89d750bf 488 git diff-index --cached --name-only --diff-filter=A $c_tree >"$a" &&
83b3df7d
JH
489 git read-tree --reset $c_tree &&
490 git update-index --add --stdin <"$a" ||
b1440ce2 491 die "$(gettext "Cannot unstage modified files")"
83b3df7d 492 rm -f "$a"
cbeaccc3 493 fi
fcdd0e92
SB
494 squelch=
495 if test -n "$GIT_QUIET"
496 then
497 squelch='>/dev/null 2>&1'
498 fi
26b59b48 499 (cd "$START_DIR" && eval "git status $squelch") || :
f2c66ed1
NS
500 else
501 # Merge conflict; keep the exit status from merge-recursive
150937c4 502 status=$?
743bf6d8 503 git rerere
064ed100 504 if test -n "$INDEX_OPTION"
cbeaccc3 505 then
6fdd50e9 506 gettextln "Index was not unstashed." >&2
cbeaccc3 507 fi
150937c4 508 exit $status
f2c66ed1
NS
509 fi
510}
511
f276872d
JS
512pop_stash() {
513 assert_stash_ref "$@"
514
515 apply_stash "$@" &&
516 drop_stash "$@"
517}
518
e25d5f9c 519drop_stash () {
92e39e44 520 assert_stash_ref "$@"
e25d5f9c 521
92e39e44 522 git reflog delete --updateref --rewrite "${REV}" &&
d4ca6c8b
ÆAB
523 say "$(eval_gettext "Dropped \${REV} (\$s)")" ||
524 die "$(eval_gettext "\${REV}: Could not drop stash entry")"
e25d5f9c
BC
525
526 # clear_stash if we just dropped the last stash entry
44df2e29 527 git rev-parse --verify "$ref_stash@{0}" >/dev/null 2>&1 || clear_stash
e25d5f9c
BC
528}
529
656b5034 530apply_to_branch () {
b1440ce2 531 test -n "$1" || die "$(gettext "No branch name specified")"
656b5034 532 branch=$1
fb433dc9 533 shift 1
656b5034 534
fb433dc9
JS
535 set -- --index "$@"
536 assert_stash_like "$@"
537
538 git checkout -b $branch $REV^ &&
57693d03
JS
539 apply_stash "$@" && {
540 test -z "$IS_STASH_REF" || drop_stash "$@"
541 }
656b5034
AMS
542}
543
ef763129 544PARSE_CACHE='--not-parsed'
3c2eb80f
MM
545# The default command is "save" if nothing but options are given
546seen_non_option=
547for opt
548do
549 case "$opt" in
550 -*) ;;
551 *) seen_non_option=t; break ;;
552 esac
553done
554
555test -n "$seen_non_option" || set "save" "$@"
556
f2c66ed1
NS
557# Main command set
558case "$1" in
fcb10a96
JH
559list)
560 shift
f2c66ed1
NS
561 list_stash "$@"
562 ;;
563show)
564 shift
565 show_stash "$@"
566 ;;
683befa1
KL
567save)
568 shift
47629dcf 569 save_stash "$@"
683befa1 570 ;;
f2c66ed1
NS
571apply)
572 shift
573 apply_stash "$@"
574 ;;
575clear)
3023dc69
JH
576 shift
577 clear_stash "$@"
f2c66ed1 578 ;;
bc9e7399 579create)
0719f300 580 shift
bc9e7399
JH
581 create_stash "$*" && echo "$w_commit"
582 ;;
bd514cad
RR
583store)
584 shift
585 store_stash "$@"
586 ;;
e25d5f9c
BC
587drop)
588 shift
589 drop_stash "$@"
590 ;;
bd56ff54
BC
591pop)
592 shift
f276872d 593 pop_stash "$@"
bd56ff54 594 ;;
656b5034
AMS
595branch)
596 shift
597 apply_to_branch "$@"
598 ;;
f2c66ed1 599*)
3c2eb80f
MM
600 case $# in
601 0)
97bc00a4 602 save_stash &&
5a175871 603 say "$(gettext "(To restore them type \"git stash apply\")")"
ea41cfc4
JS
604 ;;
605 *)
683befa1 606 usage
ea41cfc4 607 esac
9f62e18a 608 ;;
f2c66ed1 609esac