t3404: set $EDITOR in subshell
[git] / t / t3404-rebase-interactive.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2007 Johannes E. Schindelin
4 #
5
6 test_description='git rebase interactive
7
8 This test runs git rebase "interactively", by faking an edit, and verifies
9 that the result still makes sense.
10
11 Initial setup:
12
13      one - two - three - four (conflict-branch)
14    /
15  A - B - C - D - E            (master)
16  | \
17  |   F - G - H                (branch1)
18  |     \
19  |\      I                    (branch2)
20  | \
21  |   J - K - L - M            (no-conflict-branch)
22   \
23     N - O - P                 (no-ff-branch)
24
25  where A, B, D and G all touch file1, and one, two, three, four all
26  touch file "conflict".
27 '
28 . ./test-lib.sh
29
30 . "$TEST_DIRECTORY"/lib-rebase.sh
31
32 # WARNING: Modifications to the initial repository can change the SHA ID used
33 # in the expect2 file for the 'stop on conflicting pick' test.
34
35 test_expect_success 'setup' '
36         test_commit A file1 &&
37         test_commit B file1 &&
38         test_commit C file2 &&
39         test_commit D file1 &&
40         test_commit E file3 &&
41         git checkout -b branch1 A &&
42         test_commit F file4 &&
43         test_commit G file1 &&
44         test_commit H file5 &&
45         git checkout -b branch2 F &&
46         test_commit I file6 &&
47         git checkout -b conflict-branch A &&
48         test_commit one conflict &&
49         test_commit two conflict &&
50         test_commit three conflict &&
51         test_commit four conflict &&
52         git checkout -b no-conflict-branch A &&
53         test_commit J fileJ &&
54         test_commit K fileK &&
55         test_commit L fileL &&
56         test_commit M fileM &&
57         git checkout -b no-ff-branch A &&
58         test_commit N fileN &&
59         test_commit O fileO &&
60         test_commit P fileP
61 '
62
63 # "exec" commands are run with the user shell by default, but this may
64 # be non-POSIX. For example, if SHELL=zsh then ">file" doesn't work
65 # to create a file. Unsetting SHELL avoids such non-portable behavior
66 # in tests. It must be exported for it to take effect where needed.
67 SHELL=
68 export SHELL
69
70 test_expect_success 'rebase --keep-empty' '
71         git checkout -b emptybranch master &&
72         git commit --allow-empty -m "empty" &&
73         git rebase --keep-empty -i HEAD~2 &&
74         git log --oneline >actual &&
75         test_line_count = 6 actual
76 '
77
78 test_expect_success 'rebase -i with empty HEAD' '
79         cat >expect <<-\EOF &&
80         error: nothing to do
81         EOF
82         (
83                 set_fake_editor &&
84                 test_must_fail env FAKE_LINES="1 exec_true" \
85                         git rebase -i HEAD^ >actual 2>&1
86         ) &&
87         test_i18ncmp expect actual
88 '
89
90 test_expect_success 'rebase -i with the exec command' '
91         git checkout master &&
92         (
93         set_fake_editor &&
94         FAKE_LINES="1 exec_>touch-one
95                 2 exec_>touch-two exec_false exec_>touch-three
96                 3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
97         export FAKE_LINES &&
98         test_must_fail git rebase -i A
99         ) &&
100         test_path_is_file touch-one &&
101         test_path_is_file touch-two &&
102         test_path_is_missing touch-three " (should have stopped before)" &&
103         test_cmp_rev C HEAD &&
104         git rebase --continue &&
105         test_path_is_file touch-three &&
106         test_path_is_file "touch-file  name with spaces" &&
107         test_path_is_file touch-after-semicolon &&
108         test_cmp_rev master HEAD &&
109         rm -f touch-*
110 '
111
112 test_expect_success 'rebase -i with the exec command runs from tree root' '
113         git checkout master &&
114         mkdir subdir && (cd subdir &&
115         set_fake_editor &&
116         FAKE_LINES="1 exec_>touch-subdir" \
117                 git rebase -i HEAD^
118         ) &&
119         test_path_is_file touch-subdir &&
120         rm -fr subdir
121 '
122
123 test_expect_success 'rebase -i with exec allows git commands in subdirs' '
124         test_when_finished "rm -rf subdir" &&
125         test_when_finished "git rebase --abort ||:" &&
126         git checkout master &&
127         mkdir subdir && (cd subdir &&
128         set_fake_editor &&
129         FAKE_LINES="1 x_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \
130                 git rebase -i HEAD^
131         )
132 '
133
134 test_expect_success 'rebase -i sets work tree properly' '
135         test_when_finished "rm -rf subdir" &&
136         test_when_finished "test_might_fail git rebase --abort" &&
137         mkdir subdir &&
138         git rebase -x "(cd subdir && git rev-parse --show-toplevel)" HEAD^ \
139                 >actual &&
140         ! grep "/subdir$" actual
141 '
142
143 test_expect_success 'rebase -i with the exec command checks tree cleanness' '
144         git checkout master &&
145         (
146                 set_fake_editor &&
147                 test_must_fail env FAKE_LINES="exec_echo_foo_>file1 1" \
148                         git rebase -i HEAD^
149         ) &&
150         test_cmp_rev master^ HEAD &&
151         git reset --hard &&
152         git rebase --continue
153 '
154
155 test_expect_success 'rebase -x with empty command fails' '
156         test_when_finished "git rebase --abort ||:" &&
157         test_must_fail env git rebase -x "" @ 2>actual &&
158         test_write_lines "error: empty exec command" >expected &&
159         test_i18ncmp expected actual &&
160         test_must_fail env git rebase -x " " @ 2>actual &&
161         test_i18ncmp expected actual
162 '
163
164 LF='
165 '
166 test_expect_success 'rebase -x with newline in command fails' '
167         test_when_finished "git rebase --abort ||:" &&
168         test_must_fail env git rebase -x "a${LF}b" @ 2>actual &&
169         test_write_lines "error: exec commands cannot contain newlines" \
170                          >expected &&
171         test_i18ncmp expected actual
172 '
173
174 test_expect_success 'rebase -i with exec of inexistent command' '
175         git checkout master &&
176         test_when_finished "git rebase --abort" &&
177         (
178                 set_fake_editor &&
179                 test_must_fail env FAKE_LINES="exec_this-command-does-not-exist 1" \
180                         git rebase -i HEAD^ >actual 2>&1
181         ) &&
182         ! grep "Maybe git-rebase is broken" actual
183 '
184
185 test_expect_success 'implicit interactive rebase does not invoke sequence editor' '
186         test_when_finished "git rebase --abort ||:" &&
187         GIT_SEQUENCE_EDITOR="echo bad >" git rebase -x"echo one" @^
188 '
189
190 test_expect_success 'no changes are a nop' '
191         git checkout branch2 &&
192         set_fake_editor &&
193         git rebase -i F &&
194         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
195         test $(git rev-parse I) = $(git rev-parse HEAD)
196 '
197
198 test_expect_success 'test the [branch] option' '
199         git checkout -b dead-end &&
200         git rm file6 &&
201         git commit -m "stop here" &&
202         set_fake_editor &&
203         git rebase -i F branch2 &&
204         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
205         test $(git rev-parse I) = $(git rev-parse branch2) &&
206         test $(git rev-parse I) = $(git rev-parse HEAD)
207 '
208
209 test_expect_success 'test --onto <branch>' '
210         git checkout -b test-onto branch2 &&
211         set_fake_editor &&
212         git rebase -i --onto branch1 F &&
213         test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
214         test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
215         test $(git rev-parse I) = $(git rev-parse branch2)
216 '
217
218 test_expect_success 'rebase on top of a non-conflicting commit' '
219         git checkout branch1 &&
220         git tag original-branch1 &&
221         set_fake_editor &&
222         git rebase -i branch2 &&
223         test file6 = $(git diff --name-only original-branch1) &&
224         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
225         test $(git rev-parse I) = $(git rev-parse branch2) &&
226         test $(git rev-parse I) = $(git rev-parse HEAD~2)
227 '
228
229 test_expect_success 'reflog for the branch shows state before rebase' '
230         test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1)
231 '
232
233 test_expect_success 'reflog for the branch shows correct finish message' '
234         printf "rebase -i (finish): refs/heads/branch1 onto %s\n" \
235                 "$(git rev-parse branch2)" >expected &&
236         git log -g --pretty=%gs -1 refs/heads/branch1 >actual &&
237         test_cmp expected actual
238 '
239
240 test_expect_success 'exchange two commits' '
241         (
242                 set_fake_editor &&
243                 FAKE_LINES="2 1" git rebase -i HEAD~2
244         ) &&
245         test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
246         test G = $(git cat-file commit HEAD | sed -ne \$p)
247 '
248
249 test_expect_success 'stop on conflicting pick' '
250         cat >expect <<-\EOF &&
251         diff --git a/file1 b/file1
252         index f70f10e..fd79235 100644
253         --- a/file1
254         +++ b/file1
255         @@ -1 +1 @@
256         -A
257         +G
258         EOF
259         cat >expect2 <<-\EOF &&
260         <<<<<<< HEAD
261         D
262         =======
263         G
264         >>>>>>> 5d18e54... G
265         EOF
266         git tag new-branch1 &&
267         set_fake_editor &&
268         test_must_fail git rebase -i master &&
269         test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
270         test_cmp expect .git/rebase-merge/patch &&
271         test_cmp expect2 file1 &&
272         test "$(git diff --name-status |
273                 sed -n -e "/^U/s/^U[^a-z]*//p")" = file1 &&
274         test 4 = $(grep -v "^#" < .git/rebase-merge/done | wc -l) &&
275         test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
276 '
277
278 test_expect_success 'show conflicted patch' '
279         GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&
280         grep "show.*REBASE_HEAD" stderr &&
281         # the original stopped-sha1 is abbreviated
282         stopped_sha1="$(git rev-parse $(cat ".git/rebase-merge/stopped-sha"))" &&
283         test "$(git rev-parse REBASE_HEAD)" = "$stopped_sha1"
284 '
285
286 test_expect_success 'abort' '
287         git rebase --abort &&
288         test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
289         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
290         test_path_is_missing .git/rebase-merge
291 '
292
293 test_expect_success 'abort with error when new base cannot be checked out' '
294         git rm --cached file1 &&
295         git commit -m "remove file in base" &&
296         set_fake_editor &&
297         test_must_fail git rebase -i master > output 2>&1 &&
298         test_i18ngrep "The following untracked working tree files would be overwritten by checkout:" \
299                 output &&
300         test_i18ngrep "file1" output &&
301         test_path_is_missing .git/rebase-merge &&
302         git reset --hard HEAD^
303 '
304
305 test_expect_success 'retain authorship' '
306         echo A > file7 &&
307         git add file7 &&
308         test_tick &&
309         GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
310         git tag twerp &&
311         set_fake_editor &&
312         git rebase -i --onto master HEAD^ &&
313         git show HEAD | grep "^Author: Twerp Snog"
314 '
315
316 test_expect_success 'retain authorship w/ conflicts' '
317         oGIT_AUTHOR_NAME=$GIT_AUTHOR_NAME &&
318         test_when_finished "GIT_AUTHOR_NAME=\$oGIT_AUTHOR_NAME" &&
319
320         git reset --hard twerp &&
321         test_commit a conflict a conflict-a &&
322         git reset --hard twerp &&
323
324         GIT_AUTHOR_NAME=AttributeMe &&
325         export GIT_AUTHOR_NAME &&
326         test_commit b conflict b conflict-b &&
327         GIT_AUTHOR_NAME=$oGIT_AUTHOR_NAME &&
328
329         set_fake_editor &&
330         test_must_fail git rebase -i conflict-a &&
331         echo resolved >conflict &&
332         git add conflict &&
333         git rebase --continue &&
334         test $(git rev-parse conflict-a^0) = $(git rev-parse HEAD^) &&
335         git show >out &&
336         grep AttributeMe out
337 '
338
339 test_expect_success 'squash' '
340         git reset --hard twerp &&
341         echo B > file7 &&
342         test_tick &&
343         GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
344         echo "******************************" &&
345         (
346                 set_fake_editor &&
347                 FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
348                         git rebase -i --onto master HEAD~2
349         ) &&
350         test B = $(cat file7) &&
351         test $(git rev-parse HEAD^) = $(git rev-parse master)
352 '
353
354 test_expect_success 'retain authorship when squashing' '
355         git show HEAD | grep "^Author: Twerp Snog"
356 '
357
358 test_expect_success REBASE_P '-p handles "no changes" gracefully' '
359         HEAD=$(git rev-parse HEAD) &&
360         set_fake_editor &&
361         git rebase -i -p HEAD^ &&
362         git update-index --refresh &&
363         git diff-files --quiet &&
364         git diff-index --quiet --cached HEAD -- &&
365         test $HEAD = $(git rev-parse HEAD)
366 '
367
368 test_expect_failure REBASE_P 'exchange two commits with -p' '
369         git checkout H &&
370         (
371                 set_fake_editor &&
372                 FAKE_LINES="2 1" git rebase -i -p HEAD~2
373         ) &&
374         test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
375         test G = $(git cat-file commit HEAD | sed -ne \$p)
376 '
377
378 test_expect_success REBASE_P 'preserve merges with -p' '
379         git checkout -b to-be-preserved master^ &&
380         : > unrelated-file &&
381         git add unrelated-file &&
382         test_tick &&
383         git commit -m "unrelated" &&
384         git checkout -b another-branch master &&
385         echo B > file1 &&
386         test_tick &&
387         git commit -m J file1 &&
388         test_tick &&
389         git merge to-be-preserved &&
390         echo C > file1 &&
391         test_tick &&
392         git commit -m K file1 &&
393         echo D > file1 &&
394         test_tick &&
395         git commit -m L1 file1 &&
396         git checkout HEAD^ &&
397         echo 1 > unrelated-file &&
398         test_tick &&
399         git commit -m L2 unrelated-file &&
400         test_tick &&
401         git merge another-branch &&
402         echo E > file1 &&
403         test_tick &&
404         git commit -m M file1 &&
405         git checkout -b to-be-rebased &&
406         test_tick &&
407         set_fake_editor &&
408         git rebase -i -p --onto branch1 master &&
409         git update-index --refresh &&
410         git diff-files --quiet &&
411         git diff-index --quiet --cached HEAD -- &&
412         test $(git rev-parse HEAD~6) = $(git rev-parse branch1) &&
413         test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) &&
414         test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) &&
415         test $(git show HEAD~5:file1) = B &&
416         test $(git show HEAD~3:file1) = C &&
417         test $(git show HEAD:file1) = E &&
418         test $(git show HEAD:unrelated-file) = 1
419 '
420
421 test_expect_success REBASE_P 'edit ancestor with -p' '
422         (
423                 set_fake_editor &&
424                 FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3
425         ) &&
426         echo 2 > unrelated-file &&
427         test_tick &&
428         git commit -m L2-modified --amend unrelated-file &&
429         git rebase --continue &&
430         git update-index --refresh &&
431         git diff-files --quiet &&
432         git diff-index --quiet --cached HEAD -- &&
433         test $(git show HEAD:unrelated-file) = 2
434 '
435
436 test_expect_success '--continue tries to commit' '
437         git reset --hard D &&
438         test_tick &&
439         (
440                 set_fake_editor &&
441                 test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
442                 echo resolved > file1 &&
443                 git add file1 &&
444                 FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
445         ) &&
446         test $(git rev-parse HEAD^) = $(git rev-parse new-branch1) &&
447         git show HEAD | grep chouette
448 '
449
450 test_expect_success 'verbose flag is heeded, even after --continue' '
451         git reset --hard master@{1} &&
452         test_tick &&
453         set_fake_editor &&
454         test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
455         echo resolved > file1 &&
456         git add file1 &&
457         git rebase --continue > output &&
458         grep "^ file1 | 2 +-$" output
459 '
460
461 test_expect_success C_LOCALE_OUTPUT 'multi-squash only fires up editor once' '
462         base=$(git rev-parse HEAD~4) &&
463         (
464                 set_fake_editor &&
465                 FAKE_COMMIT_AMEND="ONCE" \
466                         FAKE_LINES="1 squash 2 squash 3 squash 4" \
467                         EXPECT_HEADER_COUNT=4 \
468                         git rebase -i $base
469         ) &&
470         test $base = $(git rev-parse HEAD^) &&
471         test 1 = $(git show | grep ONCE | wc -l)
472 '
473
474 test_expect_success C_LOCALE_OUTPUT 'multi-fixup does not fire up editor' '
475         git checkout -b multi-fixup E &&
476         base=$(git rev-parse HEAD~4) &&
477         (
478                 set_fake_editor &&
479                 FAKE_COMMIT_AMEND="NEVER" \
480                         FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
481                         git rebase -i $base
482         ) &&
483         test $base = $(git rev-parse HEAD^) &&
484         test 0 = $(git show | grep NEVER | wc -l) &&
485         git checkout @{-1} &&
486         git branch -D multi-fixup
487 '
488
489 test_expect_success 'commit message used after conflict' '
490         git checkout -b conflict-fixup conflict-branch &&
491         base=$(git rev-parse HEAD~4) &&
492         (
493                 set_fake_editor &&
494                 test_must_fail env FAKE_LINES="1 fixup 3 fixup 4" \
495                         git rebase -i $base &&
496                 echo three > conflict &&
497                 git add conflict &&
498                 FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \
499                         git rebase --continue
500         ) &&
501         test $base = $(git rev-parse HEAD^) &&
502         test 1 = $(git show | grep ONCE | wc -l) &&
503         git checkout @{-1} &&
504         git branch -D conflict-fixup
505 '
506
507 test_expect_success 'commit message retained after conflict' '
508         git checkout -b conflict-squash conflict-branch &&
509         base=$(git rev-parse HEAD~4) &&
510         (
511                 set_fake_editor &&
512                 test_must_fail env FAKE_LINES="1 fixup 3 squash 4" \
513                         git rebase -i $base &&
514                 echo three > conflict &&
515                 git add conflict &&
516                 FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \
517                         git rebase --continue
518         ) &&
519         test $base = $(git rev-parse HEAD^) &&
520         test 2 = $(git show | grep TWICE | wc -l) &&
521         git checkout @{-1} &&
522         git branch -D conflict-squash
523 '
524
525 test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
526         cat >expect-squash-fixup <<-\EOF &&
527         B
528
529         D
530
531         ONCE
532         EOF
533         git checkout -b squash-fixup E &&
534         base=$(git rev-parse HEAD~4) &&
535         (
536                 set_fake_editor &&
537                 FAKE_COMMIT_AMEND="ONCE" \
538                         FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
539                         EXPECT_HEADER_COUNT=4 \
540                         git rebase -i $base
541         ) &&
542         git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
543         test_cmp expect-squash-fixup actual-squash-fixup &&
544         git cat-file commit HEAD@{2} |
545                 grep "^# This is a combination of 3 commits\."  &&
546         git cat-file commit HEAD@{3} |
547                 grep "^# This is a combination of 2 commits\."  &&
548         git checkout @{-1} &&
549         git branch -D squash-fixup
550 '
551
552 test_expect_success C_LOCALE_OUTPUT 'squash ignores comments' '
553         git checkout -b skip-comments E &&
554         base=$(git rev-parse HEAD~4) &&
555         (
556                 set_fake_editor &&
557                 FAKE_COMMIT_AMEND="ONCE" \
558                         FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
559                         EXPECT_HEADER_COUNT=4 \
560                         git rebase -i $base
561         ) &&
562         test $base = $(git rev-parse HEAD^) &&
563         test 1 = $(git show | grep ONCE | wc -l) &&
564         git checkout @{-1} &&
565         git branch -D skip-comments
566 '
567
568 test_expect_success C_LOCALE_OUTPUT 'squash ignores blank lines' '
569         git checkout -b skip-blank-lines E &&
570         base=$(git rev-parse HEAD~4) &&
571         (
572                 set_fake_editor &&
573                 FAKE_COMMIT_AMEND="ONCE" \
574                         FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
575                         EXPECT_HEADER_COUNT=4 \
576                         git rebase -i $base
577         ) &&
578         test $base = $(git rev-parse HEAD^) &&
579         test 1 = $(git show | grep ONCE | wc -l) &&
580         git checkout @{-1} &&
581         git branch -D skip-blank-lines
582 '
583
584 test_expect_success 'squash works as expected' '
585         git checkout -b squash-works no-conflict-branch &&
586         one=$(git rev-parse HEAD~3) &&
587         (
588                 set_fake_editor &&
589                 FAKE_LINES="1 s 3 2" EXPECT_HEADER_COUNT=2 git rebase -i HEAD~3
590         ) &&
591         test $one = $(git rev-parse HEAD~2)
592 '
593
594 test_expect_success 'interrupted squash works as expected' '
595         git checkout -b interrupted-squash conflict-branch &&
596         one=$(git rev-parse HEAD~3) &&
597         (
598                 set_fake_editor &&
599                 test_must_fail env FAKE_LINES="1 squash 3 2" \
600                         git rebase -i HEAD~3
601         ) &&
602         test_write_lines one two four > conflict &&
603         git add conflict &&
604         test_must_fail git rebase --continue &&
605         echo resolved > conflict &&
606         git add conflict &&
607         git rebase --continue &&
608         test $one = $(git rev-parse HEAD~2)
609 '
610
611 test_expect_success 'interrupted squash works as expected (case 2)' '
612         git checkout -b interrupted-squash2 conflict-branch &&
613         one=$(git rev-parse HEAD~3) &&
614         (
615                 set_fake_editor &&
616                 test_must_fail env FAKE_LINES="3 squash 1 2" \
617                         git rebase -i HEAD~3
618         ) &&
619         test_write_lines one four > conflict &&
620         git add conflict &&
621         test_must_fail git rebase --continue &&
622         test_write_lines one two four > conflict &&
623         git add conflict &&
624         test_must_fail git rebase --continue &&
625         echo resolved > conflict &&
626         git add conflict &&
627         git rebase --continue &&
628         test $one = $(git rev-parse HEAD~2)
629 '
630
631 test_expect_success '--continue tries to commit, even for "edit"' '
632         echo unrelated > file7 &&
633         git add file7 &&
634         test_tick &&
635         git commit -m "unrelated change" &&
636         parent=$(git rev-parse HEAD^) &&
637         test_tick &&
638         (
639                 set_fake_editor &&
640                 FAKE_LINES="edit 1" git rebase -i HEAD^ &&
641                 echo edited > file7 &&
642                 git add file7 &&
643                 FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue
644         ) &&
645         test edited = $(git show HEAD:file7) &&
646         git show HEAD | grep chouette &&
647         test $parent = $(git rev-parse HEAD^)
648 '
649
650 test_expect_success 'aborted --continue does not squash commits after "edit"' '
651         old=$(git rev-parse HEAD) &&
652         test_tick &&
653         (
654                 set_fake_editor &&
655                 FAKE_LINES="edit 1" git rebase -i HEAD^ &&
656                 echo "edited again" > file7 &&
657                 git add file7 &&
658                 test_must_fail env FAKE_COMMIT_MESSAGE=" " git rebase --continue
659         ) &&
660         test $old = $(git rev-parse HEAD) &&
661         git rebase --abort
662 '
663
664 test_expect_success 'auto-amend only edited commits after "edit"' '
665         test_tick &&
666         (
667                 set_fake_editor &&
668                 FAKE_LINES="edit 1" git rebase -i HEAD^ &&
669                 echo "edited again" > file7 &&
670                 git add file7 &&
671                 FAKE_COMMIT_MESSAGE="edited file7 again" git commit &&
672                 echo "and again" > file7 &&
673                 git add file7 &&
674                 test_tick &&
675                 test_must_fail env FAKE_COMMIT_MESSAGE="and again" \
676                         git rebase --continue
677         ) &&
678         git rebase --abort
679 '
680
681 test_expect_success 'clean error after failed "exec"' '
682         test_tick &&
683         test_when_finished "git rebase --abort || :" &&
684         (
685                 set_fake_editor &&
686                 test_must_fail env FAKE_LINES="1 exec_false" git rebase -i HEAD^
687         ) &&
688         echo "edited again" > file7 &&
689         git add file7 &&
690         test_must_fail git rebase --continue 2>error &&
691         test_i18ngrep "you have staged changes in your working tree" error
692 '
693
694 test_expect_success 'rebase a detached HEAD' '
695         grandparent=$(git rev-parse HEAD~2) &&
696         git checkout $(git rev-parse HEAD) &&
697         test_tick &&
698         (
699                 set_fake_editor &&
700                 FAKE_LINES="2 1" git rebase -i HEAD~2
701         ) &&
702         test $grandparent = $(git rev-parse HEAD~2)
703 '
704
705 test_expect_success 'rebase a commit violating pre-commit' '
706
707         mkdir -p .git/hooks &&
708         write_script .git/hooks/pre-commit <<-\EOF &&
709         test -z "$(git diff --cached --check)"
710         EOF
711         echo "monde! " >> file1 &&
712         test_tick &&
713         test_must_fail git commit -m doesnt-verify file1 &&
714         git commit -m doesnt-verify --no-verify file1 &&
715         test_tick &&
716         (
717                 set_fake_editor &&
718                 FAKE_LINES=2 git rebase -i HEAD~2
719         )
720 '
721
722 test_expect_success 'rebase with a file named HEAD in worktree' '
723
724         rm -fr .git/hooks &&
725         git reset --hard &&
726         git checkout -b branch3 A &&
727
728         (
729                 GIT_AUTHOR_NAME="Squashed Away" &&
730                 export GIT_AUTHOR_NAME &&
731                 >HEAD &&
732                 git add HEAD &&
733                 git commit -m "Add head" &&
734                 >BODY &&
735                 git add BODY &&
736                 git commit -m "Add body"
737         ) &&
738
739         (
740                 set_fake_editor &&
741                 FAKE_LINES="1 squash 2" git rebase -i @{-1}
742         ) &&
743         test "$(git show -s --pretty=format:%an)" = "Squashed Away"
744
745 '
746
747 test_expect_success 'do "noop" when there is nothing to cherry-pick' '
748
749         git checkout -b branch4 HEAD &&
750         GIT_EDITOR=: git commit --amend \
751                 --author="Somebody else <somebody@else.com>" &&
752         test $(git rev-parse branch3) != $(git rev-parse branch4) &&
753         set_fake_editor &&
754         git rebase -i branch3 &&
755         test $(git rev-parse branch3) = $(git rev-parse branch4)
756
757 '
758
759 test_expect_success 'submodule rebase setup' '
760         git checkout A &&
761         mkdir sub &&
762         (
763                 cd sub && git init && >elif &&
764                 git add elif && git commit -m "submodule initial"
765         ) &&
766         echo 1 >file1 &&
767         git add file1 sub &&
768         test_tick &&
769         git commit -m "One" &&
770         echo 2 >file1 &&
771         test_tick &&
772         git commit -a -m "Two" &&
773         (
774                 cd sub && echo 3 >elif &&
775                 git commit -a -m "submodule second"
776         ) &&
777         test_tick &&
778         set_fake_editor &&
779         git commit -a -m "Three changes submodule"
780 '
781
782 test_expect_success 'submodule rebase -i' '
783         (
784                 set_fake_editor &&
785                 FAKE_LINES="1 squash 2 3" git rebase -i A
786         )
787 '
788
789 test_expect_success 'submodule conflict setup' '
790         git tag submodule-base &&
791         git checkout HEAD^ &&
792         (
793                 cd sub && git checkout HEAD^ && echo 4 >elif &&
794                 git add elif && git commit -m "submodule conflict"
795         ) &&
796         git add sub &&
797         test_tick &&
798         git commit -m "Conflict in submodule" &&
799         git tag submodule-topic
800 '
801
802 test_expect_success 'rebase -i continue with only submodule staged' '
803         set_fake_editor &&
804         test_must_fail git rebase -i submodule-base &&
805         git add sub &&
806         git rebase --continue &&
807         test $(git rev-parse submodule-base) != $(git rev-parse HEAD)
808 '
809
810 test_expect_success 'rebase -i continue with unstaged submodule' '
811         git checkout submodule-topic &&
812         git reset --hard &&
813         set_fake_editor &&
814         test_must_fail git rebase -i submodule-base &&
815         git reset &&
816         git rebase --continue &&
817         test $(git rev-parse submodule-base) = $(git rev-parse HEAD)
818 '
819
820 test_expect_success 'avoid unnecessary reset' '
821         git checkout master &&
822         git reset --hard &&
823         test-tool chmtime =123456789 file3 &&
824         git update-index --refresh &&
825         HEAD=$(git rev-parse HEAD) &&
826         set_fake_editor &&
827         git rebase -i HEAD~4 &&
828         test $HEAD = $(git rev-parse HEAD) &&
829         MTIME=$(test-tool chmtime --get file3) &&
830         test 123456789 = $MTIME
831 '
832
833 test_expect_success 'reword' '
834         git checkout -b reword-branch master &&
835         (
836                 set_fake_editor &&
837                 FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" \
838                         git rebase -i A &&
839                 git show HEAD | grep "E changed" &&
840                 test $(git rev-parse master) != $(git rev-parse HEAD) &&
841                 test $(git rev-parse master^) = $(git rev-parse HEAD^) &&
842                 FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" \
843                         git rebase -i A &&
844                 git show HEAD^ | grep "D changed" &&
845                 FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" \
846                         git rebase -i A &&
847                 git show HEAD~3 | grep "B changed" &&
848                 FAKE_LINES="1 r 2 pick 3 p 4" FAKE_COMMIT_MESSAGE="C changed" \
849                         git rebase -i A
850         ) &&
851         git show HEAD~2 | grep "C changed"
852 '
853
854 test_expect_success 'rebase -i can copy notes' '
855         git config notes.rewrite.rebase true &&
856         git config notes.rewriteRef "refs/notes/*" &&
857         test_commit n1 &&
858         test_commit n2 &&
859         test_commit n3 &&
860         git notes add -m"a note" n3 &&
861         set_fake_editor &&
862         git rebase -i --onto n1 n2 &&
863         test "a note" = "$(git notes show HEAD)"
864 '
865
866 test_expect_success 'rebase -i can copy notes over a fixup' '
867         cat >expect <<-\EOF &&
868         an earlier note
869
870         a note
871         EOF
872         git reset --hard n3 &&
873         git notes add -m"an earlier note" n2 &&
874         (
875                 set_fake_editor &&
876                 GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 f 2" \
877                         git rebase -i n1
878         ) &&
879         git notes show > output &&
880         test_cmp expect output
881 '
882
883 test_expect_success 'rebase while detaching HEAD' '
884         git symbolic-ref HEAD &&
885         grandparent=$(git rev-parse HEAD~2) &&
886         test_tick &&
887         (
888                 set_fake_editor &&
889                 FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0
890         ) &&
891         test $grandparent = $(git rev-parse HEAD~2) &&
892         test_must_fail git symbolic-ref HEAD
893 '
894
895 test_tick # Ensure that the rebased commits get a different timestamp.
896 test_expect_success 'always cherry-pick with --no-ff' '
897         git checkout no-ff-branch &&
898         git tag original-no-ff-branch &&
899         set_fake_editor &&
900         git rebase -i --no-ff A &&
901         for p in 0 1 2
902         do
903                 test ! $(git rev-parse HEAD~$p) = $(git rev-parse original-no-ff-branch~$p) &&
904                 git diff HEAD~$p original-no-ff-branch~$p > out &&
905                 test_must_be_empty out
906         done &&
907         test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) &&
908         git diff HEAD~3 original-no-ff-branch~3 > out &&
909         test_must_be_empty out
910 '
911
912 test_expect_success 'set up commits with funny messages' '
913         git checkout -b funny A &&
914         echo >>file1 &&
915         test_tick &&
916         git commit -a -m "end with slash\\" &&
917         echo >>file1 &&
918         test_tick &&
919         git commit -a -m "something (\000) that looks like octal" &&
920         echo >>file1 &&
921         test_tick &&
922         git commit -a -m "something (\n) that looks like a newline" &&
923         echo >>file1 &&
924         test_tick &&
925         git commit -a -m "another commit"
926 '
927
928 test_expect_success 'rebase-i history with funny messages' '
929         git rev-list A..funny >expect &&
930         test_tick &&
931         (
932                 set_fake_editor &&
933                 FAKE_LINES="1 2 3 4" git rebase -i A
934         ) &&
935         git rev-list A.. >actual &&
936         test_cmp expect actual
937 '
938
939 test_expect_success 'prepare for rebase -i --exec' '
940         git checkout master &&
941         git checkout -b execute &&
942         test_commit one_exec main.txt one_exec &&
943         test_commit two_exec main.txt two_exec &&
944         test_commit three_exec main.txt three_exec
945 '
946
947 test_expect_success 'running "git rebase -i --exec git show HEAD"' '
948         (
949                 set_fake_editor &&
950                 git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
951                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
952                 export FAKE_LINES &&
953                 git rebase -i HEAD~2 >expect
954         ) &&
955         sed -e "1,9d" expect >expected &&
956         test_cmp expected actual
957 '
958
959 test_expect_success 'running "git rebase --exec git show HEAD -i"' '
960         git reset --hard execute &&
961         (
962                 set_fake_editor &&
963                 git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
964                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
965                 export FAKE_LINES &&
966                 git rebase -i HEAD~2 >expect
967         ) &&
968         sed -e "1,9d" expect >expected &&
969         test_cmp expected actual
970 '
971
972 test_expect_success 'running "git rebase -ix git show HEAD"' '
973         git reset --hard execute &&
974         (
975                 set_fake_editor &&
976                 git rebase -ix "git show HEAD" HEAD~2 >actual &&
977                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
978                 export FAKE_LINES &&
979                 git rebase -i HEAD~2 >expect
980         ) &&
981         sed -e "1,9d" expect >expected &&
982         test_cmp expected actual
983 '
984
985
986 test_expect_success 'rebase -ix with several <CMD>' '
987         git reset --hard execute &&
988         (
989                 set_fake_editor &&
990                 git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
991                 FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
992                 export FAKE_LINES &&
993                 git rebase -i HEAD~2 >expect
994         ) &&
995         sed -e "1,9d" expect >expected &&
996         test_cmp expected actual
997 '
998
999 test_expect_success 'rebase -ix with several instances of --exec' '
1000         git reset --hard execute &&
1001         (
1002                 set_fake_editor &&
1003                 git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
1004                 FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
1005                                 exec_git_show_HEAD exec_pwd" &&
1006                 export FAKE_LINES &&
1007                 git rebase -i HEAD~2 >expect
1008         ) &&
1009         sed -e "1,11d" expect >expected &&
1010         test_cmp expected actual
1011 '
1012
1013 test_expect_success C_LOCALE_OUTPUT 'rebase -ix with --autosquash' '
1014         git reset --hard execute &&
1015         git checkout -b autosquash &&
1016         echo second >second.txt &&
1017         git add second.txt &&
1018         git commit -m "fixup! two_exec" &&
1019         echo bis >bis.txt &&
1020         git add bis.txt &&
1021         git commit -m "fixup! two_exec" &&
1022         git checkout -b autosquash_actual &&
1023         git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual &&
1024         git checkout autosquash &&
1025         (
1026                 set_fake_editor &&
1027                 git checkout -b autosquash_expected &&
1028                 FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
1029                 export FAKE_LINES &&
1030                 git rebase -i HEAD~4 >expect
1031         ) &&
1032         sed -e "1,13d" expect >expected &&
1033         test_cmp expected actual
1034 '
1035
1036 test_expect_success 'rebase --exec works without -i ' '
1037         git reset --hard execute &&
1038         rm -rf exec_output &&
1039         EDITOR="echo >invoked_editor" git rebase --exec "echo a line >>exec_output"  HEAD~2 2>actual &&
1040         test_i18ngrep  "Successfully rebased and updated" actual &&
1041         test_line_count = 2 exec_output &&
1042         test_path_is_missing invoked_editor
1043 '
1044
1045 test_expect_success 'rebase -i --exec without <CMD>' '
1046         git reset --hard execute &&
1047         set_fake_editor &&
1048         test_must_fail git rebase -i --exec 2>actual &&
1049         test_i18ngrep "requires a value" actual &&
1050         git checkout master
1051 '
1052
1053 test_expect_success 'rebase -i --root re-order and drop commits' '
1054         git checkout E &&
1055         (
1056                 set_fake_editor &&
1057                 FAKE_LINES="3 1 2 5" git rebase -i --root
1058         ) &&
1059         test E = $(git cat-file commit HEAD | sed -ne \$p) &&
1060         test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
1061         test A = $(git cat-file commit HEAD^^ | sed -ne \$p) &&
1062         test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) &&
1063         test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ )
1064 '
1065
1066 test_expect_success 'rebase -i --root retain root commit author and message' '
1067         git checkout A &&
1068         echo B >file7 &&
1069         git add file7 &&
1070         GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
1071         (
1072                 set_fake_editor &&
1073                 FAKE_LINES="2" git rebase -i --root
1074         ) &&
1075         git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
1076         git cat-file commit HEAD | grep -q "^different author$"
1077 '
1078
1079 test_expect_success 'rebase -i --root temporary sentinel commit' '
1080         git checkout B &&
1081         (
1082                 set_fake_editor &&
1083                 test_must_fail env FAKE_LINES="2" git rebase -i --root
1084         ) &&
1085         git cat-file commit HEAD | grep "^tree 4b825dc642cb" &&
1086         git rebase --abort
1087 '
1088
1089 test_expect_success 'rebase -i --root fixup root commit' '
1090         git checkout B &&
1091         (
1092                 set_fake_editor &&
1093                 FAKE_LINES="1 fixup 2" git rebase -i --root
1094         ) &&
1095         test A = $(git cat-file commit HEAD | sed -ne \$p) &&
1096         test B = $(git show HEAD:file1) &&
1097         test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
1098 '
1099
1100 test_expect_success 'rebase -i --root reword original root commit' '
1101         test_when_finished "test_might_fail git rebase --abort" &&
1102         git checkout -b reword-original-root-branch master &&
1103         (
1104                 set_fake_editor &&
1105                 FAKE_LINES="reword 1 2" FAKE_COMMIT_MESSAGE="A changed" \
1106                         git rebase -i --root
1107         ) &&
1108         git show HEAD^ | grep "A changed" &&
1109         test -z "$(git show -s --format=%p HEAD^)"
1110 '
1111
1112 test_expect_success 'rebase -i --root reword new root commit' '
1113         test_when_finished "test_might_fail git rebase --abort" &&
1114         git checkout -b reword-now-root-branch master &&
1115         (
1116                 set_fake_editor &&
1117                 FAKE_LINES="reword 3 1" FAKE_COMMIT_MESSAGE="C changed" \
1118                 git rebase -i --root
1119         ) &&
1120         git show HEAD^ | grep "C changed" &&
1121         test -z "$(git show -s --format=%p HEAD^)"
1122 '
1123
1124 test_expect_success 'rebase -i --root when root has untracked file conflict' '
1125         test_when_finished "reset_rebase" &&
1126         git checkout -b failing-root-pick A &&
1127         echo x >file2 &&
1128         git rm file1 &&
1129         git commit -m "remove file 1 add file 2" &&
1130         echo z >file1 &&
1131         (
1132                 set_fake_editor &&
1133                 test_must_fail env FAKE_LINES="1 2" git rebase -i --root
1134         ) &&
1135         rm file1 &&
1136         git rebase --continue &&
1137         test "$(git log -1 --format=%B)" = "remove file 1 add file 2" &&
1138         test "$(git rev-list --count HEAD)" = 2
1139 '
1140
1141 test_expect_success 'rebase -i --root reword root when root has untracked file conflict' '
1142         test_when_finished "reset_rebase" &&
1143         echo z>file1 &&
1144         (
1145                 set_fake_editor &&
1146                 test_must_fail env FAKE_LINES="reword 1 2" \
1147                         FAKE_COMMIT_MESSAGE="Modified A" git rebase -i --root &&
1148                 rm file1 &&
1149                 FAKE_COMMIT_MESSAGE="Reworded A" git rebase --continue
1150         ) &&
1151         test "$(git log -1 --format=%B HEAD^)" = "Reworded A" &&
1152         test "$(git rev-list --count HEAD)" = 2
1153 '
1154
1155 test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-interactive rebase' '
1156         git checkout reword-original-root-branch &&
1157         git reset --hard &&
1158         git checkout conflict-branch &&
1159         (
1160                 set_fake_editor &&
1161                 test_must_fail git rebase --onto HEAD~2 HEAD~ &&
1162                 test_must_fail git rebase --edit-todo
1163         ) &&
1164         git rebase --abort
1165 '
1166
1167 test_expect_success 'rebase --edit-todo can be used to modify todo' '
1168         git reset --hard &&
1169         git checkout no-conflict-branch^0 &&
1170         (
1171                 set_fake_editor &&
1172                 FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
1173                 FAKE_LINES="2 1" git rebase --edit-todo &&
1174                 git rebase --continue
1175         ) &&
1176         test M = $(git cat-file commit HEAD^ | sed -ne \$p) &&
1177         test L = $(git cat-file commit HEAD | sed -ne \$p)
1178 '
1179
1180 test_expect_success 'rebase -i produces readable reflog' '
1181         git reset --hard &&
1182         git branch -f branch-reflog-test H &&
1183         set_fake_editor &&
1184         git rebase -i --onto I F branch-reflog-test &&
1185         cat >expect <<-\EOF &&
1186         rebase -i (finish): returning to refs/heads/branch-reflog-test
1187         rebase -i (pick): H
1188         rebase -i (pick): G
1189         rebase -i (start): checkout I
1190         EOF
1191         git reflog -n4 HEAD |
1192         sed "s/[^:]*: //" >actual &&
1193         test_cmp expect actual
1194 '
1195
1196 test_expect_success 'rebase -i respects core.commentchar' '
1197         git reset --hard &&
1198         git checkout E^0 &&
1199         test_config core.commentchar "\\" &&
1200         write_script remove-all-but-first.sh <<-\EOF &&
1201         sed -e "2,\$s/^/\\\\/" "$1" >"$1.tmp" &&
1202         mv "$1.tmp" "$1"
1203         EOF
1204         (
1205                 test_set_editor "$(pwd)/remove-all-but-first.sh" &&
1206                 git rebase -i B
1207         ) &&
1208         test B = $(git cat-file commit HEAD^ | sed -ne \$p)
1209 '
1210
1211 test_expect_success 'rebase -i respects core.commentchar=auto' '
1212         test_config core.commentchar auto &&
1213         write_script copy-edit-script.sh <<-\EOF &&
1214         cp "$1" edit-script
1215         EOF
1216         test_when_finished "git rebase --abort || :" &&
1217         (
1218                 test_set_editor "$(pwd)/copy-edit-script.sh" &&
1219                 git rebase -i HEAD^
1220         ) &&
1221         test -z "$(grep -ve "^#" -e "^\$" -e "^pick" edit-script)"
1222 '
1223
1224 test_expect_success 'rebase -i, with <onto> and <upstream> specified as :/quuxery' '
1225         test_when_finished "git branch -D torebase" &&
1226         git checkout -b torebase branch1 &&
1227         upstream=$(git rev-parse ":/J") &&
1228         onto=$(git rev-parse ":/A") &&
1229         git rebase --onto $onto $upstream &&
1230         git reset --hard branch1 &&
1231         git rebase --onto ":/A" ":/J" &&
1232         git checkout branch1
1233 '
1234
1235 test_expect_success 'rebase -i with --strategy and -X' '
1236         git checkout -b conflict-merge-use-theirs conflict-branch &&
1237         git reset --hard HEAD^ &&
1238         echo five >conflict &&
1239         echo Z >file1 &&
1240         git commit -a -m "one file conflict" &&
1241         EDITOR=true git rebase -i --strategy=recursive -Xours conflict-branch &&
1242         test $(git show conflict-branch:conflict) = $(cat conflict) &&
1243         test $(cat file1) = Z
1244 '
1245
1246 test_expect_success 'interrupted rebase -i with --strategy and -X' '
1247         git checkout -b conflict-merge-use-theirs-interrupted conflict-branch &&
1248         git reset --hard HEAD^ &&
1249         >breakpoint &&
1250         git add breakpoint &&
1251         git commit -m "breakpoint for interactive mode" &&
1252         echo five >conflict &&
1253         echo Z >file1 &&
1254         git commit -a -m "one file conflict" &&
1255         (
1256                 set_fake_editor &&
1257                 FAKE_LINES="edit 1 2" git rebase -i --strategy=recursive \
1258                         -Xours conflict-branch
1259         ) &&
1260         git rebase --continue &&
1261         test $(git show conflict-branch:conflict) = $(cat conflict) &&
1262         test $(cat file1) = Z
1263 '
1264
1265 test_expect_success 'rebase -i error on commits with \ in message' '
1266         current_head=$(git rev-parse HEAD) &&
1267         test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&
1268         test_commit TO-REMOVE will-conflict old-content &&
1269         test_commit "\temp" will-conflict new-content dummy &&
1270         test_must_fail env EDITOR=true git rebase -i HEAD^ --onto HEAD^^ 2>error &&
1271         test_expect_code 1 grep  "      emp" error
1272 '
1273
1274 test_expect_success 'short SHA-1 setup' '
1275         test_when_finished "git checkout master" &&
1276         git checkout --orphan collide &&
1277         git rm -rf . &&
1278         (
1279         unset test_tick &&
1280         test_commit collide1 collide &&
1281         test_commit --notick collide2 collide &&
1282         test_commit --notick collide3 collide
1283         )
1284 '
1285
1286 test_expect_success 'short SHA-1 collide' '
1287         test_when_finished "reset_rebase && git checkout master" &&
1288         git checkout collide &&
1289         (
1290         unset test_tick &&
1291         test_tick &&
1292         set_fake_editor &&
1293         FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
1294         FAKE_LINES="reword 1 2" git rebase -i HEAD~2
1295         )
1296 '
1297
1298 test_expect_success 'respect core.abbrev' '
1299         git config core.abbrev 12 &&
1300         (
1301                 set_cat_todo_editor &&
1302                 test_must_fail git rebase -i HEAD~4 >todo-list
1303         ) &&
1304         test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list)
1305 '
1306
1307 test_expect_success 'todo count' '
1308         write_script dump-raw.sh <<-\EOF &&
1309                 cat "$1"
1310         EOF
1311         (
1312                 test_set_editor "$(pwd)/dump-raw.sh" &&
1313                 git rebase -i HEAD~4 >actual
1314         ) &&
1315         test_i18ngrep "^# Rebase ..* onto ..* ([0-9]" actual
1316 '
1317
1318 test_expect_success 'rebase -i commits that overwrite untracked files (pick)' '
1319         git checkout --force branch2 &&
1320         git clean -f &&
1321         (
1322                 set_fake_editor &&
1323                 FAKE_LINES="edit 1 2" git rebase -i A
1324         ) &&
1325         test_cmp_rev HEAD F &&
1326         test_path_is_missing file6 &&
1327         >file6 &&
1328         test_must_fail git rebase --continue &&
1329         test_cmp_rev HEAD F &&
1330         rm file6 &&
1331         git rebase --continue &&
1332         test_cmp_rev HEAD I
1333 '
1334
1335 test_expect_success 'rebase -i commits that overwrite untracked files (squash)' '
1336         git checkout --force branch2 &&
1337         git clean -f &&
1338         git tag original-branch2 &&
1339         (
1340                 set_fake_editor &&
1341                 FAKE_LINES="edit 1 squash 2" git rebase -i A
1342         ) &&
1343         test_cmp_rev HEAD F &&
1344         test_path_is_missing file6 &&
1345         >file6 &&
1346         test_must_fail git rebase --continue &&
1347         test_cmp_rev HEAD F &&
1348         rm file6 &&
1349         git rebase --continue &&
1350         test $(git cat-file commit HEAD | sed -ne \$p) = I &&
1351         git reset --hard original-branch2
1352 '
1353
1354 test_expect_success 'rebase -i commits that overwrite untracked files (no ff)' '
1355         git checkout --force branch2 &&
1356         git clean -f &&
1357         (
1358                 set_fake_editor &&
1359                 FAKE_LINES="edit 1 2" git rebase -i --no-ff A
1360         ) &&
1361         test $(git cat-file commit HEAD | sed -ne \$p) = F &&
1362         test_path_is_missing file6 &&
1363         >file6 &&
1364         test_must_fail git rebase --continue &&
1365         test $(git cat-file commit HEAD | sed -ne \$p) = F &&
1366         rm file6 &&
1367         git rebase --continue &&
1368         test $(git cat-file commit HEAD | sed -ne \$p) = I
1369 '
1370
1371 test_expect_success 'rebase --continue removes CHERRY_PICK_HEAD' '
1372         git checkout -b commit-to-skip &&
1373         for double in X 3 1
1374         do
1375                 test_seq 5 | sed "s/$double/&&/" >seq &&
1376                 git add seq &&
1377                 test_tick &&
1378                 git commit -m seq-$double
1379         done &&
1380         git tag seq-onto &&
1381         git reset --hard HEAD~2 &&
1382         git cherry-pick seq-onto &&
1383         (
1384                 set_fake_editor &&
1385                 test_must_fail env FAKE_LINES= git rebase -i seq-onto
1386         ) &&
1387         test -d .git/rebase-merge &&
1388         git rebase --continue &&
1389         git diff --exit-code seq-onto &&
1390         test ! -d .git/rebase-merge &&
1391         test ! -f .git/CHERRY_PICK_HEAD
1392 '
1393
1394 rebase_setup_and_clean () {
1395         test_when_finished "
1396                 git checkout master &&
1397                 test_might_fail git branch -D $1 &&
1398                 test_might_fail git rebase --abort
1399         " &&
1400         git checkout -b $1 ${2:-master}
1401 }
1402
1403 test_expect_success 'drop' '
1404         rebase_setup_and_clean drop-test &&
1405         (
1406                 set_fake_editor &&
1407                 FAKE_LINES="1 drop 2 3 d 4 5" git rebase -i --root
1408         ) &&
1409         test E = $(git cat-file commit HEAD | sed -ne \$p) &&
1410         test C = $(git cat-file commit HEAD^ | sed -ne \$p) &&
1411         test A = $(git cat-file commit HEAD^^ | sed -ne \$p)
1412 '
1413
1414 test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
1415         test_config rebase.missingCommitsCheck ignore &&
1416         rebase_setup_and_clean missing-commit &&
1417         (
1418                 set_fake_editor &&
1419                 FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual
1420         ) &&
1421         test D = $(git cat-file commit HEAD | sed -ne \$p) &&
1422         test_i18ngrep \
1423                 "Successfully rebased and updated refs/heads/missing-commit" \
1424                 actual
1425 '
1426
1427 test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
1428         cat >expect <<-EOF &&
1429         Warning: some commits may have been dropped accidentally.
1430         Dropped commits (newer to older):
1431          - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
1432         To avoid this message, use "drop" to explicitly remove a commit.
1433         EOF
1434         test_config rebase.missingCommitsCheck warn &&
1435         rebase_setup_and_clean missing-commit &&
1436         (
1437                 set_fake_editor &&
1438                 FAKE_LINES="1 2 3 4" git rebase -i --root 2>actual.2
1439         ) &&
1440         head -n4 actual.2 >actual &&
1441         test_i18ncmp expect actual &&
1442         test D = $(git cat-file commit HEAD | sed -ne \$p)
1443 '
1444
1445 test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
1446         cat >expect <<-EOF &&
1447         Warning: some commits may have been dropped accidentally.
1448         Dropped commits (newer to older):
1449          - $(git rev-list --pretty=oneline --abbrev-commit -1 master)
1450          - $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
1451         To avoid this message, use "drop" to explicitly remove a commit.
1452
1453         Use '\''git config rebase.missingCommitsCheck'\'' to change the level of warnings.
1454         The possible behaviours are: ignore, warn, error.
1455
1456         You can fix this with '\''git rebase --edit-todo'\'' and then run '\''git rebase --continue'\''.
1457         Or you can abort the rebase with '\''git rebase --abort'\''.
1458         EOF
1459         test_config rebase.missingCommitsCheck error &&
1460         rebase_setup_and_clean missing-commit &&
1461         (
1462                 set_fake_editor &&
1463                 test_must_fail env FAKE_LINES="1 2 4" \
1464                         git rebase -i --root 2>actual &&
1465                 test_i18ncmp expect actual &&
1466                 cp .git/rebase-merge/git-rebase-todo.backup \
1467                         .git/rebase-merge/git-rebase-todo &&
1468                 FAKE_LINES="1 2 drop 3 4 drop 5" git rebase --edit-todo
1469         ) &&
1470         git rebase --continue &&
1471         test D = $(git cat-file commit HEAD | sed -ne \$p) &&
1472         test B = $(git cat-file commit HEAD^ | sed -ne \$p)
1473 '
1474
1475 test_expect_success 'respects rebase.abbreviateCommands with fixup, squash and exec' '
1476         rebase_setup_and_clean abbrevcmd &&
1477         test_commit "first" file1.txt "first line" first &&
1478         test_commit "second" file1.txt "another line" second &&
1479         test_commit "fixup! first" file2.txt "first line again" first_fixup &&
1480         test_commit "squash! second" file1.txt "another line here" second_squash &&
1481         cat >expected <<-EOF &&
1482         p $(git rev-list --abbrev-commit -1 first) first
1483         f $(git rev-list --abbrev-commit -1 first_fixup) fixup! first
1484         x git show HEAD
1485         p $(git rev-list --abbrev-commit -1 second) second
1486         s $(git rev-list --abbrev-commit -1 second_squash) squash! second
1487         x git show HEAD
1488         EOF
1489         git checkout abbrevcmd &&
1490         test_config rebase.abbreviateCommands true &&
1491         (
1492                 set_cat_todo_editor &&
1493                 test_must_fail git rebase -i --exec "git show HEAD" \
1494                         --autosquash master >actual
1495         ) &&
1496         test_cmp expected actual
1497 '
1498
1499 test_expect_success 'static check of bad command' '
1500         rebase_setup_and_clean bad-cmd &&
1501         (
1502                 set_fake_editor &&
1503                 test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
1504                 git rebase -i --root 2>actual &&
1505                 test_i18ngrep "badcmd $(git rev-list --oneline -1 master~1)" \
1506                                 actual &&
1507                 test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
1508                                 actual &&
1509                 FAKE_LINES="1 2 3 drop 4 5" git rebase --edit-todo
1510         ) &&
1511         git rebase --continue &&
1512         test E = $(git cat-file commit HEAD | sed -ne \$p) &&
1513         test C = $(git cat-file commit HEAD^ | sed -ne \$p)
1514 '
1515
1516 test_expect_success 'tabs and spaces are accepted in the todolist' '
1517         rebase_setup_and_clean indented-comment &&
1518         write_script add-indent.sh <<-\EOF &&
1519         (
1520                 # Turn single spaces into space/tab mix
1521                 sed "1s/ /      /g; 2s/ /  /g; 3s/ /    /g" "$1"
1522                 printf "\n\t# comment\n #more\n\t # comment\n"
1523         ) >"$1.new"
1524         mv "$1.new" "$1"
1525         EOF
1526         (
1527                 test_set_editor "$(pwd)/add-indent.sh" &&
1528                 git rebase -i HEAD^^^
1529         ) &&
1530         test E = $(git cat-file commit HEAD | sed -ne \$p)
1531 '
1532
1533 test_expect_success 'static check of bad SHA-1' '
1534         rebase_setup_and_clean bad-sha &&
1535         (
1536                 set_fake_editor &&
1537                 test_must_fail env FAKE_LINES="1 2 edit fakesha 3 4 5 #" \
1538                         git rebase -i --root 2>actual &&
1539                         test_i18ngrep "edit XXXXXXX False commit" actual &&
1540                         test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
1541                                         actual &&
1542                 FAKE_LINES="1 2 4 5 6" git rebase --edit-todo
1543         ) &&
1544         git rebase --continue &&
1545         test E = $(git cat-file commit HEAD | sed -ne \$p)
1546 '
1547
1548 test_expect_success 'editor saves as CR/LF' '
1549         git checkout -b with-crlf &&
1550         write_script add-crs.sh <<-\EOF &&
1551         sed -e "s/\$/Q/" <"$1" | tr Q "\\015" >"$1".new &&
1552         mv -f "$1".new "$1"
1553         EOF
1554         (
1555                 test_set_editor "$(pwd)/add-crs.sh" &&
1556                 git rebase -i HEAD^
1557         )
1558 '
1559
1560 SQ="'"
1561 test_expect_success 'rebase -i --gpg-sign=<key-id>' '
1562         test_when_finished "test_might_fail git rebase --abort" &&
1563         (
1564                 set_fake_editor &&
1565                 FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" \
1566                         HEAD^ >out 2>err
1567         ) &&
1568         test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
1569 '
1570
1571 test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
1572         test_when_finished "test_might_fail git rebase --abort" &&
1573         test_config commit.gpgsign true &&
1574         (
1575                 set_fake_editor &&
1576                 FAKE_LINES="edit 1" git rebase -i --gpg-sign="\"S I Gner\"" \
1577                         HEAD^ >out 2>err
1578         ) &&
1579         test_i18ngrep "$SQ-S\"S I Gner\"$SQ" err
1580 '
1581
1582 test_expect_success 'valid author header after --root swap' '
1583         rebase_setup_and_clean author-header no-conflict-branch &&
1584         git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit &&
1585         git cat-file commit HEAD | grep ^author >expected &&
1586         (
1587                 set_fake_editor &&
1588                 FAKE_LINES="5 1" git rebase -i --root
1589         ) &&
1590         git cat-file commit HEAD^ | grep ^author >actual &&
1591         test_cmp expected actual
1592 '
1593
1594 test_expect_success 'valid author header when author contains single quote' '
1595         rebase_setup_and_clean author-header no-conflict-branch &&
1596         git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit &&
1597         git cat-file commit HEAD | grep ^author >expected &&
1598         (
1599                 set_fake_editor &&
1600                 FAKE_LINES="2" git rebase -i HEAD~2
1601         ) &&
1602         git cat-file commit HEAD | grep ^author >actual &&
1603         test_cmp expected actual
1604 '
1605
1606 test_done