Merge branch 'es/worktree-repair-copied' into cw/worktrees-relative
[git/gitster.git] / t / t7102-reset.sh
blob2add26d76844deb04aee4568bc467f66df965d57
1 #!/bin/sh
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
14 . ./test-lib.sh
16 commit_msg () {
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"
21 if test -n "$1"
22 then
23 printf "$msg" | iconv -f utf-8 -t "$1"
24 else
25 printf "$msg"
29 # Tested non-UTF-8 encoding
30 test_encoding="ISO8859-1"
32 test_expect_success 'creating initial files and commits' '
33 test_tick &&
34 echo "1st file" >first &&
35 git add first &&
36 git commit -m "create 1st file" &&
38 echo "2nd file" >second &&
39 git add 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) &&
47 git rm 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
64 check_changes () {
65 test "$(git rev-parse HEAD)" = "$1" &&
66 git diff | test_cmp .diff_expect - &&
67 git diff --cached | test_cmp .cached_expect - &&
68 for FILE in *
70 echo $FILE':'
71 cat $FILE || return
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
83 done
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' '
100 >.diff_expect &&
101 >.cached_expect &&
102 cat >.cat_expect <<-\EOF &&
103 secondfile:
104 1st line 2nd file
105 2nd line 2nd file
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 &&
112 check_changes $head5
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 &&
129 check_changes $head5
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 &&
141 check_changes $head5
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" &&
162 git checkout main &&
163 git branch -D branch1 branch2 &&
164 check_changes $head5
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" &&
184 git checkout main &&
185 git branch -D branch3 branch4 &&
186 check_changes $head5
189 test_expect_success 'resetting to HEAD with no changes should succeed and do nothing' '
190 git reset --hard &&
191 check_changes $head5 &&
192 git reset --hard HEAD &&
193 check_changes $head5 &&
194 git reset --soft &&
195 check_changes $head5 &&
196 git reset --soft HEAD &&
197 check_changes $head5 &&
198 git reset --mixed &&
199 check_changes $head5 &&
200 git reset --mixed HEAD &&
201 check_changes $head5 &&
202 git reset &&
203 check_changes $head5 &&
204 git reset HEAD &&
205 check_changes $head5
208 test_expect_success '--soft reset only should show changes in diff --cached' '
209 >.diff_expect &&
210 cat >.cached_expect <<-EOF &&
211 diff --git a/secondfile b/secondfile
212 index $head5p1s..$head5s 100644
213 --- a/secondfile
214 +++ b/secondfile
215 @@ -1 +1,2 @@
216 -2nd file
217 +1st line 2nd file
218 +2nd line 2nd file
220 cat >.cat_expect <<-\EOF &&
221 secondfile:
222 1st line 2nd file
223 2nd line 2nd file
225 git reset --soft HEAD^ &&
226 check_changes $head5p1 &&
227 test "$(git rev-parse ORIG_HEAD)" = \
228 $head5
231 test_expect_success 'changing files and redo the last commit should succeed' '
232 >.diff_expect &&
233 >.cached_expect &&
234 cat >.cat_expect <<-\EOF &&
235 secondfile:
236 1st line 2nd file
237 2nd line 2nd file
238 3rd line 2nd file
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)" = \
245 $head5
248 test_expect_success '--hard reset should change the files and undo commits permanently' '
249 >.diff_expect &&
250 >.cached_expect &&
251 cat >.cat_expect <<-\EOF &&
252 first:
253 1st file
254 2nd line 1st file
255 second:
256 2nd file
258 git reset --hard HEAD~2 &&
259 check_changes $head5p2 &&
260 test "$(git rev-parse ORIG_HEAD)" = \
261 $head4
264 test_expect_success 'redoing changes adding them without commit them should succeed' '
265 >.diff_expect &&
266 cat >.cached_expect <<-EOF &&
267 diff --git a/first b/first
268 deleted file mode 100644
269 index $head5p2f..0000000
270 --- a/first
271 +++ /dev/null
272 @@ -1,2 +0,0 @@
273 -1st file
274 -2nd line 1st file
275 diff --git a/second b/second
276 deleted file mode 100644
277 index $head5p1s..0000000
278 --- a/second
279 +++ /dev/null
280 @@ -1 +0,0 @@
281 -2nd file
282 diff --git a/secondfile b/secondfile
283 new file mode 100644
284 index 0000000..$head5s
285 --- /dev/null
286 +++ b/secondfile
287 @@ -0,0 +1,2 @@
288 +1st line 2nd file
289 +2nd line 2nd file
291 cat >.cat_expect <<-\EOF &&
292 secondfile:
293 1st line 2nd file
294 2nd line 2nd file
296 git rm first &&
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
310 --- a/first
311 +++ /dev/null
312 @@ -1,2 +0,0 @@
313 -1st file
314 -2nd line 1st file
315 diff --git a/second b/second
316 deleted file mode 100644
317 index $head5p1s..0000000
318 --- a/second
319 +++ /dev/null
320 @@ -1 +0,0 @@
321 -2nd file
323 >.cached_expect &&
324 cat >.cat_expect <<-\EOF &&
325 secondfile:
326 1st line 2nd file
327 2nd line 2nd file
329 git reset &&
330 check_changes $head5p2 &&
331 test "$(git rev-parse ORIG_HEAD)" = $head5p2
334 test_expect_success 'redoing the last two commits should succeed' '
335 >.diff_expect &&
336 >.cached_expect &&
337 cat >.cat_expect <<-\EOF &&
338 secondfile:
339 1st line 2nd file
340 2nd line 2nd file
342 git add secondfile &&
343 git reset --hard $head5p2 &&
344 git rm first &&
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 - &&
353 check_changes $head5
356 test_expect_success '--hard reset to HEAD should clear a failed merge' '
357 >.diff_expect &&
358 >.cached_expect &&
359 cat >.cat_expect <<-\EOF &&
360 secondfile:
361 1st line 2nd file
362 2nd line 2nd file
363 3rd line in branch2
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 &&
378 git reset --hard &&
379 check_changes $head3
382 test_expect_success '--hard reset to ORIG_HEAD should clear a fast-forward merge' '
383 >.diff_expect &&
384 >.cached_expect &&
385 cat >.cat_expect <<-\EOF &&
386 secondfile:
387 1st line 2nd file
388 2nd line 2nd file
390 git reset --hard HEAD^ &&
391 check_changes $head5 &&
393 git pull . branch1 &&
394 git reset --hard ORIG_HEAD &&
395 check_changes $head5 &&
397 git checkout main &&
398 git branch -D branch1 branch2 &&
399 check_changes $head5
402 test_expect_success 'test --mixed <paths>' '
403 echo 1 >file1 &&
404 echo 2 >file2 &&
405 git add file1 file2 &&
406 test_tick &&
407 git commit -m files &&
408 before1=$(git rev-parse --short HEAD:file1) &&
409 before2=$(git rev-parse --short HEAD:file2) &&
410 git rm file2 &&
411 echo 3 >file3 &&
412 echo 4 >file4 &&
413 echo 5 >file1 &&
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 &&
419 git diff >output &&
421 cat >expect <<-EOF &&
422 diff --git a/file1 b/file1
423 index $before1..$after1 100644
424 --- a/file1
425 +++ b/file1
426 @@ -1 +1 @@
429 diff --git a/file2 b/file2
430 deleted file mode 100644
431 index $before2..0000000
432 --- a/file2
433 +++ /dev/null
434 @@ -1 +0,0 @@
438 test_cmp expect output &&
439 git diff --cached >output &&
441 cat >cached_expect <<-EOF &&
442 diff --git a/file4 b/file4
443 new file mode 100644
444 index 0000000..$after4
445 --- /dev/null
446 +++ b/file4
447 @@ -0,0 +1 @@
451 test_cmp cached_expect output
454 test_expect_success 'test resetting the index at give paths' '
455 mkdir sub &&
456 >sub/file1 &&
457 >sub/file2 &&
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) &&
463 echo "$T" &&
464 echo "$U" &&
465 test_must_fail git diff-index --cached --exit-code "$T" &&
466 test "$T" != "$U"
469 test_expect_success 'resetting an unmodified path is a no-op' '
470 git reset --hard &&
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 &&
502 # With --quiet
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' '
513 echo 123 >>file2 &&
514 git add file2 &&
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:
521 M file2
523 git update-index --no-skip-worktree file2 &&
524 git add 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 &&
539 git ls-files -u &&
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)' '
546 git reset --hard &&
547 >secondfile &&
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)' '
557 git reset --hard &&
558 >secondfile &&
559 git add secondfile &&
560 rm -f secondfile &&
561 test_must_fail git reset secondfile &&
562 test -n "$(git diff --cached --name-only -- secondfile)" &&
563 test ! -f secondfile
566 test_expect_success 'disambiguation (3)' '
567 git reset --hard &&
568 >secondfile &&
569 git add secondfile &&
570 rm -f secondfile &&
571 git reset HEAD secondfile &&
572 test_must_fail git diff --quiet &&
573 test -z "$(git diff --cached --name-only)" &&
574 test ! -f secondfile
577 test_expect_success 'disambiguation (4)' '
578 git reset --hard &&
579 >secondfile &&
580 git add secondfile &&
581 rm -f secondfile &&
582 git reset -- secondfile &&
583 test_must_fail git diff --quiet &&
584 test -z "$(git diff --cached --name-only)" &&
585 test ! -f secondfile
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 &&
598 git add new-file &&
599 git reset -N HEAD &&
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 &&
613 cd mixed_worktree &&
614 test_commit dummy
615 ) &&
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
628 test_done