Merge branch 'jk/config-int-range-check'
[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 ran 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. Unseting 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 -i with the exec command' '
71         git checkout master &&
72         (
73         set_fake_editor &&
74         FAKE_LINES="1 exec_>touch-one
75                 2 exec_>touch-two exec_false exec_>touch-three
76                 3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
77         export FAKE_LINES &&
78         test_must_fail git rebase -i A
79         ) &&
80         test_path_is_file touch-one &&
81         test_path_is_file touch-two &&
82         test_path_is_missing touch-three " (should have stopped before)" &&
83         test_cmp_rev C HEAD &&
84         git rebase --continue &&
85         test_path_is_file touch-three &&
86         test_path_is_file "touch-file  name with spaces" &&
87         test_path_is_file touch-after-semicolon &&
88         test_cmp_rev master HEAD &&
89         rm -f touch-*
90 '
91
92 test_expect_success 'rebase -i with the exec command runs from tree root' '
93         git checkout master &&
94         mkdir subdir && (cd subdir &&
95         set_fake_editor &&
96         FAKE_LINES="1 exec_>touch-subdir" \
97                 git rebase -i HEAD^
98         ) &&
99         test_path_is_file touch-subdir &&
100         rm -fr subdir
101 '
102
103 test_expect_success 'rebase -i with the exec command checks tree cleanness' '
104         git checkout master &&
105         (
106         set_fake_editor &&
107         FAKE_LINES="exec_echo_foo_>file1 1" &&
108         export FAKE_LINES &&
109         test_must_fail git rebase -i HEAD^
110         ) &&
111         test_cmp_rev master^ HEAD &&
112         git reset --hard &&
113         git rebase --continue
114 '
115
116 test_expect_success 'rebase -i with exec of inexistent command' '
117         git checkout master &&
118         test_when_finished "git rebase --abort" &&
119         (
120         set_fake_editor &&
121         FAKE_LINES="exec_this-command-does-not-exist 1" &&
122         export FAKE_LINES &&
123         test_must_fail git rebase -i HEAD^ >actual 2>&1
124         ) &&
125         ! grep "Maybe git-rebase is broken" actual
126 '
127
128 test_expect_success 'no changes are a nop' '
129         git checkout branch2 &&
130         set_fake_editor &&
131         git rebase -i F &&
132         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
133         test $(git rev-parse I) = $(git rev-parse HEAD)
134 '
135
136 test_expect_success 'test the [branch] option' '
137         git checkout -b dead-end &&
138         git rm file6 &&
139         git commit -m "stop here" &&
140         set_fake_editor &&
141         git rebase -i F branch2 &&
142         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
143         test $(git rev-parse I) = $(git rev-parse branch2) &&
144         test $(git rev-parse I) = $(git rev-parse HEAD)
145 '
146
147 test_expect_success 'test --onto <branch>' '
148         git checkout -b test-onto branch2 &&
149         set_fake_editor &&
150         git rebase -i --onto branch1 F &&
151         test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
152         test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
153         test $(git rev-parse I) = $(git rev-parse branch2)
154 '
155
156 test_expect_success 'rebase on top of a non-conflicting commit' '
157         git checkout branch1 &&
158         git tag original-branch1 &&
159         set_fake_editor &&
160         git rebase -i branch2 &&
161         test file6 = $(git diff --name-only original-branch1) &&
162         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
163         test $(git rev-parse I) = $(git rev-parse branch2) &&
164         test $(git rev-parse I) = $(git rev-parse HEAD~2)
165 '
166
167 test_expect_success 'reflog for the branch shows state before rebase' '
168         test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1)
169 '
170
171 test_expect_success 'exchange two commits' '
172         set_fake_editor &&
173         FAKE_LINES="2 1" git rebase -i HEAD~2 &&
174         test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
175         test G = $(git cat-file commit HEAD | sed -ne \$p)
176 '
177
178 cat > expect << EOF
179 diff --git a/file1 b/file1
180 index f70f10e..fd79235 100644
181 --- a/file1
182 +++ b/file1
183 @@ -1 +1 @@
184 -A
185 +G
186 EOF
187
188 cat > expect2 << EOF
189 <<<<<<< HEAD
190 D
191 =======
192 G
193 >>>>>>> 5d18e54... G
194 EOF
195
196 test_expect_success 'stop on conflicting pick' '
197         git tag new-branch1 &&
198         set_fake_editor &&
199         test_must_fail git rebase -i master &&
200         test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
201         test_cmp expect .git/rebase-merge/patch &&
202         test_cmp expect2 file1 &&
203         test "$(git diff --name-status |
204                 sed -n -e "/^U/s/^U[^a-z]*//p")" = file1 &&
205         test 4 = $(grep -v "^#" < .git/rebase-merge/done | wc -l) &&
206         test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo)
207 '
208
209 test_expect_success 'abort' '
210         git rebase --abort &&
211         test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
212         test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
213         test_path_is_missing .git/rebase-merge
214 '
215
216 test_expect_success 'abort with error when new base cannot be checked out' '
217         git rm --cached file1 &&
218         git commit -m "remove file in base" &&
219         set_fake_editor &&
220         test_must_fail git rebase -i master > output 2>&1 &&
221         grep "The following untracked working tree files would be overwritten by checkout:" \
222                 output &&
223         grep "file1" output &&
224         test_path_is_missing .git/rebase-merge &&
225         git reset --hard HEAD^
226 '
227
228 test_expect_success 'retain authorship' '
229         echo A > file7 &&
230         git add file7 &&
231         test_tick &&
232         GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
233         git tag twerp &&
234         set_fake_editor &&
235         git rebase -i --onto master HEAD^ &&
236         git show HEAD | grep "^Author: Twerp Snog"
237 '
238
239 test_expect_success 'squash' '
240         git reset --hard twerp &&
241         echo B > file7 &&
242         test_tick &&
243         GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
244         echo "******************************" &&
245         set_fake_editor &&
246         FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
247                 git rebase -i --onto master HEAD~2 &&
248         test B = $(cat file7) &&
249         test $(git rev-parse HEAD^) = $(git rev-parse master)
250 '
251
252 test_expect_success 'retain authorship when squashing' '
253         git show HEAD | grep "^Author: Twerp Snog"
254 '
255
256 test_expect_success '-p handles "no changes" gracefully' '
257         HEAD=$(git rev-parse HEAD) &&
258         set_fake_editor &&
259         git rebase -i -p HEAD^ &&
260         git update-index --refresh &&
261         git diff-files --quiet &&
262         git diff-index --quiet --cached HEAD -- &&
263         test $HEAD = $(git rev-parse HEAD)
264 '
265
266 test_expect_failure 'exchange two commits with -p' '
267         git checkout H &&
268         set_fake_editor &&
269         FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
270         test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
271         test G = $(git cat-file commit HEAD | sed -ne \$p)
272 '
273
274 test_expect_success 'preserve merges with -p' '
275         git checkout -b to-be-preserved master^ &&
276         : > unrelated-file &&
277         git add unrelated-file &&
278         test_tick &&
279         git commit -m "unrelated" &&
280         git checkout -b another-branch master &&
281         echo B > file1 &&
282         test_tick &&
283         git commit -m J file1 &&
284         test_tick &&
285         git merge to-be-preserved &&
286         echo C > file1 &&
287         test_tick &&
288         git commit -m K file1 &&
289         echo D > file1 &&
290         test_tick &&
291         git commit -m L1 file1 &&
292         git checkout HEAD^ &&
293         echo 1 > unrelated-file &&
294         test_tick &&
295         git commit -m L2 unrelated-file &&
296         test_tick &&
297         git merge another-branch &&
298         echo E > file1 &&
299         test_tick &&
300         git commit -m M file1 &&
301         git checkout -b to-be-rebased &&
302         test_tick &&
303         set_fake_editor &&
304         git rebase -i -p --onto branch1 master &&
305         git update-index --refresh &&
306         git diff-files --quiet &&
307         git diff-index --quiet --cached HEAD -- &&
308         test $(git rev-parse HEAD~6) = $(git rev-parse branch1) &&
309         test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) &&
310         test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) &&
311         test $(git show HEAD~5:file1) = B &&
312         test $(git show HEAD~3:file1) = C &&
313         test $(git show HEAD:file1) = E &&
314         test $(git show HEAD:unrelated-file) = 1
315 '
316
317 test_expect_success 'edit ancestor with -p' '
318         set_fake_editor &&
319         FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
320         echo 2 > unrelated-file &&
321         test_tick &&
322         git commit -m L2-modified --amend unrelated-file &&
323         git rebase --continue &&
324         git update-index --refresh &&
325         git diff-files --quiet &&
326         git diff-index --quiet --cached HEAD -- &&
327         test $(git show HEAD:unrelated-file) = 2
328 '
329
330 test_expect_success '--continue tries to commit' '
331         test_tick &&
332         set_fake_editor &&
333         test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
334         echo resolved > file1 &&
335         git add file1 &&
336         FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue &&
337         test $(git rev-parse HEAD^) = $(git rev-parse new-branch1) &&
338         git show HEAD | grep chouette
339 '
340
341 test_expect_success 'verbose flag is heeded, even after --continue' '
342         git reset --hard master@{1} &&
343         test_tick &&
344         set_fake_editor &&
345         test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
346         echo resolved > file1 &&
347         git add file1 &&
348         git rebase --continue > output &&
349         grep "^ file1 | 2 +-$" output
350 '
351
352 test_expect_success 'multi-squash only fires up editor once' '
353         base=$(git rev-parse HEAD~4) &&
354         set_fake_editor &&
355         FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
356                 EXPECT_HEADER_COUNT=4 \
357                 git rebase -i $base &&
358         test $base = $(git rev-parse HEAD^) &&
359         test 1 = $(git show | grep ONCE | wc -l)
360 '
361
362 test_expect_success 'multi-fixup does not fire up editor' '
363         git checkout -b multi-fixup E &&
364         base=$(git rev-parse HEAD~4) &&
365         set_fake_editor &&
366         FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
367                 git rebase -i $base &&
368         test $base = $(git rev-parse HEAD^) &&
369         test 0 = $(git show | grep NEVER | wc -l) &&
370         git checkout to-be-rebased &&
371         git branch -D multi-fixup
372 '
373
374 test_expect_success 'commit message used after conflict' '
375         git checkout -b conflict-fixup conflict-branch &&
376         base=$(git rev-parse HEAD~4) &&
377         set_fake_editor &&
378         (
379                 FAKE_LINES="1 fixup 3 fixup 4" &&
380                 export FAKE_LINES &&
381                 test_must_fail git rebase -i $base
382         ) &&
383         echo three > conflict &&
384         git add conflict &&
385         FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \
386                 git rebase --continue &&
387         test $base = $(git rev-parse HEAD^) &&
388         test 1 = $(git show | grep ONCE | wc -l) &&
389         git checkout to-be-rebased &&
390         git branch -D conflict-fixup
391 '
392
393 test_expect_success 'commit message retained after conflict' '
394         git checkout -b conflict-squash conflict-branch &&
395         base=$(git rev-parse HEAD~4) &&
396         set_fake_editor &&
397         (
398                 FAKE_LINES="1 fixup 3 squash 4" &&
399                 export FAKE_LINES &&
400                 test_must_fail git rebase -i $base
401         ) &&
402         echo three > conflict &&
403         git add conflict &&
404         FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \
405                 git rebase --continue &&
406         test $base = $(git rev-parse HEAD^) &&
407         test 2 = $(git show | grep TWICE | wc -l) &&
408         git checkout to-be-rebased &&
409         git branch -D conflict-squash
410 '
411
412 cat > expect-squash-fixup << EOF
413 B
414
415 D
416
417 ONCE
418 EOF
419
420 test_expect_success 'squash and fixup generate correct log messages' '
421         git checkout -b squash-fixup E &&
422         base=$(git rev-parse HEAD~4) &&
423         set_fake_editor &&
424         FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
425                 EXPECT_HEADER_COUNT=4 \
426                 git rebase -i $base &&
427         git cat-file commit HEAD | sed -e 1,/^\$/d > actual-squash-fixup &&
428         test_cmp expect-squash-fixup actual-squash-fixup &&
429         git checkout to-be-rebased &&
430         git branch -D squash-fixup
431 '
432
433 test_expect_success 'squash ignores comments' '
434         git checkout -b skip-comments E &&
435         base=$(git rev-parse HEAD~4) &&
436         set_fake_editor &&
437         FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
438                 EXPECT_HEADER_COUNT=4 \
439                 git rebase -i $base &&
440         test $base = $(git rev-parse HEAD^) &&
441         test 1 = $(git show | grep ONCE | wc -l) &&
442         git checkout to-be-rebased &&
443         git branch -D skip-comments
444 '
445
446 test_expect_success 'squash ignores blank lines' '
447         git checkout -b skip-blank-lines E &&
448         base=$(git rev-parse HEAD~4) &&
449         set_fake_editor &&
450         FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
451                 EXPECT_HEADER_COUNT=4 \
452                 git rebase -i $base &&
453         test $base = $(git rev-parse HEAD^) &&
454         test 1 = $(git show | grep ONCE | wc -l) &&
455         git checkout to-be-rebased &&
456         git branch -D skip-blank-lines
457 '
458
459 test_expect_success 'squash works as expected' '
460         git checkout -b squash-works no-conflict-branch &&
461         one=$(git rev-parse HEAD~3) &&
462         set_fake_editor &&
463         FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
464                 git rebase -i HEAD~3 &&
465         test $one = $(git rev-parse HEAD~2)
466 '
467
468 test_expect_success 'interrupted squash works as expected' '
469         git checkout -b interrupted-squash conflict-branch &&
470         one=$(git rev-parse HEAD~3) &&
471         set_fake_editor &&
472         (
473                 FAKE_LINES="1 squash 3 2" &&
474                 export FAKE_LINES &&
475                 test_must_fail git rebase -i HEAD~3
476         ) &&
477         (echo one; echo two; echo four) > conflict &&
478         git add conflict &&
479         test_must_fail git rebase --continue &&
480         echo resolved > conflict &&
481         git add conflict &&
482         git rebase --continue &&
483         test $one = $(git rev-parse HEAD~2)
484 '
485
486 test_expect_success 'interrupted squash works as expected (case 2)' '
487         git checkout -b interrupted-squash2 conflict-branch &&
488         one=$(git rev-parse HEAD~3) &&
489         set_fake_editor &&
490         (
491                 FAKE_LINES="3 squash 1 2" &&
492                 export FAKE_LINES &&
493                 test_must_fail git rebase -i HEAD~3
494         ) &&
495         (echo one; echo four) > conflict &&
496         git add conflict &&
497         test_must_fail git rebase --continue &&
498         (echo one; echo two; echo four) > conflict &&
499         git add conflict &&
500         test_must_fail git rebase --continue &&
501         echo resolved > conflict &&
502         git add conflict &&
503         git rebase --continue &&
504         test $one = $(git rev-parse HEAD~2)
505 '
506
507 test_expect_success '--continue tries to commit, even for "edit"' '
508         echo unrelated > file7 &&
509         git add file7 &&
510         test_tick &&
511         git commit -m "unrelated change" &&
512         parent=$(git rev-parse HEAD^) &&
513         test_tick &&
514         set_fake_editor &&
515         FAKE_LINES="edit 1" git rebase -i HEAD^ &&
516         echo edited > file7 &&
517         git add file7 &&
518         FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue &&
519         test edited = $(git show HEAD:file7) &&
520         git show HEAD | grep chouette &&
521         test $parent = $(git rev-parse HEAD^)
522 '
523
524 test_expect_success 'aborted --continue does not squash commits after "edit"' '
525         old=$(git rev-parse HEAD) &&
526         test_tick &&
527         set_fake_editor &&
528         FAKE_LINES="edit 1" git rebase -i HEAD^ &&
529         echo "edited again" > file7 &&
530         git add file7 &&
531         (
532                 FAKE_COMMIT_MESSAGE=" " &&
533                 export FAKE_COMMIT_MESSAGE &&
534                 test_must_fail git rebase --continue
535         ) &&
536         test $old = $(git rev-parse HEAD) &&
537         git rebase --abort
538 '
539
540 test_expect_success 'auto-amend only edited commits after "edit"' '
541         test_tick &&
542         set_fake_editor &&
543         FAKE_LINES="edit 1" git rebase -i HEAD^ &&
544         echo "edited again" > file7 &&
545         git add file7 &&
546         FAKE_COMMIT_MESSAGE="edited file7 again" git commit &&
547         echo "and again" > file7 &&
548         git add file7 &&
549         test_tick &&
550         (
551                 FAKE_COMMIT_MESSAGE="and again" &&
552                 export FAKE_COMMIT_MESSAGE &&
553                 test_must_fail git rebase --continue
554         ) &&
555         git rebase --abort
556 '
557
558 test_expect_success 'clean error after failed "exec"' '
559         test_tick &&
560         test_when_finished "git rebase --abort || :" &&
561         set_fake_editor &&
562         (
563                 FAKE_LINES="1 exec_false" &&
564                 export FAKE_LINES &&
565                 test_must_fail git rebase -i HEAD^
566         ) &&
567         echo "edited again" > file7 &&
568         git add file7 &&
569         test_must_fail git rebase --continue 2>error &&
570         grep "You have staged changes in your working tree." error
571 '
572
573 test_expect_success 'rebase a detached HEAD' '
574         grandparent=$(git rev-parse HEAD~2) &&
575         git checkout $(git rev-parse HEAD) &&
576         test_tick &&
577         set_fake_editor &&
578         FAKE_LINES="2 1" git rebase -i HEAD~2 &&
579         test $grandparent = $(git rev-parse HEAD~2)
580 '
581
582 test_expect_success 'rebase a commit violating pre-commit' '
583
584         mkdir -p .git/hooks &&
585         PRE_COMMIT=.git/hooks/pre-commit &&
586         echo "#!/bin/sh" > $PRE_COMMIT &&
587         echo "test -z \"\$(git diff --cached --check)\"" >> $PRE_COMMIT &&
588         chmod a+x $PRE_COMMIT &&
589         echo "monde! " >> file1 &&
590         test_tick &&
591         test_must_fail git commit -m doesnt-verify file1 &&
592         git commit -m doesnt-verify --no-verify file1 &&
593         test_tick &&
594         set_fake_editor &&
595         FAKE_LINES=2 git rebase -i HEAD~2
596
597 '
598
599 test_expect_success 'rebase with a file named HEAD in worktree' '
600
601         rm -fr .git/hooks &&
602         git reset --hard &&
603         git checkout -b branch3 A &&
604
605         (
606                 GIT_AUTHOR_NAME="Squashed Away" &&
607                 export GIT_AUTHOR_NAME &&
608                 >HEAD &&
609                 git add HEAD &&
610                 git commit -m "Add head" &&
611                 >BODY &&
612                 git add BODY &&
613                 git commit -m "Add body"
614         ) &&
615
616         set_fake_editor &&
617         FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
618         test "$(git show -s --pretty=format:%an)" = "Squashed Away"
619
620 '
621
622 test_expect_success 'do "noop" when there is nothing to cherry-pick' '
623
624         git checkout -b branch4 HEAD &&
625         GIT_EDITOR=: git commit --amend \
626                 --author="Somebody else <somebody@else.com>" &&
627         test $(git rev-parse branch3) != $(git rev-parse branch4) &&
628         set_fake_editor &&
629         git rebase -i branch3 &&
630         test $(git rev-parse branch3) = $(git rev-parse branch4)
631
632 '
633
634 test_expect_success 'submodule rebase setup' '
635         git checkout A &&
636         mkdir sub &&
637         (
638                 cd sub && git init && >elif &&
639                 git add elif && git commit -m "submodule initial"
640         ) &&
641         echo 1 >file1 &&
642         git add file1 sub &&
643         test_tick &&
644         git commit -m "One" &&
645         echo 2 >file1 &&
646         test_tick &&
647         git commit -a -m "Two" &&
648         (
649                 cd sub && echo 3 >elif &&
650                 git commit -a -m "submodule second"
651         ) &&
652         test_tick &&
653         set_fake_editor &&
654         git commit -a -m "Three changes submodule"
655 '
656
657 test_expect_success 'submodule rebase -i' '
658         set_fake_editor &&
659         FAKE_LINES="1 squash 2 3" git rebase -i A
660 '
661
662 test_expect_success 'submodule conflict setup' '
663         git tag submodule-base &&
664         git checkout HEAD^ &&
665         (
666                 cd sub && git checkout HEAD^ && echo 4 >elif &&
667                 git add elif && git commit -m "submodule conflict"
668         ) &&
669         git add sub &&
670         test_tick &&
671         git commit -m "Conflict in submodule" &&
672         git tag submodule-topic
673 '
674
675 test_expect_success 'rebase -i continue with only submodule staged' '
676         set_fake_editor &&
677         test_must_fail git rebase -i submodule-base &&
678         git add sub &&
679         git rebase --continue &&
680         test $(git rev-parse submodule-base) != $(git rev-parse HEAD)
681 '
682
683 test_expect_success 'rebase -i continue with unstaged submodule' '
684         git checkout submodule-topic &&
685         git reset --hard &&
686         set_fake_editor &&
687         test_must_fail git rebase -i submodule-base &&
688         git reset &&
689         git rebase --continue &&
690         test $(git rev-parse submodule-base) = $(git rev-parse HEAD)
691 '
692
693 test_expect_success 'avoid unnecessary reset' '
694         git checkout master &&
695         git reset --hard &&
696         test-chmtime =123456789 file3 &&
697         git update-index --refresh &&
698         HEAD=$(git rev-parse HEAD) &&
699         set_fake_editor &&
700         git rebase -i HEAD~4 &&
701         test $HEAD = $(git rev-parse HEAD) &&
702         MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
703         test 123456789 = $MTIME
704 '
705
706 test_expect_success 'reword' '
707         git checkout -b reword-branch master &&
708         set_fake_editor &&
709         FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A &&
710         git show HEAD | grep "E changed" &&
711         test $(git rev-parse master) != $(git rev-parse HEAD) &&
712         test $(git rev-parse master^) = $(git rev-parse HEAD^) &&
713         FAKE_LINES="1 2 reword 3 4" FAKE_COMMIT_MESSAGE="D changed" git rebase -i A &&
714         git show HEAD^ | grep "D changed" &&
715         FAKE_LINES="reword 1 2 3 4" FAKE_COMMIT_MESSAGE="B changed" git rebase -i A &&
716         git show HEAD~3 | grep "B changed" &&
717         FAKE_LINES="1 reword 2 3 4" FAKE_COMMIT_MESSAGE="C changed" git rebase -i A &&
718         git show HEAD~2 | grep "C changed"
719 '
720
721 test_expect_success 'rebase -i can copy notes' '
722         git config notes.rewrite.rebase true &&
723         git config notes.rewriteRef "refs/notes/*" &&
724         test_commit n1 &&
725         test_commit n2 &&
726         test_commit n3 &&
727         git notes add -m"a note" n3 &&
728         set_fake_editor &&
729         git rebase -i --onto n1 n2 &&
730         test "a note" = "$(git notes show HEAD)"
731 '
732
733 cat >expect <<EOF
734 an earlier note
735
736 a note
737 EOF
738
739 test_expect_success 'rebase -i can copy notes over a fixup' '
740         git reset --hard n3 &&
741         git notes add -m"an earlier note" n2 &&
742         set_fake_editor &&
743         GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
744         git notes show > output &&
745         test_cmp expect output
746 '
747
748 test_expect_success 'rebase while detaching HEAD' '
749         git symbolic-ref HEAD &&
750         grandparent=$(git rev-parse HEAD~2) &&
751         test_tick &&
752         set_fake_editor &&
753         FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
754         test $grandparent = $(git rev-parse HEAD~2) &&
755         test_must_fail git symbolic-ref HEAD
756 '
757
758 test_tick # Ensure that the rebased commits get a different timestamp.
759 test_expect_success 'always cherry-pick with --no-ff' '
760         git checkout no-ff-branch &&
761         git tag original-no-ff-branch &&
762         set_fake_editor &&
763         git rebase -i --no-ff A &&
764         touch empty &&
765         for p in 0 1 2
766         do
767                 test ! $(git rev-parse HEAD~$p) = $(git rev-parse original-no-ff-branch~$p) &&
768                 git diff HEAD~$p original-no-ff-branch~$p > out &&
769                 test_cmp empty out
770         done &&
771         test $(git rev-parse HEAD~3) = $(git rev-parse original-no-ff-branch~3) &&
772         git diff HEAD~3 original-no-ff-branch~3 > out &&
773         test_cmp empty out
774 '
775
776 test_expect_success 'set up commits with funny messages' '
777         git checkout -b funny A &&
778         echo >>file1 &&
779         test_tick &&
780         git commit -a -m "end with slash\\" &&
781         echo >>file1 &&
782         test_tick &&
783         git commit -a -m "something (\000) that looks like octal" &&
784         echo >>file1 &&
785         test_tick &&
786         git commit -a -m "something (\n) that looks like a newline" &&
787         echo >>file1 &&
788         test_tick &&
789         git commit -a -m "another commit"
790 '
791
792 test_expect_success 'rebase-i history with funny messages' '
793         git rev-list A..funny >expect &&
794         test_tick &&
795         set_fake_editor &&
796         FAKE_LINES="1 2 3 4" git rebase -i A &&
797         git rev-list A.. >actual &&
798         test_cmp expect actual
799 '
800
801
802 test_expect_success 'prepare for rebase -i --exec' '
803         git checkout master &&
804         git checkout -b execute &&
805         test_commit one_exec main.txt one_exec &&
806         test_commit two_exec main.txt two_exec &&
807         test_commit three_exec main.txt three_exec
808 '
809
810
811 test_expect_success 'running "git rebase -i --exec git show HEAD"' '
812         set_fake_editor &&
813         git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
814         (
815                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
816                 export FAKE_LINES &&
817                 git rebase -i HEAD~2 >expect
818         ) &&
819         sed -e "1,9d" expect >expected &&
820         test_cmp expected actual
821 '
822
823
824 test_expect_success 'running "git rebase --exec git show HEAD -i"' '
825         git reset --hard execute &&
826         set_fake_editor &&
827         git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
828         (
829                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
830                 export FAKE_LINES &&
831                 git rebase -i HEAD~2 >expect
832         ) &&
833         sed -e "1,9d" expect >expected &&
834         test_cmp expected actual
835 '
836
837
838 test_expect_success 'running "git rebase -ix git show HEAD"' '
839         git reset --hard execute &&
840         set_fake_editor &&
841         git rebase -ix "git show HEAD" HEAD~2 >actual &&
842         (
843                 FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
844                 export FAKE_LINES &&
845                 git rebase -i HEAD~2 >expect
846         ) &&
847         sed -e "1,9d" expect >expected &&
848         test_cmp expected actual
849 '
850
851
852 test_expect_success 'rebase -ix with several <CMD>' '
853         git reset --hard execute &&
854         set_fake_editor &&
855         git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
856         (
857                 FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
858                 export FAKE_LINES &&
859                 git rebase -i HEAD~2 >expect
860         ) &&
861         sed -e "1,9d" expect >expected &&
862         test_cmp expected actual
863 '
864
865
866 test_expect_success 'rebase -ix with several instances of --exec' '
867         git reset --hard execute &&
868         set_fake_editor &&
869         git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
870         (
871                 FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
872                                 exec_git_show_HEAD exec_pwd" &&
873                 export FAKE_LINES &&
874                 git rebase -i HEAD~2 >expect
875         ) &&
876         sed -e "1,11d" expect >expected &&
877         test_cmp expected actual
878 '
879
880
881 test_expect_success 'rebase -ix with --autosquash' '
882         git reset --hard execute &&
883         git checkout -b autosquash &&
884         echo second >second.txt &&
885         git add second.txt &&
886         git commit -m "fixup! two_exec" &&
887         echo bis >bis.txt &&
888         git add bis.txt &&
889         git commit -m "fixup! two_exec" &&
890         set_fake_editor &&
891         (
892                 git checkout -b autosquash_actual &&
893                 git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
894         ) &&
895         git checkout autosquash &&
896         (
897                 git checkout -b autosquash_expected &&
898                 FAKE_LINES="1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
899                 export FAKE_LINES &&
900                 git rebase -i HEAD~4 >expect
901         ) &&
902         sed -e "1,13d" expect >expected &&
903         test_cmp expected actual
904 '
905
906
907 test_expect_success 'rebase --exec without -i shows error message' '
908         git reset --hard execute &&
909         set_fake_editor &&
910         test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
911         echo "The --exec option must be used with the --interactive option" >expected &&
912         test_i18ncmp expected actual
913 '
914
915
916 test_expect_success 'rebase -i --exec without <CMD>' '
917         git reset --hard execute &&
918         set_fake_editor &&
919         test_must_fail git rebase -i --exec 2>tmp &&
920         sed -e "1d" tmp >actual &&
921         test_must_fail git rebase -h >expected &&
922         test_cmp expected actual &&
923         git checkout master
924 '
925
926 test_expect_success 'rebase -i --root re-order and drop commits' '
927         git checkout E &&
928         set_fake_editor &&
929         FAKE_LINES="3 1 2 5" git rebase -i --root &&
930         test E = $(git cat-file commit HEAD | sed -ne \$p) &&
931         test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
932         test A = $(git cat-file commit HEAD^^ | sed -ne \$p) &&
933         test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) &&
934         test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ )
935 '
936
937 test_expect_success 'rebase -i --root retain root commit author and message' '
938         git checkout A &&
939         echo B >file7 &&
940         git add file7 &&
941         GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
942         set_fake_editor &&
943         FAKE_LINES="2" git rebase -i --root &&
944         git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
945         git cat-file commit HEAD | grep -q "^different author$"
946 '
947
948 test_expect_success 'rebase -i --root temporary sentinel commit' '
949         git checkout B &&
950         (
951                 set_fake_editor &&
952                 FAKE_LINES="2" &&
953                 export FAKE_LINES &&
954                 test_must_fail git rebase -i --root
955         ) &&
956         git cat-file commit HEAD | grep "^tree 4b825dc642cb" &&
957         git rebase --abort
958 '
959
960 test_expect_success 'rebase -i --root fixup root commit' '
961         git checkout B &&
962         set_fake_editor &&
963         FAKE_LINES="1 fixup 2" git rebase -i --root &&
964         test A = $(git cat-file commit HEAD | sed -ne \$p) &&
965         test B = $(git show HEAD:file1) &&
966         test 0 = $(git cat-file commit HEAD | grep -c ^parent\ )
967 '
968
969 test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
970         git reset --hard &&
971         git checkout conflict-branch &&
972         set_fake_editor &&
973         test_must_fail git rebase --onto HEAD~2 HEAD~ &&
974         test_must_fail git rebase --edit-todo &&
975         git rebase --abort
976 '
977
978 test_expect_success 'rebase --edit-todo can be used to modify todo' '
979         git reset --hard &&
980         git checkout no-conflict-branch^0 &&
981         set_fake_editor &&
982         FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
983         FAKE_LINES="2 1" git rebase --edit-todo &&
984         git rebase --continue
985         test M = $(git cat-file commit HEAD^ | sed -ne \$p) &&
986         test L = $(git cat-file commit HEAD | sed -ne \$p)
987 '
988
989 test_expect_success 'rebase -i produces readable reflog' '
990         git reset --hard &&
991         git branch -f branch-reflog-test H &&
992         set_fake_editor &&
993         git rebase -i --onto I F branch-reflog-test &&
994         cat >expect <<-\EOF &&
995         rebase -i (start): checkout I
996         rebase -i (pick): G
997         rebase -i (pick): H
998         rebase -i (finish): returning to refs/heads/branch-reflog-test
999         EOF
1000         tail -n 4 .git/logs/HEAD |
1001         sed -e "s/.*    //" >actual &&
1002         test_cmp expect actual
1003 '
1004
1005 test_expect_success 'rebase -i respects core.commentchar' '
1006         git reset --hard &&
1007         git checkout E^0 &&
1008         test_config core.commentchar "\\" &&
1009         write_script remove-all-but-first.sh <<-\EOF &&
1010         sed -e "2,\$s/^/\\\\/" "$1" >"$1.tmp" &&
1011         mv "$1.tmp" "$1"
1012         EOF
1013         test_set_editor "$(pwd)/remove-all-but-first.sh" &&
1014         git rebase -i B &&
1015         test B = $(git cat-file commit HEAD^ | sed -ne \$p)
1016 '
1017
1018 test_expect_success 'rebase -i, with <onto> and <upstream> specified as :/quuxery' '
1019         test_when_finished "git branch -D torebase" &&
1020         git checkout -b torebase branch1 &&
1021         upstream=$(git rev-parse ":/J") &&
1022         onto=$(git rev-parse ":/A") &&
1023         git rebase --onto $onto $upstream &&
1024         git reset --hard branch1 &&
1025         git rebase --onto ":/A" ":/J" &&
1026         git checkout branch1
1027 '
1028
1029 test_expect_success 'rebase -i with --strategy and -X' '
1030         git checkout -b conflict-merge-use-theirs conflict-branch &&
1031         git reset --hard HEAD^ &&
1032         echo five >conflict &&
1033         echo Z >file1 &&
1034         git commit -a -m "one file conflict" &&
1035         EDITOR=true git rebase -i --strategy=recursive -Xours conflict-branch &&
1036         test $(git show conflict-branch:conflict) = $(cat conflict) &&
1037         test $(cat file1) = Z
1038 '
1039
1040 test_expect_success 'rebase -i error on commits with \ in message' '
1041         current_head=$(git rev-parse HEAD)
1042         test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&
1043         test_commit TO-REMOVE will-conflict old-content &&
1044         test_commit "\temp" will-conflict new-content dummy &&
1045         (
1046         EDITOR=true &&
1047         export EDITOR &&
1048         test_must_fail git rebase -i HEAD^ --onto HEAD^^ 2>error
1049         ) &&
1050         test_expect_code 1 grep  "      emp" error
1051 '
1052
1053 test_expect_success 'short SHA-1 setup' '
1054         test_when_finished "git checkout master" &&
1055         git checkout --orphan collide &&
1056         git rm -rf . &&
1057         (
1058         unset test_tick &&
1059         test_commit collide1 collide &&
1060         test_commit --notick collide2 collide &&
1061         test_commit --notick collide3 collide
1062         )
1063 '
1064
1065 test_expect_success 'short SHA-1 collide' '
1066         test_when_finished "reset_rebase && git checkout master" &&
1067         git checkout collide &&
1068         (
1069         unset test_tick &&
1070         test_tick &&
1071         set_fake_editor &&
1072         FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
1073         FAKE_LINES="reword 1 2" git rebase -i HEAD~2
1074         )
1075 '
1076
1077 test_done