3 # Copyright (c) 2007 Carlos Rica
6 test_description
='git reset
8 Documented tests for git reset'
10 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=main
11 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
13 TEST_PASSES_SANITIZE_LEAK
=true
17 # String "modify 2nd file (changed)" partly in German
18 # (translated with Google Translate),
19 # encoded in UTF-8, used as a commit log message below.
20 msg
="modify 2nd file (ge\303\244ndert)\n"
23 printf "$msg" |
iconv -f utf-8
-t "$1"
29 # Tested non-UTF-8 encoding
30 test_encoding
="ISO8859-1"
32 test_expect_success
'creating initial files and commits' '
34 echo "1st file" >first &&
36 git commit -m "create 1st file" &&
38 echo "2nd file" >second &&
40 git commit -m "create 2nd file" &&
42 echo "2nd line 1st file" >>first &&
43 git commit -a -m "modify 1st file" &&
44 head5p2=$(git rev-parse --verify HEAD) &&
45 head5p2f=$(git rev-parse --short HEAD:first) &&
48 git mv second secondfile &&
49 git commit -a -m "remove 1st and rename 2nd" &&
50 head5p1=$(git rev-parse --verify HEAD) &&
51 head5p1s=$(git rev-parse --short HEAD:secondfile) &&
53 echo "1st line 2nd file" >secondfile &&
54 echo "2nd line 2nd file" >>secondfile &&
55 # "git commit -m" would break MinGW, as Windows refuse to pass
56 # $test_encoding encoded parameter to git.
57 commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
58 head5=$(git rev-parse --verify HEAD) &&
59 head5s=$(git rev-parse --short HEAD:secondfile) &&
60 head5sl=$(git rev-parse HEAD:secondfile)
62 # git log --pretty=oneline # to see those SHA1 involved
65 test "$(git rev-parse HEAD)" = "$1" &&
66 git
diff | test_cmp .diff_expect
- &&
67 git
diff --cached | test_cmp .cached_expect
- &&
72 done | test_cmp .cat_expect
-
75 # no negated form for various type of resets
76 for opt
in soft mixed hard merge keep
78 test_expect_success
"no 'git reset --no-$opt'" '
79 test_when_finished "rm -f err" &&
80 test_must_fail git reset --no-$opt 2>err &&
81 grep "error: unknown option .no-$opt." err
85 test_expect_success
'reset --hard message' '
86 hex=$(git log -1 --format="%h") &&
87 git reset --hard >.actual &&
88 echo HEAD is now at $hex $(commit_msg) >.expected &&
89 test_cmp .expected .actual
92 test_expect_success
'reset --hard message (ISO8859-1 logoutputencoding)' '
93 hex=$(git log -1 --format="%h") &&
94 git -c "i18n.logOutputEncoding=$test_encoding" reset --hard >.actual &&
95 echo HEAD is now at $hex $(commit_msg $test_encoding) >.expected &&
96 test_cmp .expected .actual
99 test_expect_success
'giving a non existing revision should fail' '
102 cat >.cat_expect <<-\EOF &&
108 test_must_fail git reset aaaaaa &&
109 test_must_fail git reset --mixed aaaaaa &&
110 test_must_fail git reset --soft aaaaaa &&
111 test_must_fail git reset --hard aaaaaa &&
115 test_expect_success
'reset --soft with unmerged index should fail' '
116 touch .git/MERGE_HEAD &&
117 echo "100644 $head5sl 1 un" |
118 git update-index --index-info &&
119 test_must_fail git reset --soft HEAD &&
120 rm .git/MERGE_HEAD &&
121 git rm --cached -- un
124 test_expect_success
'giving paths with options different than --mixed should fail' '
125 test_must_fail git reset --soft -- first &&
126 test_must_fail git reset --hard -- first &&
127 test_must_fail git reset --soft HEAD^ -- first &&
128 test_must_fail git reset --hard HEAD^ -- first &&
132 test_expect_success
'giving unrecognized options should fail' '
133 test_must_fail git reset --other &&
134 test_must_fail git reset -o &&
135 test_must_fail git reset --mixed --other &&
136 test_must_fail git reset --mixed -o &&
137 test_must_fail git reset --soft --other &&
138 test_must_fail git reset --soft -o &&
139 test_must_fail git reset --hard --other &&
140 test_must_fail git reset --hard -o &&
144 test_expect_success
'trying to do reset --soft with pending merge should fail' '
145 git branch branch1 &&
146 git branch branch2 &&
148 git checkout branch1 &&
149 echo "3rd line in branch1" >>secondfile &&
150 git commit -a -m "change in branch1" &&
152 git checkout branch2 &&
153 echo "3rd line in branch2" >>secondfile &&
154 git commit -a -m "change in branch2" &&
156 test_must_fail git merge branch1 &&
157 test_must_fail git reset --soft &&
159 printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
160 git commit -a -m "the change in branch2" &&
163 git branch -D branch1 branch2 &&
167 test_expect_success
'trying to do reset --soft with pending checkout merge should fail' '
168 git branch branch3 &&
169 git branch branch4 &&
171 git checkout branch3 &&
172 echo "3rd line in branch3" >>secondfile &&
173 git commit -a -m "line in branch3" &&
175 git checkout branch4 &&
176 echo "3rd line in branch4" >>secondfile &&
178 git checkout -m branch3 &&
179 test_must_fail git reset --soft &&
181 printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
182 git commit -a -m "the line in branch3" &&
185 git branch -D branch3 branch4 &&
189 test_expect_success
'resetting to HEAD with no changes should succeed and do nothing' '
191 check_changes $head5 &&
192 git reset --hard HEAD &&
193 check_changes $head5 &&
195 check_changes $head5 &&
196 git reset --soft HEAD &&
197 check_changes $head5 &&
199 check_changes $head5 &&
200 git reset --mixed HEAD &&
201 check_changes $head5 &&
203 check_changes $head5 &&
208 test_expect_success
'--soft reset only should show changes in diff --cached' '
210 cat >.cached_expect <<-EOF &&
211 diff --git a/secondfile b/secondfile
212 index $head5p1s..$head5s 100644
220 cat >.cat_expect <<-\EOF &&
225 git reset --soft HEAD^ &&
226 check_changes $head5p1 &&
227 test "$(git rev-parse ORIG_HEAD)" = \
231 test_expect_success
'changing files and redo the last commit should succeed' '
234 cat >.cat_expect <<-\EOF &&
240 echo "3rd line 2nd file" >>secondfile &&
241 git commit -a -C ORIG_HEAD &&
242 head4=$(git rev-parse --verify HEAD) &&
243 check_changes $head4 &&
244 test "$(git rev-parse ORIG_HEAD)" = \
248 test_expect_success
'--hard reset should change the files and undo commits permanently' '
251 cat >.cat_expect <<-\EOF &&
258 git reset --hard HEAD~2 &&
259 check_changes $head5p2 &&
260 test "$(git rev-parse ORIG_HEAD)" = \
264 test_expect_success
'redoing changes adding them without commit them should succeed' '
266 cat >.cached_expect <<-EOF &&
267 diff --git a/first b/first
268 deleted file mode 100644
269 index $head5p2f..0000000
275 diff --git a/second b/second
276 deleted file mode 100644
277 index $head5p1s..0000000
282 diff --git a/secondfile b/secondfile
284 index 0000000..$head5s
291 cat >.cat_expect <<-\EOF &&
297 git mv second secondfile &&
299 echo "1st line 2nd file" >secondfile &&
300 echo "2nd line 2nd file" >>secondfile &&
301 git add secondfile &&
302 check_changes $head5p2
305 test_expect_success
'--mixed reset to HEAD should unadd the files' '
306 cat >.diff_expect <<-EOF &&
307 diff --git a/first b/first
308 deleted file mode 100644
309 index $head5p2f..0000000
315 diff --git a/second b/second
316 deleted file mode 100644
317 index $head5p1s..0000000
324 cat >.cat_expect <<-\EOF &&
330 check_changes $head5p2 &&
331 test "$(git rev-parse ORIG_HEAD)" = $head5p2
334 test_expect_success
'redoing the last two commits should succeed' '
337 cat >.cat_expect <<-\EOF &&
342 git add secondfile &&
343 git reset --hard $head5p2 &&
345 git mv second secondfile &&
346 git commit -a -m "remove 1st and rename 2nd" &&
348 echo "1st line 2nd file" >secondfile &&
349 echo "2nd line 2nd file" >>secondfile &&
350 # "git commit -m" would break MinGW, as Windows refuse to pass
351 # $test_encoding encoded parameter to git.
352 commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
356 test_expect_success
'--hard reset to HEAD should clear a failed merge' '
359 cat >.cat_expect <<-\EOF &&
365 git branch branch1 &&
366 git branch branch2 &&
368 git checkout branch1 &&
369 echo "3rd line in branch1" >>secondfile &&
370 git commit -a -m "change in branch1" &&
372 git checkout branch2 &&
373 echo "3rd line in branch2" >>secondfile &&
374 git commit -a -m "change in branch2" &&
375 head3=$(git rev-parse --verify HEAD) &&
377 test_must_fail git pull . branch1 &&
382 test_expect_success
'--hard reset to ORIG_HEAD should clear a fast-forward merge' '
385 cat >.cat_expect <<-\EOF &&
390 git reset --hard HEAD^ &&
391 check_changes $head5 &&
393 git pull . branch1 &&
394 git reset --hard ORIG_HEAD &&
395 check_changes $head5 &&
398 git branch -D branch1 branch2 &&
402 test_expect_success
'test --mixed <paths>' '
405 git add file1 file2 &&
407 git commit -m files &&
408 before1=$(git rev-parse --short HEAD:file1) &&
409 before2=$(git rev-parse --short HEAD:file2) &&
414 after1=$(git rev-parse --short $(git hash-object file1)) &&
415 after4=$(git rev-parse --short $(git hash-object file4)) &&
416 git add file1 file3 file4 &&
417 git reset HEAD -- file1 file2 file3 &&
418 test_must_fail git diff --quiet &&
421 cat >expect <<-EOF &&
422 diff --git a/file1 b/file1
423 index $before1..$after1 100644
429 diff --git a/file2 b/file2
430 deleted file mode 100644
431 index $before2..0000000
438 test_cmp expect output &&
439 git diff --cached >output &&
441 cat >cached_expect <<-EOF &&
442 diff --git a/file4 b/file4
444 index 0000000..$after4
451 test_cmp cached_expect output
454 test_expect_success
'test resetting the index at give paths' '
458 git update-index --add sub/file1 sub/file2 &&
459 T=$(git write-tree) &&
460 git reset HEAD sub/file2 &&
461 test_must_fail git diff --quiet &&
462 U=$(git write-tree) &&
465 test_must_fail git diff-index --cached --exit-code "$T" &&
469 test_expect_success
'resetting an unmodified path is a no-op' '
471 git reset -- file1 &&
472 git diff-files --exit-code &&
473 git diff-index --cached --exit-code HEAD
476 test_reset_refreshes_index
() {
478 # To test whether the index is refreshed in `git reset --mixed` with
479 # the given options, create a scenario where we clearly see different
480 # results depending on whether the refresh occurred or not.
482 # Step 0: start with a clean index
483 git
reset --hard HEAD
&&
485 # Step 1: remove file2, but only in the index (no change to worktree)
486 git
rm --cached file2
&&
488 # Step 2: reset index & leave worktree unchanged from HEAD
489 git
$1 reset $2 --mixed HEAD
&&
491 # Step 3: verify whether the index is refreshed by checking whether
492 # file2 still has staged changes in the index differing from HEAD (if
493 # the refresh occurred, there should be no such changes)
494 git diff-files
>output.log
&&
495 test_must_be_empty output.log
498 test_expect_success
'--mixed refreshes the index' '
499 # Verify default behavior (without --[no-]refresh or reset.refresh)
500 test_reset_refreshes_index &&
503 test_reset_refreshes_index "" --quiet
506 test_expect_success
'--mixed --[no-]refresh sets refresh behavior' '
507 # Verify that --[no-]refresh controls index refresh
508 test_reset_refreshes_index "" --refresh &&
509 ! test_reset_refreshes_index "" --no-refresh
512 test_expect_success
'--mixed preserves skip-worktree' '
515 git update-index --skip-worktree file2 &&
516 git reset --mixed HEAD >output &&
517 test_must_be_empty output &&
519 cat >expect <<-\EOF &&
520 Unstaged changes after reset:
523 git update-index --no-skip-worktree file2 &&
525 git reset --mixed HEAD >output &&
526 test_cmp expect output
529 test_expect_success
'resetting specific path that is unmerged' '
530 git rm --cached file2 &&
531 F1=$(git rev-parse HEAD:file1) &&
532 F2=$(git rev-parse HEAD:file2) &&
533 F3=$(git rev-parse HEAD:secondfile) &&
535 echo "100644 $F1 1 file2" &&
536 echo "100644 $F2 2 file2" &&
537 echo "100644 $F3 3 file2"
538 } | git update-index --index-info &&
540 git reset HEAD file2 &&
541 test_must_fail git diff --quiet &&
542 git diff-index --exit-code --cached HEAD
545 test_expect_success
'disambiguation (1)' '
548 git add secondfile &&
549 git reset secondfile &&
550 test_must_fail git diff --quiet -- secondfile &&
551 test -z "$(git diff --cached --name-only)" &&
552 test -f secondfile &&
553 test_must_be_empty secondfile
556 test_expect_success
'disambiguation (2)' '
559 git add secondfile &&
561 test_must_fail git reset secondfile &&
562 test -n "$(git diff --cached --name-only -- secondfile)" &&
566 test_expect_success
'disambiguation (3)' '
569 git add secondfile &&
571 git reset HEAD secondfile &&
572 test_must_fail git diff --quiet &&
573 test -z "$(git diff --cached --name-only)" &&
577 test_expect_success
'disambiguation (4)' '
580 git add secondfile &&
582 git reset -- secondfile &&
583 test_must_fail git diff --quiet &&
584 test -z "$(git diff --cached --name-only)" &&
588 test_expect_success
'reset with paths accepts tree' '
589 # for simpler tests, drop last commit containing added files
590 git reset --hard HEAD^ &&
591 git reset HEAD^^{tree} -- . &&
592 git diff --cached HEAD^ --exit-code &&
593 git diff HEAD --exit-code
596 test_expect_success
'reset -N keeps removed files as intent-to-add' '
597 echo new-file >new-file &&
601 tree=$(git write-tree) &&
602 git ls-tree $tree new-file >actual &&
603 test_must_be_empty actual &&
605 git diff --name-only >actual &&
606 echo new-file >expect &&
607 test_cmp expect actual
610 test_expect_success
'reset --mixed sets up work tree' '
611 git init mixed_worktree &&
616 git --git-dir=mixed_worktree/.git --work-tree=mixed_worktree reset >actual &&
617 test_must_be_empty actual
620 test_expect_success
'reset handles --end-of-options' '
621 git update-ref refs/heads/--foo HEAD^ &&
622 git log -1 --format=%s refs/heads/--foo >expect &&
623 git reset --hard --end-of-options --foo &&
624 git log -1 --format=%s HEAD >actual &&
625 test_cmp expect actual