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