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