1#!/bin/sh
2#
3# Copyright (c) 2007 Johannes E Schindelin
4#
5
6test_description='Test git stash'
7
8. ./test-lib.sh
9
10test_expect_success 'stash some dirty working directory' '
11 echo 1 > file &&
12 git add file &&
13 echo unrelated >other-file &&
14 git add other-file &&
15 test_tick &&
16 git commit -m initial &&
17 echo 2 > file &&
18 git add file &&
19 echo 3 > file &&
20 test_tick &&
21 git stash &&
22 git diff-files --quiet &&
23 git diff-index --cached --quiet HEAD
24'
25
26cat > expect << EOF
27diff --git a/file b/file
28index 0cfbf08..00750ed 100644
29--- a/file
30+++ b/file
31@@ -1 +1 @@
32-2
33+3
34EOF
35
36test_expect_success 'parents of stash' '
37 test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
38 git diff stash^2..stash > output &&
39 test_cmp output expect
40'
41
42test_expect_success 'applying bogus stash does nothing' '
43 test_must_fail git stash apply stash@{1} &&
44 echo 1 >expect &&
45 test_cmp expect file
46'
47
48test_expect_success 'apply requires a clean index' '
49 test_when_finished "git reset --hard" &&
50 echo changed >other-file &&
51 git add other-file &&
52 test_must_fail git stash apply
53'
54
55test_expect_success 'apply does not need clean working directory' '
56 echo 4 >other-file &&
57 git stash apply &&
58 echo 3 >expect &&
59 test_cmp expect file
60'
61
62test_expect_success 'apply does not clobber working directory changes' '
63 git reset --hard &&
64 echo 4 >file &&
65 test_must_fail git stash apply &&
66 echo 4 >expect &&
67 test_cmp expect file
68'
69
70test_expect_success 'apply stashed changes' '
71 git reset --hard &&
72 echo 5 >other-file &&
73 git add other-file &&
74 test_tick &&
75 git commit -m other-file &&
76 git stash apply &&
77 test 3 = $(cat file) &&
78 test 1 = $(git show :file) &&
79 test 1 = $(git show HEAD:file)
80'
81
82test_expect_success 'apply stashed changes (including index)' '
83 git reset --hard HEAD^ &&
84 echo 6 > other-file &&
85 git add other-file &&
86 test_tick &&
87 git commit -m other-file &&
88 git stash apply --index &&
89 test 3 = $(cat file) &&
90 test 2 = $(git show :file) &&
91 test 1 = $(git show HEAD:file)
92'
93
94test_expect_success 'unstashing in a subdirectory' '
95 git reset --hard HEAD &&
96 mkdir subdir &&
97 (
98 cd subdir &&
99 git stash apply
100 )
101'
102
103test_expect_success 'drop top stash' '
104 git reset --hard &&
105 git stash list > stashlist1 &&
106 echo 7 > file &&
107 git stash &&
108 git stash drop &&
109 git stash list > stashlist2 &&
110 test_cmp stashlist1 stashlist2 &&
111 git stash apply &&
112 test 3 = $(cat file) &&
113 test 1 = $(git show :file) &&
114 test 1 = $(git show HEAD:file)
115'
116
117test_expect_success 'drop middle stash' '
118 git reset --hard &&
119 echo 8 > file &&
120 git stash &&
121 echo 9 > file &&
122 git stash &&
123 git stash drop stash@{1} &&
124 test 2 = $(git stash list | wc -l) &&
125 git stash apply &&
126 test 9 = $(cat file) &&
127 test 1 = $(git show :file) &&
128 test 1 = $(git show HEAD:file) &&
129 git reset --hard &&
130 git stash drop &&
131 git stash apply &&
132 test 3 = $(cat file) &&
133 test 1 = $(git show :file) &&
134 test 1 = $(git show HEAD:file)
135'
136
137test_expect_success 'stash pop' '
138 git reset --hard &&
139 git stash pop &&
140 test 3 = $(cat file) &&
141 test 1 = $(git show :file) &&
142 test 1 = $(git show HEAD:file) &&
143 test 0 = $(git stash list | wc -l)
144'
145
146cat > expect << EOF
147diff --git a/file2 b/file2
148new file mode 100644
149index 0000000..1fe912c
150--- /dev/null
151+++ b/file2
152@@ -0,0 +1 @@
153+bar2
154EOF
155
156cat > expect1 << EOF
157diff --git a/file b/file
158index 257cc56..5716ca5 100644
159--- a/file
160+++ b/file
161@@ -1 +1 @@
162-foo
163+bar
164EOF
165
166cat > expect2 << EOF
167diff --git a/file b/file
168index 7601807..5716ca5 100644
169--- a/file
170+++ b/file
171@@ -1 +1 @@
172-baz
173+bar
174diff --git a/file2 b/file2
175new file mode 100644
176index 0000000..1fe912c
177--- /dev/null
178+++ b/file2
179@@ -0,0 +1 @@
180+bar2
181EOF
182
183test_expect_success 'stash branch' '
184 echo foo > file &&
185 git commit file -m first &&
186 echo bar > file &&
187 echo bar2 > file2 &&
188 git add file2 &&
189 git stash &&
190 echo baz > file &&
191 git commit file -m second &&
192 git stash branch stashbranch &&
193 test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
194 test $(git rev-parse HEAD) = $(git rev-parse master^) &&
195 git diff --cached > output &&
196 test_cmp output expect &&
197 git diff > output &&
198 test_cmp output expect1 &&
199 git add file &&
200 git commit -m alternate\ second &&
201 git diff master..stashbranch > output &&
202 test_cmp output expect2 &&
203 test 0 = $(git stash list | wc -l)
204'
205
206test_expect_success 'apply -q is quiet' '
207 echo foo > file &&
208 git stash &&
209 git stash apply -q > output.out 2>&1 &&
210 test_must_be_empty output.out
211'
212
213test_expect_success 'save -q is quiet' '
214 git stash save --quiet > output.out 2>&1 &&
215 test_must_be_empty output.out
216'
217
218test_expect_success 'pop -q is quiet' '
219 git stash pop -q > output.out 2>&1 &&
220 test_must_be_empty output.out
221'
222
223test_expect_success 'pop -q --index works and is quiet' '
224 echo foo > file &&
225 git add file &&
226 git stash save --quiet &&
227 git stash pop -q --index > output.out 2>&1 &&
228 test foo = "$(git show :file)" &&
229 test_must_be_empty output.out
230'
231
232test_expect_success 'drop -q is quiet' '
233 git stash &&
234 git stash drop -q > output.out 2>&1 &&
235 test_must_be_empty output.out
236'
237
238test_expect_success 'stash -k' '
239 echo bar3 > file &&
240 echo bar4 > file2 &&
241 git add file2 &&
242 git stash -k &&
243 test bar,bar4 = $(cat file),$(cat file2)
244'
245
246test_expect_success 'stash --no-keep-index' '
247 echo bar33 > file &&
248 echo bar44 > file2 &&
249 git add file2 &&
250 git stash --no-keep-index &&
251 test bar,bar2 = $(cat file),$(cat file2)
252'
253
254test_expect_success 'stash --invalid-option' '
255 echo bar5 > file &&
256 echo bar6 > file2 &&
257 git add file2 &&
258 test_must_fail git stash --invalid-option &&
259 test_must_fail git stash save --invalid-option &&
260 test bar5,bar6 = $(cat file),$(cat file2) &&
261 git stash -- -message-starting-with-dash &&
262 test bar,bar2 = $(cat file),$(cat file2)
263'
264
265test_expect_success 'stash an added file' '
266 git reset --hard &&
267 echo new >file3 &&
268 git add file3 &&
269 git stash save "added file" &&
270 ! test -r file3 &&
271 git stash apply &&
272 test new = "$(cat file3)"
273'
274
275test_expect_success 'stash rm then recreate' '
276 git reset --hard &&
277 git rm file &&
278 echo bar7 >file &&
279 git stash save "rm then recreate" &&
280 test bar = "$(cat file)" &&
281 git stash apply &&
282 test bar7 = "$(cat file)"
283'
284
285test_expect_success 'stash rm and ignore' '
286 git reset --hard &&
287 git rm file &&
288 echo file >.gitignore &&
289 git stash save "rm and ignore" &&
290 test bar = "$(cat file)" &&
291 test file = "$(cat .gitignore)" &&
292 git stash apply &&
293 ! test -r file &&
294 test file = "$(cat .gitignore)"
295'
296
297test_expect_success 'stash rm and ignore (stage .gitignore)' '
298 git reset --hard &&
299 git rm file &&
300 echo file >.gitignore &&
301 git add .gitignore &&
302 git stash save "rm and ignore (stage .gitignore)" &&
303 test bar = "$(cat file)" &&
304 ! test -r .gitignore &&
305 git stash apply &&
306 ! test -r file &&
307 test file = "$(cat .gitignore)"
308'
309
310test_expect_success SYMLINKS 'stash file to symlink' '
311 git reset --hard &&
312 rm file &&
313 ln -s file2 file &&
314 git stash save "file to symlink" &&
315 test -f file &&
316 test bar = "$(cat file)" &&
317 git stash apply &&
318 case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
319'
320
321test_expect_success SYMLINKS 'stash file to symlink (stage rm)' '
322 git reset --hard &&
323 git rm file &&
324 ln -s file2 file &&
325 git stash save "file to symlink (stage rm)" &&
326 test -f file &&
327 test bar = "$(cat file)" &&
328 git stash apply &&
329 case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
330'
331
332test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
333 git reset --hard &&
334 rm file &&
335 ln -s file2 file &&
336 git add file &&
337 git stash save "file to symlink (full stage)" &&
338 test -f file &&
339 test bar = "$(cat file)" &&
340 git stash apply &&
341 case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
342'
343
344# This test creates a commit with a symlink used for the following tests
345
346test_expect_success 'stash symlink to file' '
347 git reset --hard &&
348 test_ln_s_add file filelink &&
349 git commit -m "Add symlink" &&
350 rm filelink &&
351 cp file filelink &&
352 git stash save "symlink to file"
353'
354
355test_expect_success SYMLINKS 'this must have re-created the symlink' '
356 test -h filelink &&
357 case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
358'
359
360test_expect_success 'unstash must re-create the file' '
361 git stash apply &&
362 ! test -h filelink &&
363 test bar = "$(cat file)"
364'
365
366test_expect_success 'stash symlink to file (stage rm)' '
367 git reset --hard &&
368 git rm filelink &&
369 cp file filelink &&
370 git stash save "symlink to file (stage rm)"
371'
372
373test_expect_success SYMLINKS 'this must have re-created the symlink' '
374 test -h filelink &&
375 case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
376'
377
378test_expect_success 'unstash must re-create the file' '
379 git stash apply &&
380 ! test -h filelink &&
381 test bar = "$(cat file)"
382'
383
384test_expect_success 'stash symlink to file (full stage)' '
385 git reset --hard &&
386 rm filelink &&
387 cp file filelink &&
388 git add filelink &&
389 git stash save "symlink to file (full stage)"
390'
391
392test_expect_success SYMLINKS 'this must have re-created the symlink' '
393 test -h filelink &&
394 case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac
395'
396
397test_expect_success 'unstash must re-create the file' '
398 git stash apply &&
399 ! test -h filelink &&
400 test bar = "$(cat file)"
401'
402
403test_expect_failure 'stash directory to file' '
404 git reset --hard &&
405 mkdir dir &&
406 echo foo >dir/file &&
407 git add dir/file &&
408 git commit -m "Add file in dir" &&
409 rm -fr dir &&
410 echo bar >dir &&
411 git stash save "directory to file" &&
412 test -d dir &&
413 test foo = "$(cat dir/file)" &&
414 test_must_fail git stash apply &&
415 test bar = "$(cat dir)" &&
416 git reset --soft HEAD^
417'
418
419test_expect_failure 'stash file to directory' '
420 git reset --hard &&
421 rm file &&
422 mkdir file &&
423 echo foo >file/file &&
424 git stash save "file to directory" &&
425 test -f file &&
426 test bar = "$(cat file)" &&
427 git stash apply &&
428 test -f file/file &&
429 test foo = "$(cat file/file)"
430'
431
432test_expect_success 'stash branch - no stashes on stack, stash-like argument' '
433 git stash clear &&
434 test_when_finished "git reset --hard HEAD" &&
435 git reset --hard &&
436 echo foo >> file &&
437 STASH_ID=$(git stash create) &&
438 git reset --hard &&
439 git stash branch stash-branch ${STASH_ID} &&
440 test_when_finished "git reset --hard HEAD && git checkout master && git branch -D stash-branch" &&
441 test $(git ls-files --modified | wc -l) -eq 1
442'
443
444test_expect_success 'stash branch - stashes on stack, stash-like argument' '
445 git stash clear &&
446 test_when_finished "git reset --hard HEAD" &&
447 git reset --hard &&
448 echo foo >> file &&
449 git stash &&
450 test_when_finished "git stash drop" &&
451 echo bar >> file &&
452 STASH_ID=$(git stash create) &&
453 git reset --hard &&
454 git stash branch stash-branch ${STASH_ID} &&
455 test_when_finished "git reset --hard HEAD && git checkout master && git branch -D stash-branch" &&
456 test $(git ls-files --modified | wc -l) -eq 1
457'
458
459test_expect_success 'stash show format defaults to --stat' '
460 git stash clear &&
461 test_when_finished "git reset --hard HEAD" &&
462 git reset --hard &&
463 echo foo >> file &&
464 git stash &&
465 test_when_finished "git stash drop" &&
466 echo bar >> file &&
467 STASH_ID=$(git stash create) &&
468 git reset --hard &&
469 cat >expected <<-EOF &&
470 file | 1 +
471 1 file changed, 1 insertion(+)
472 EOF
473 git stash show ${STASH_ID} >actual &&
474 test_i18ncmp expected actual
475'
476
477test_expect_success 'stash show - stashes on stack, stash-like argument' '
478 git stash clear &&
479 test_when_finished "git reset --hard HEAD" &&
480 git reset --hard &&
481 echo foo >> file &&
482 git stash &&
483 test_when_finished "git stash drop" &&
484 echo bar >> file &&
485 STASH_ID=$(git stash create) &&
486 git reset --hard &&
487 echo "1 0 file" >expected &&
488 git stash show --numstat ${STASH_ID} >actual &&
489 test_cmp expected actual
490'
491
492test_expect_success 'stash show -p - stashes on stack, stash-like argument' '
493 git stash clear &&
494 test_when_finished "git reset --hard HEAD" &&
495 git reset --hard &&
496 echo foo >> file &&
497 git stash &&
498 test_when_finished "git stash drop" &&
499 echo bar >> file &&
500 STASH_ID=$(git stash create) &&
501 git reset --hard &&
502 cat >expected <<-EOF &&
503 diff --git a/file b/file
504 index 7601807..935fbd3 100644
505 --- a/file
506 +++ b/file
507 @@ -1 +1,2 @@
508 baz
509 +bar
510 EOF
511 git stash show -p ${STASH_ID} >actual &&
512 test_cmp expected actual
513'
514
515test_expect_success 'stash show - no stashes on stack, stash-like argument' '
516 git stash clear &&
517 test_when_finished "git reset --hard HEAD" &&
518 git reset --hard &&
519 echo foo >> file &&
520 STASH_ID=$(git stash create) &&
521 git reset --hard &&
522 echo "1 0 file" >expected &&
523 git stash show --numstat ${STASH_ID} >actual &&
524 test_cmp expected actual
525'
526
527test_expect_success 'stash show -p - no stashes on stack, stash-like argument' '
528 git stash clear &&
529 test_when_finished "git reset --hard HEAD" &&
530 git reset --hard &&
531 echo foo >> file &&
532 STASH_ID=$(git stash create) &&
533 git reset --hard &&
534 cat >expected <<-EOF &&
535 diff --git a/file b/file
536 index 7601807..71b52c4 100644
537 --- a/file
538 +++ b/file
539 @@ -1 +1,2 @@
540 baz
541 +foo
542 EOF
543 git stash show -p ${STASH_ID} >actual &&
544 test_cmp expected actual
545'
546
547test_expect_success 'stash drop - fail early if specified stash is not a stash reference' '
548 git stash clear &&
549 test_when_finished "git reset --hard HEAD && git stash clear" &&
550 git reset --hard &&
551 echo foo > file &&
552 git stash &&
553 echo bar > file &&
554 git stash &&
555 test_must_fail git stash drop $(git rev-parse stash@{0}) &&
556 git stash pop &&
557 test bar = "$(cat file)" &&
558 git reset --hard HEAD
559'
560
561test_expect_success 'stash pop - fail early if specified stash is not a stash reference' '
562 git stash clear &&
563 test_when_finished "git reset --hard HEAD && git stash clear" &&
564 git reset --hard &&
565 echo foo > file &&
566 git stash &&
567 echo bar > file &&
568 git stash &&
569 test_must_fail git stash pop $(git rev-parse stash@{0}) &&
570 git stash pop &&
571 test bar = "$(cat file)" &&
572 git reset --hard HEAD
573'
574
575test_expect_success 'ref with non-existent reflog' '
576 git stash clear &&
577 echo bar5 > file &&
578 echo bar6 > file2 &&
579 git add file2 &&
580 git stash &&
581 test_must_fail git rev-parse --quiet --verify does-not-exist &&
582 test_must_fail git stash drop does-not-exist &&
583 test_must_fail git stash drop does-not-exist@{0} &&
584 test_must_fail git stash pop does-not-exist &&
585 test_must_fail git stash pop does-not-exist@{0} &&
586 test_must_fail git stash apply does-not-exist &&
587 test_must_fail git stash apply does-not-exist@{0} &&
588 test_must_fail git stash show does-not-exist &&
589 test_must_fail git stash show does-not-exist@{0} &&
590 test_must_fail git stash branch tmp does-not-exist &&
591 test_must_fail git stash branch tmp does-not-exist@{0} &&
592 git stash drop
593'
594
595test_expect_success 'invalid ref of the form stash@{n}, n >= N' '
596 git stash clear &&
597 test_must_fail git stash drop stash@{0} &&
598 echo bar5 > file &&
599 echo bar6 > file2 &&
600 git add file2 &&
601 git stash &&
602 test_must_fail git stash drop stash@{1} &&
603 test_must_fail git stash pop stash@{1} &&
604 test_must_fail git stash apply stash@{1} &&
605 test_must_fail git stash show stash@{1} &&
606 test_must_fail git stash branch tmp stash@{1} &&
607 git stash drop
608'
609
610test_expect_success 'stash branch should not drop the stash if the branch exists' '
611 git stash clear &&
612 echo foo >file &&
613 git add file &&
614 git commit -m initial &&
615 echo bar >file &&
616 git stash &&
617 test_must_fail git stash branch master stash@{0} &&
618 git rev-parse stash@{0} --
619'
620
621test_expect_success 'stash apply shows status same as git status (relative to current directory)' '
622 git stash clear &&
623 echo 1 >subdir/subfile1 &&
624 echo 2 >subdir/subfile2 &&
625 git add subdir/subfile1 &&
626 git commit -m subdir &&
627 (
628 cd subdir &&
629 echo x >subfile1 &&
630 echo x >../file &&
631 git status >../expect &&
632 git stash &&
633 sane_unset GIT_MERGE_VERBOSITY &&
634 git stash apply
635 ) |
636 sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
637 test_i18ncmp expect actual
638'
639
640cat > expect << EOF
641diff --git a/HEAD b/HEAD
642new file mode 100644
643index 0000000..fe0cbee
644--- /dev/null
645+++ b/HEAD
646@@ -0,0 +1 @@
647+file-not-a-ref
648EOF
649
650test_expect_success 'stash where working directory contains "HEAD" file' '
651 git stash clear &&
652 git reset --hard &&
653 echo file-not-a-ref > HEAD &&
654 git add HEAD &&
655 test_tick &&
656 git stash &&
657 git diff-files --quiet &&
658 git diff-index --cached --quiet HEAD &&
659 test "$(git rev-parse stash^)" = "$(git rev-parse HEAD)" &&
660 git diff stash^..stash > output &&
661 test_cmp output expect
662'
663
664test_expect_success 'store called with invalid commit' '
665 test_must_fail git stash store foo
666'
667
668test_expect_success 'store updates stash ref and reflog' '
669 git stash clear &&
670 git reset --hard &&
671 echo quux >bazzy &&
672 git add bazzy &&
673 STASH_ID=$(git stash create) &&
674 git reset --hard &&
675 ! grep quux bazzy &&
676 git stash store -m quuxery $STASH_ID &&
677 test $(cat .git/refs/stash) = $STASH_ID &&
678 grep $STASH_ID .git/logs/refs/stash &&
679 git stash pop &&
680 grep quux bazzy
681'
682
683test_expect_success 'handle stash specification with spaces' '
684 git stash clear &&
685 echo pig >file &&
686 git stash &&
687 stamp=$(git log -g --format="%cd" -1 refs/stash) &&
688 test_tick &&
689 echo cow >file &&
690 git stash &&
691 git stash apply "stash@{$stamp}" &&
692 grep pig file
693'
694
695test_expect_success 'setup stash with index and worktree changes' '
696 git stash clear &&
697 git reset --hard &&
698 echo index >file &&
699 git add file &&
700 echo working >file &&
701 git stash
702'
703
704test_expect_success 'stash list implies --first-parent -m' '
705 cat >expect <<-EOF &&
706 stash@{0}
707
708 diff --git a/file b/file
709 index 257cc56..d26b33d 100644
710 --- a/file
711 +++ b/file
712 @@ -1 +1 @@
713 -foo
714 +working
715 EOF
716 git stash list --format=%gd -p >actual &&
717 test_cmp expect actual
718'
719
720test_expect_success 'stash list --cc shows combined diff' '
721 cat >expect <<-\EOF &&
722 stash@{0}
723
724 diff --cc file
725 index 257cc56,9015a7a..d26b33d
726 --- a/file
727 +++ b/file
728 @@@ -1,1 -1,1 +1,1 @@@
729 - foo
730 -index
731 ++working
732 EOF
733 git stash list --format=%gd -p --cc >actual &&
734 test_cmp expect actual
735'
736
737test_done