Merge branch 'dl/complete-stash-updates'
[git] / t / t7102-reset.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Carlos Rica
4 #
5
6 test_description='git reset
7
8 Documented tests for git reset'
9
10 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
11 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
12
13 . ./test-lib.sh
14
15 commit_msg () {
16         # String "modify 2nd file (changed)" partly in German
17         # (translated with Google Translate),
18         # encoded in UTF-8, used as a commit log message below.
19         msg="modify 2nd file (ge\303\244ndert)\n"
20         if test -n "$1"
21         then
22                 printf "$msg" | iconv -f utf-8 -t "$1"
23         else
24                 printf "$msg"
25         fi
26 }
27
28 # Tested non-UTF-8 encoding
29 test_encoding="ISO8859-1"
30
31 test_expect_success 'creating initial files and commits' '
32         test_tick &&
33         echo "1st file" >first &&
34         git add first &&
35         git commit -m "create 1st file" &&
36
37         echo "2nd file" >second &&
38         git add second &&
39         git commit -m "create 2nd file" &&
40
41         echo "2nd line 1st file" >>first &&
42         git commit -a -m "modify 1st file" &&
43         head5p2=$(git rev-parse --verify HEAD) &&
44         head5p2f=$(git rev-parse --short HEAD:first) &&
45
46         git rm first &&
47         git mv second secondfile &&
48         git commit -a -m "remove 1st and rename 2nd" &&
49         head5p1=$(git rev-parse --verify HEAD) &&
50         head5p1s=$(git rev-parse --short HEAD:secondfile) &&
51
52         echo "1st line 2nd file" >secondfile &&
53         echo "2nd line 2nd file" >>secondfile &&
54         # "git commit -m" would break MinGW, as Windows refuse to pass
55         # $test_encoding encoded parameter to git.
56         commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
57         head5=$(git rev-parse --verify HEAD) &&
58         head5s=$(git rev-parse --short HEAD:secondfile) &&
59         head5sl=$(git rev-parse HEAD:secondfile)
60 '
61 # git log --pretty=oneline # to see those SHA1 involved
62
63 check_changes () {
64         test "$(git rev-parse HEAD)" = "$1" &&
65         git diff | test_cmp .diff_expect - &&
66         git diff --cached | test_cmp .cached_expect - &&
67         for FILE in *
68         do
69                 echo $FILE':'
70                 cat $FILE || return
71         done | test_cmp .cat_expect -
72 }
73
74 test_expect_success 'reset --hard message' '
75         hex=$(git log -1 --format="%h") &&
76         git reset --hard >.actual &&
77         echo HEAD is now at $hex $(commit_msg) >.expected &&
78         test_cmp .expected .actual
79 '
80
81 test_expect_success 'reset --hard message (ISO8859-1 logoutputencoding)' '
82         hex=$(git log -1 --format="%h") &&
83         git -c "i18n.logOutputEncoding=$test_encoding" reset --hard >.actual &&
84         echo HEAD is now at $hex $(commit_msg $test_encoding) >.expected &&
85         test_cmp .expected .actual
86 '
87
88 test_expect_success 'giving a non existing revision should fail' '
89         >.diff_expect &&
90         >.cached_expect &&
91         cat >.cat_expect <<-\EOF &&
92         secondfile:
93         1st line 2nd file
94         2nd line 2nd file
95         EOF
96
97         test_must_fail git reset aaaaaa &&
98         test_must_fail git reset --mixed aaaaaa &&
99         test_must_fail git reset --soft aaaaaa &&
100         test_must_fail git reset --hard aaaaaa &&
101         check_changes $head5
102 '
103
104 test_expect_success 'reset --soft with unmerged index should fail' '
105         touch .git/MERGE_HEAD &&
106         echo "100644 $head5sl 1 un" |
107                 git update-index --index-info &&
108         test_must_fail git reset --soft HEAD &&
109         rm .git/MERGE_HEAD &&
110         git rm --cached -- un
111 '
112
113 test_expect_success 'giving paths with options different than --mixed should fail' '
114         test_must_fail git reset --soft -- first &&
115         test_must_fail git reset --hard -- first &&
116         test_must_fail git reset --soft HEAD^ -- first &&
117         test_must_fail git reset --hard HEAD^ -- first &&
118         check_changes $head5
119 '
120
121 test_expect_success 'giving unrecognized options should fail' '
122         test_must_fail git reset --other &&
123         test_must_fail git reset -o &&
124         test_must_fail git reset --mixed --other &&
125         test_must_fail git reset --mixed -o &&
126         test_must_fail git reset --soft --other &&
127         test_must_fail git reset --soft -o &&
128         test_must_fail git reset --hard --other &&
129         test_must_fail git reset --hard -o &&
130         check_changes $head5
131 '
132
133 test_expect_success 'trying to do reset --soft with pending merge should fail' '
134         git branch branch1 &&
135         git branch branch2 &&
136
137         git checkout branch1 &&
138         echo "3rd line in branch1" >>secondfile &&
139         git commit -a -m "change in branch1" &&
140
141         git checkout branch2 &&
142         echo "3rd line in branch2" >>secondfile &&
143         git commit -a -m "change in branch2" &&
144
145         test_must_fail git merge branch1 &&
146         test_must_fail git reset --soft &&
147
148         printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
149         git commit -a -m "the change in branch2" &&
150
151         git checkout main &&
152         git branch -D branch1 branch2 &&
153         check_changes $head5
154 '
155
156 test_expect_success 'trying to do reset --soft with pending checkout merge should fail' '
157         git branch branch3 &&
158         git branch branch4 &&
159
160         git checkout branch3 &&
161         echo "3rd line in branch3" >>secondfile &&
162         git commit -a -m "line in branch3" &&
163
164         git checkout branch4 &&
165         echo "3rd line in branch4" >>secondfile &&
166
167         git checkout -m branch3 &&
168         test_must_fail git reset --soft &&
169
170         printf "1st line 2nd file\n2nd line 2nd file\n3rd line" >secondfile &&
171         git commit -a -m "the line in branch3" &&
172
173         git checkout main &&
174         git branch -D branch3 branch4 &&
175         check_changes $head5
176 '
177
178 test_expect_success 'resetting to HEAD with no changes should succeed and do nothing' '
179         git reset --hard &&
180                 check_changes $head5 &&
181         git reset --hard HEAD &&
182                 check_changes $head5 &&
183         git reset --soft &&
184                 check_changes $head5 &&
185         git reset --soft HEAD &&
186                 check_changes $head5 &&
187         git reset --mixed &&
188                 check_changes $head5 &&
189         git reset --mixed HEAD &&
190                 check_changes $head5 &&
191         git reset &&
192                 check_changes $head5 &&
193         git reset HEAD &&
194                 check_changes $head5
195 '
196
197 test_expect_success '--soft reset only should show changes in diff --cached' '
198         >.diff_expect &&
199         cat >.cached_expect <<-EOF &&
200         diff --git a/secondfile b/secondfile
201         index $head5p1s..$head5s 100644
202         --- a/secondfile
203         +++ b/secondfile
204         @@ -1 +1,2 @@
205         -2nd file
206         +1st line 2nd file
207         +2nd line 2nd file
208         EOF
209         cat >.cat_expect <<-\EOF &&
210         secondfile:
211         1st line 2nd file
212         2nd line 2nd file
213         EOF
214         git reset --soft HEAD^ &&
215         check_changes $head5p1 &&
216         test "$(git rev-parse ORIG_HEAD)" = \
217                         $head5
218 '
219
220 test_expect_success 'changing files and redo the last commit should succeed' '
221         >.diff_expect &&
222         >.cached_expect &&
223         cat >.cat_expect <<-\EOF &&
224         secondfile:
225         1st line 2nd file
226         2nd line 2nd file
227         3rd line 2nd file
228         EOF
229         echo "3rd line 2nd file" >>secondfile &&
230         git commit -a -C ORIG_HEAD &&
231         head4=$(git rev-parse --verify HEAD) &&
232         check_changes $head4 &&
233         test "$(git rev-parse ORIG_HEAD)" = \
234                         $head5
235 '
236
237 test_expect_success '--hard reset should change the files and undo commits permanently' '
238         >.diff_expect &&
239         >.cached_expect &&
240         cat >.cat_expect <<-\EOF &&
241         first:
242         1st file
243         2nd line 1st file
244         second:
245         2nd file
246         EOF
247         git reset --hard HEAD~2 &&
248         check_changes $head5p2 &&
249         test "$(git rev-parse ORIG_HEAD)" = \
250                         $head4
251 '
252
253 test_expect_success 'redoing changes adding them without commit them should succeed' '
254         >.diff_expect &&
255         cat >.cached_expect <<-EOF &&
256         diff --git a/first b/first
257         deleted file mode 100644
258         index $head5p2f..0000000
259         --- a/first
260         +++ /dev/null
261         @@ -1,2 +0,0 @@
262         -1st file
263         -2nd line 1st file
264         diff --git a/second b/second
265         deleted file mode 100644
266         index $head5p1s..0000000
267         --- a/second
268         +++ /dev/null
269         @@ -1 +0,0 @@
270         -2nd file
271         diff --git a/secondfile b/secondfile
272         new file mode 100644
273         index 0000000..$head5s
274         --- /dev/null
275         +++ b/secondfile
276         @@ -0,0 +1,2 @@
277         +1st line 2nd file
278         +2nd line 2nd file
279         EOF
280         cat >.cat_expect <<-\EOF &&
281         secondfile:
282         1st line 2nd file
283         2nd line 2nd file
284         EOF
285         git rm first &&
286         git mv second secondfile &&
287
288         echo "1st line 2nd file" >secondfile &&
289         echo "2nd line 2nd file" >>secondfile &&
290         git add secondfile &&
291         check_changes $head5p2
292 '
293
294 test_expect_success '--mixed reset to HEAD should unadd the files' '
295         cat >.diff_expect <<-EOF &&
296         diff --git a/first b/first
297         deleted file mode 100644
298         index $head5p2f..0000000
299         --- a/first
300         +++ /dev/null
301         @@ -1,2 +0,0 @@
302         -1st file
303         -2nd line 1st file
304         diff --git a/second b/second
305         deleted file mode 100644
306         index $head5p1s..0000000
307         --- a/second
308         +++ /dev/null
309         @@ -1 +0,0 @@
310         -2nd file
311         EOF
312         >.cached_expect &&
313         cat >.cat_expect <<-\EOF &&
314         secondfile:
315         1st line 2nd file
316         2nd line 2nd file
317         EOF
318         git reset &&
319         check_changes $head5p2 &&
320         test "$(git rev-parse ORIG_HEAD)" = $head5p2
321 '
322
323 test_expect_success 'redoing the last two commits should succeed' '
324         >.diff_expect &&
325         >.cached_expect &&
326         cat >.cat_expect <<-\EOF &&
327         secondfile:
328         1st line 2nd file
329         2nd line 2nd file
330         EOF
331         git add secondfile &&
332         git reset --hard $head5p2 &&
333         git rm first &&
334         git mv second secondfile &&
335         git commit -a -m "remove 1st and rename 2nd" &&
336
337         echo "1st line 2nd file" >secondfile &&
338         echo "2nd line 2nd file" >>secondfile &&
339         # "git commit -m" would break MinGW, as Windows refuse to pass
340         # $test_encoding encoded parameter to git.
341         commit_msg $test_encoding | git -c "i18n.commitEncoding=$test_encoding" commit -a -F - &&
342         check_changes $head5
343 '
344
345 test_expect_success '--hard reset to HEAD should clear a failed merge' '
346         >.diff_expect &&
347         >.cached_expect &&
348         cat >.cat_expect <<-\EOF &&
349         secondfile:
350         1st line 2nd file
351         2nd line 2nd file
352         3rd line in branch2
353         EOF
354         git branch branch1 &&
355         git branch branch2 &&
356
357         git checkout branch1 &&
358         echo "3rd line in branch1" >>secondfile &&
359         git commit -a -m "change in branch1" &&
360
361         git checkout branch2 &&
362         echo "3rd line in branch2" >>secondfile &&
363         git commit -a -m "change in branch2" &&
364         head3=$(git rev-parse --verify HEAD) &&
365
366         test_must_fail git pull . branch1 &&
367         git reset --hard &&
368         check_changes $head3
369 '
370
371 test_expect_success '--hard reset to ORIG_HEAD should clear a fast-forward merge' '
372         >.diff_expect &&
373         >.cached_expect &&
374         cat >.cat_expect <<-\EOF &&
375         secondfile:
376         1st line 2nd file
377         2nd line 2nd file
378         EOF
379         git reset --hard HEAD^ &&
380         check_changes $head5 &&
381
382         git pull . branch1 &&
383         git reset --hard ORIG_HEAD &&
384         check_changes $head5 &&
385
386         git checkout main &&
387         git branch -D branch1 branch2 &&
388         check_changes $head5
389 '
390
391 test_expect_success 'test --mixed <paths>' '
392         echo 1 >file1 &&
393         echo 2 >file2 &&
394         git add file1 file2 &&
395         test_tick &&
396         git commit -m files &&
397         before1=$(git rev-parse --short HEAD:file1) &&
398         before2=$(git rev-parse --short HEAD:file2) &&
399         git rm file2 &&
400         echo 3 >file3 &&
401         echo 4 >file4 &&
402         echo 5 >file1 &&
403         after1=$(git rev-parse --short $(git hash-object file1)) &&
404         after4=$(git rev-parse --short $(git hash-object file4)) &&
405         git add file1 file3 file4 &&
406         git reset HEAD -- file1 file2 file3 &&
407         test_must_fail git diff --quiet &&
408         git diff >output &&
409
410         cat >expect <<-EOF &&
411         diff --git a/file1 b/file1
412         index $before1..$after1 100644
413         --- a/file1
414         +++ b/file1
415         @@ -1 +1 @@
416         -1
417         +5
418         diff --git a/file2 b/file2
419         deleted file mode 100644
420         index $before2..0000000
421         --- a/file2
422         +++ /dev/null
423         @@ -1 +0,0 @@
424         -2
425         EOF
426
427         test_cmp expect output &&
428         git diff --cached >output &&
429
430         cat >cached_expect <<-EOF &&
431         diff --git a/file4 b/file4
432         new file mode 100644
433         index 0000000..$after4
434         --- /dev/null
435         +++ b/file4
436         @@ -0,0 +1 @@
437         +4
438         EOF
439
440         test_cmp cached_expect output
441 '
442
443 test_expect_success 'test resetting the index at give paths' '
444         mkdir sub &&
445         >sub/file1 &&
446         >sub/file2 &&
447         git update-index --add sub/file1 sub/file2 &&
448         T=$(git write-tree) &&
449         git reset HEAD sub/file2 &&
450         test_must_fail git diff --quiet &&
451         U=$(git write-tree) &&
452         echo "$T" &&
453         echo "$U" &&
454         test_must_fail git diff-index --cached --exit-code "$T" &&
455         test "$T" != "$U"
456 '
457
458 test_expect_success 'resetting an unmodified path is a no-op' '
459         git reset --hard &&
460         git reset -- file1 &&
461         git diff-files --exit-code &&
462         git diff-index --cached --exit-code HEAD
463 '
464
465 test_expect_success '--mixed refreshes the index' '
466         cat >expect <<-\EOF &&
467         Unstaged changes after reset:
468         M       file2
469         EOF
470         echo 123 >>file2 &&
471         git reset --mixed HEAD >output &&
472         test_cmp expect output
473 '
474
475 test_expect_success 'resetting specific path that is unmerged' '
476         git rm --cached file2 &&
477         F1=$(git rev-parse HEAD:file1) &&
478         F2=$(git rev-parse HEAD:file2) &&
479         F3=$(git rev-parse HEAD:secondfile) &&
480         {
481                 echo "100644 $F1 1      file2" &&
482                 echo "100644 $F2 2      file2" &&
483                 echo "100644 $F3 3      file2"
484         } | git update-index --index-info &&
485         git ls-files -u &&
486         git reset HEAD file2 &&
487         test_must_fail git diff --quiet &&
488         git diff-index --exit-code --cached HEAD
489 '
490
491 test_expect_success 'disambiguation (1)' '
492         git reset --hard &&
493         >secondfile &&
494         git add secondfile &&
495         git reset secondfile &&
496         test_must_fail git diff --quiet -- secondfile &&
497         test -z "$(git diff --cached --name-only)" &&
498         test -f secondfile &&
499         test_must_be_empty secondfile
500 '
501
502 test_expect_success 'disambiguation (2)' '
503         git reset --hard &&
504         >secondfile &&
505         git add secondfile &&
506         rm -f secondfile &&
507         test_must_fail git reset secondfile &&
508         test -n "$(git diff --cached --name-only -- secondfile)" &&
509         test ! -f secondfile
510 '
511
512 test_expect_success 'disambiguation (3)' '
513         git reset --hard &&
514         >secondfile &&
515         git add secondfile &&
516         rm -f secondfile &&
517         git reset HEAD secondfile &&
518         test_must_fail git diff --quiet &&
519         test -z "$(git diff --cached --name-only)" &&
520         test ! -f secondfile
521 '
522
523 test_expect_success 'disambiguation (4)' '
524         git reset --hard &&
525         >secondfile &&
526         git add secondfile &&
527         rm -f secondfile &&
528         git reset -- secondfile &&
529         test_must_fail git diff --quiet &&
530         test -z "$(git diff --cached --name-only)" &&
531         test ! -f secondfile
532 '
533
534 test_expect_success 'reset with paths accepts tree' '
535         # for simpler tests, drop last commit containing added files
536         git reset --hard HEAD^ &&
537         git reset HEAD^^{tree} -- . &&
538         git diff --cached HEAD^ --exit-code &&
539         git diff HEAD --exit-code
540 '
541
542 test_expect_success 'reset -N keeps removed files as intent-to-add' '
543         echo new-file >new-file &&
544         git add new-file &&
545         git reset -N HEAD &&
546
547         tree=$(git write-tree) &&
548         git ls-tree $tree new-file >actual &&
549         test_must_be_empty actual &&
550
551         git diff --name-only >actual &&
552         echo new-file >expect &&
553         test_cmp expect actual
554 '
555
556 test_expect_success 'reset --mixed sets up work tree' '
557         git init mixed_worktree &&
558         (
559                 cd mixed_worktree &&
560                 test_commit dummy
561         ) &&
562         git --git-dir=mixed_worktree/.git --work-tree=mixed_worktree reset >actual &&
563         test_must_be_empty actual
564 '
565
566 test_done