]> git.ipfire.org Git - thirdparty/git.git/blame - t/t3430-rebase-merges.sh
The sixth batch
[thirdparty/git.git] / t / t3430-rebase-merges.sh
CommitLineData
8f6aed71
JS
1#!/bin/sh
2#
3# Copyright (c) 2018 Johannes E. Schindelin
4#
5
6test_description='git rebase -i --rebase-merges
7
8This test runs git rebase "interactively", retaining the branch structure by
9recreating merge commits.
10
11Initial setup:
12
13 -- B -- (first)
14 / \
15 A - C - D - E - H (master)
d54e1898
PW
16 \ \ /
17 \ F - G (second)
18 \
19 Conflicting-G
8f6aed71
JS
20'
21. ./test-lib.sh
22. "$TEST_DIRECTORY"/lib-rebase.sh
989eea95 23. "$TEST_DIRECTORY"/lib-log-graph.sh
8f6aed71
JS
24
25test_cmp_graph () {
26 cat >expect &&
989eea95 27 lib_test_cmp_graph --boundary --format=%s "$@"
8f6aed71
JS
28}
29
30test_expect_success 'setup' '
31 write_script replace-editor.sh <<-\EOF &&
32 mv "$1" "$(git rev-parse --git-path ORIGINAL-TODO)"
33 cp script-from-scratch "$1"
34 EOF
35
36 test_commit A &&
37 git checkout -b first &&
38 test_commit B &&
9a6738c0 39 b=$(git rev-parse --short HEAD) &&
8f6aed71
JS
40 git checkout master &&
41 test_commit C &&
9a6738c0 42 c=$(git rev-parse --short HEAD) &&
8f6aed71 43 test_commit D &&
9a6738c0 44 d=$(git rev-parse --short HEAD) &&
8f6aed71
JS
45 git merge --no-commit B &&
46 test_tick &&
47 git commit -m E &&
48 git tag -m E E &&
9a6738c0 49 e=$(git rev-parse --short HEAD) &&
8f6aed71
JS
50 git checkout -b second C &&
51 test_commit F &&
9a6738c0 52 f=$(git rev-parse --short HEAD) &&
8f6aed71 53 test_commit G &&
9a6738c0 54 g=$(git rev-parse --short HEAD) &&
8f6aed71
JS
55 git checkout master &&
56 git merge --no-commit G &&
57 test_tick &&
58 git commit -m H &&
9a6738c0 59 h=$(git rev-parse --short HEAD) &&
d54e1898
PW
60 git tag -m H H &&
61 git checkout A &&
62 test_commit conflicting-G G.t
8f6aed71
JS
63'
64
65test_expect_success 'create completely different structure' '
66 cat >script-from-scratch <<-\EOF &&
67 label onto
68
69 # onebranch
70 pick G
71 pick D
72 label onebranch
73
74 # second
75 reset onto
76 pick B
77 label second
78
79 reset onto
80 merge -C H second
81 merge onebranch # Merge the topic branch '\''onebranch'\''
82 EOF
83 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
84 test_tick &&
d54e1898 85 git rebase -i -r A master &&
8f6aed71
JS
86 test_cmp_graph <<-\EOF
87 * Merge the topic branch '\''onebranch'\''
88 |\
89 | * D
90 | * G
91 * | H
92 |\ \
93 | |/
94 |/|
95 | * B
96 |/
97 * A
98 EOF
99'
100
101test_expect_success 'generate correct todo list' '
9a6738c0 102 cat >expect <<-EOF &&
8f6aed71
JS
103 label onto
104
105 reset onto
9a6738c0 106 pick $b B
8f6aed71
JS
107 label E
108
109 reset onto
9a6738c0 110 pick $c C
8f6aed71 111 label branch-point
9a6738c0 112 pick $f F
113 pick $g G
8f6aed71
JS
114 label H
115
116 reset branch-point # C
9a6738c0 117 pick $d D
118 merge -C $e E # E
119 merge -C $h H # H
8f6aed71
JS
120
121 EOF
122
123 grep -v "^#" <.git/ORIGINAL-TODO >output &&
124 test_cmp expect output
125'
126
127test_expect_success '`reset` refuses to overwrite untracked files' '
128 git checkout -b refuse-to-reset &&
129 test_commit dont-overwrite-untracked &&
130 git checkout @{-1} &&
131 : >dont-overwrite-untracked.t &&
132 echo "reset refs/tags/dont-overwrite-untracked" >script-from-scratch &&
133 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
891d4a03 134 test_must_fail git rebase -ir HEAD &&
8f6aed71
JS
135 git rebase --abort
136'
137
bc9238bb 138test_expect_success 'failed `merge -C` writes patch (may be rescheduled, too)' '
8f6aed71
JS
139 test_when_finished "test_might_fail git rebase --abort" &&
140 git checkout -b conflicting-merge A &&
141
142 : fail because of conflicting untracked file &&
143 >G.t &&
144 echo "merge -C H G" >script-from-scratch &&
145 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
146 test_tick &&
147 test_must_fail git rebase -ir HEAD &&
148 grep "^merge -C .* G$" .git/rebase-merge/done &&
149 grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
150 test_path_is_file .git/rebase-merge/patch &&
151
152 : fail because of merge conflict &&
153 rm G.t .git/rebase-merge/patch &&
d54e1898 154 git reset --hard conflicting-G &&
8f6aed71
JS
155 test_must_fail git rebase --continue &&
156 ! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
157 test_path_is_file .git/rebase-merge/patch
158'
159
bc9238bb
PW
160test_expect_success 'failed `merge <branch>` does not crash' '
161 test_when_finished "test_might_fail git rebase --abort" &&
162 git checkout conflicting-G &&
163
164 echo "merge G" >script-from-scratch &&
165 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
166 test_tick &&
167 test_must_fail git rebase -ir HEAD &&
168 ! grep "^merge G$" .git/rebase-merge/git-rebase-todo &&
169 grep "^Merge branch ${SQ}G${SQ}$" .git/rebase-merge/message
170'
171
6df8df08
PW
172test_expect_success 'fast-forward merge -c still rewords' '
173 git checkout -b fast-forward-merge-c H &&
174 (
175 set_fake_editor &&
176 FAKE_COMMIT_MESSAGE=edited \
177 GIT_SEQUENCE_EDITOR="echo merge -c H G >" \
178 git rebase -ir @^
179 ) &&
180 echo edited >expected &&
181 git log --pretty=format:%B -1 >actual &&
182 test_cmp expected actual
183'
184
8f6aed71
JS
185test_expect_success 'with a branch tip that was cherry-picked already' '
186 git checkout -b already-upstream master &&
187 base="$(git rev-parse --verify HEAD)" &&
188
189 test_commit A1 &&
190 test_commit A2 &&
191 git reset --hard $base &&
192 test_commit B1 &&
193 test_tick &&
194 git merge -m "Merge branch A" A2 &&
195
196 git checkout -b upstream-with-a2 $base &&
197 test_tick &&
198 git cherry-pick A2 &&
199
200 git checkout already-upstream &&
201 test_tick &&
202 git rebase -i -r upstream-with-a2 &&
203 test_cmp_graph upstream-with-a2.. <<-\EOF
204 * Merge branch A
205 |\
206 | * A1
207 * | B1
208 |/
209 o A2
210 EOF
211'
212
7543f6f4
JS
213test_expect_success 'do not rebase cousins unless asked for' '
214 git checkout -b cousins master &&
215 before="$(git rev-parse --verify HEAD)" &&
216 test_tick &&
217 git rebase -r HEAD^ &&
218 test_cmp_rev HEAD $before &&
219 test_tick &&
220 git rebase --rebase-merges=rebase-cousins HEAD^ &&
221 test_cmp_graph HEAD^.. <<-\EOF
222 * Merge the topic branch '\''onebranch'\''
223 |\
224 | * D
225 | * G
226 |/
227 o H
228 EOF
229'
230
a9be29c9
JS
231test_expect_success 'refs/rewritten/* is worktree-local' '
232 git worktree add wt &&
233 cat >wt/script-from-scratch <<-\EOF &&
234 label xyz
235 exec GIT_DIR=../.git git rev-parse --verify refs/rewritten/xyz >a || :
236 exec git rev-parse --verify refs/rewritten/xyz >b
237 EOF
238
239 test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
240 git -C wt rebase -i HEAD &&
241 test_must_be_empty wt/a &&
242 test_cmp_rev HEAD "$(cat wt/b)"
243'
244
d559f502
PW
245test_expect_success '--abort cleans up refs/rewritten' '
246 git checkout -b abort-cleans-refs-rewritten H &&
247 GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
248 git rev-parse --verify refs/rewritten/onto &&
249 git rebase --abort &&
250 test_must_fail git rev-parse --verify refs/rewritten/onto
251'
252
253test_expect_success '--quit cleans up refs/rewritten' '
254 git checkout -b quit-cleans-refs-rewritten H &&
255 GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ &&
256 git rev-parse --verify refs/rewritten/onto &&
257 git rebase --quit &&
258 test_must_fail git rev-parse --verify refs/rewritten/onto
259'
260
537e7d61 261test_expect_success 'post-rewrite hook and fixups work for merges' '
d559f502 262 git checkout -b post-rewrite H &&
537e7d61
JS
263 test_commit same1 &&
264 git reset --hard HEAD^ &&
265 test_commit same2 &&
266 git merge -m "to fix up" same1 &&
267 echo same old same old >same2.t &&
268 test_tick &&
269 git commit --fixup HEAD same2.t &&
270 fixup="$(git rev-parse HEAD)" &&
271
272 mkdir -p .git/hooks &&
273 test_when_finished "rm .git/hooks/post-rewrite" &&
274 echo "cat >actual" | write_script .git/hooks/post-rewrite &&
275
276 test_tick &&
277 git rebase -i --autosquash -r HEAD^^^ &&
278 printf "%s %s\n%s %s\n%s %s\n%s %s\n" >expect $(git rev-parse \
279 $fixup^^2 HEAD^2 \
280 $fixup^^ HEAD^ \
281 $fixup^ HEAD \
282 $fixup HEAD) &&
283 test_cmp expect actual
284'
285
7ccdf65b
JS
286test_expect_success 'refuse to merge ancestors of HEAD' '
287 echo "merge HEAD^" >script-from-scratch &&
288 test_config -C wt sequence.editor \""$PWD"/replace-editor.sh\" &&
289 before="$(git rev-parse HEAD)" &&
290 git rebase -i HEAD &&
291 test_cmp_rev HEAD $before
292'
293
ebddf393
JS
294test_expect_success 'root commits' '
295 git checkout --orphan unrelated &&
296 (GIT_AUTHOR_NAME="Parsnip" GIT_AUTHOR_EMAIL="root@example.com" \
297 test_commit second-root) &&
298 test_commit third-root &&
299 cat >script-from-scratch <<-\EOF &&
300 pick third-root
301 label first-branch
302 reset [new root]
303 pick second-root
304 merge first-branch # Merge the 3rd root
305 EOF
306 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
307 test_tick &&
f927ae6c 308 git rebase -i --force-rebase --root -r &&
ebddf393
JS
309 test "Parsnip" = "$(git show -s --format=%an HEAD^)" &&
310 test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) &&
311 test $(git rev-parse second-root:second-root.t) = \
312 $(git rev-parse HEAD^:second-root.t) &&
313 test_cmp_graph HEAD <<-\EOF &&
314 * Merge the 3rd root
315 |\
316 | * third-root
317 * second-root
318 EOF
319
320 : fast forward if possible &&
321 before="$(git rev-parse --verify HEAD)" &&
322 test_might_fail git config --unset sequence.editor &&
323 test_tick &&
324 git rebase -i --root -r &&
325 test_cmp_rev HEAD $before
326'
327
9c85a1c2
JS
328test_expect_success 'a "merge" into a root commit is a fast-forward' '
329 head=$(git rev-parse HEAD) &&
330 cat >script-from-scratch <<-EOF &&
331 reset [new root]
332 merge $head
333 EOF
334 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
335 test_tick &&
336 git rebase -i -r HEAD^ &&
337 test_cmp_rev HEAD $head
338'
339
8fa6eea0
JS
340test_expect_success 'A root commit can be a cousin, treat it that way' '
341 git checkout --orphan khnum &&
342 test_commit yama &&
343 git checkout -b asherah master &&
344 test_commit shamkat &&
345 git merge --allow-unrelated-histories khnum &&
346 test_tick &&
347 git rebase -f -r HEAD^ &&
2c9e125b 348 test_cmp_rev ! HEAD^2 khnum &&
8fa6eea0
JS
349 test_cmp_graph HEAD^.. <<-\EOF &&
350 * Merge branch '\''khnum'\'' into asherah
351 |\
352 | * yama
353 o shamkat
354 EOF
355 test_tick &&
356 git rebase --rebase-merges=rebase-cousins HEAD^ &&
357 test_cmp_graph HEAD^.. <<-\EOF
358 * Merge branch '\''khnum'\'' into asherah
359 |\
360 | * yama
361 |/
362 o shamkat
363 EOF
364'
9c85a1c2 365
5971b083 366test_expect_success 'labels that are object IDs are rewritten' '
367 git checkout -b third B &&
5971b083 368 test_commit I &&
369 third=$(git rev-parse HEAD) &&
370 git checkout -b labels master &&
371 git merge --no-commit third &&
372 test_tick &&
373 git commit -m "Merge commit '\''$third'\'' into labels" &&
0c5a779c 374 echo noop >script-from-scratch &&
5971b083 375 test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
376 test_tick &&
377 git rebase -i -r A &&
0c5a779c 378 grep "^label $third-" .git/ORIGINAL-TODO &&
5971b083 379 ! grep "^label $third$" .git/ORIGINAL-TODO
380'
381
2b6ad0f4
JS
382test_expect_success 'octopus merges' '
383 git checkout -b three &&
384 test_commit before-octopus &&
385 test_commit three &&
386 git checkout -b two HEAD^ &&
387 test_commit two &&
388 git checkout -b one HEAD^ &&
389 test_commit one &&
390 test_tick &&
391 (GIT_AUTHOR_NAME="Hank" GIT_AUTHOR_EMAIL="hank@sea.world" \
392 git merge -m "Tüntenfüsch" two three) &&
393
394 : fast forward if possible &&
395 before="$(git rev-parse --verify HEAD)" &&
396 test_tick &&
397 git rebase -i -r HEAD^^ &&
398 test_cmp_rev HEAD $before &&
399
400 test_tick &&
f927ae6c 401 git rebase -i --force-rebase -r HEAD^^ &&
2b6ad0f4
JS
402 test "Hank" = "$(git show -s --format=%an HEAD)" &&
403 test "$before" != $(git rev-parse HEAD) &&
404 test_cmp_graph HEAD^^.. <<-\EOF
405 *-. Tüntenfüsch
406 |\ \
407 | | * three
408 | * | two
409 | |/
479db18b 410 * / one
2b6ad0f4
JS
411 |/
412 o before-octopus
413 EOF
414'
415
1ace63bc 416test_expect_success 'with --autosquash and --exec' '
f0880f77
JS
417 git checkout -b with-exec H &&
418 echo Booh >B.t &&
419 test_tick &&
420 git commit --fixup B B.t &&
421 write_script show.sh <<-\EOF &&
422 subject="$(git show -s --format=%s HEAD)"
bafa2d74 423 content="$(git diff HEAD^ HEAD | tail -n 1)"
f0880f77
JS
424 echo "$subject: $content"
425 EOF
426 test_tick &&
427 git rebase -ir --autosquash --exec ./show.sh A >actual &&
428 grep "B: +Booh" actual &&
429 grep "E: +Booh" actual &&
430 grep "G: +G" actual
431'
432
85f8d9da 433test_expect_success '--continue after resolving conflicts after a merge' '
f08110dd
JS
434 git checkout -b already-has-g E &&
435 git cherry-pick E..G &&
436 test_commit H2 &&
437
438 git checkout -b conflicts-in-merge H &&
439 test_commit H2 H2.t conflicts H2-conflict &&
440 test_must_fail git rebase -r already-has-g &&
441 grep conflicts H2.t &&
442 echo resolved >H2.t &&
443 git add -u &&
444 git rebase --continue &&
445 test_must_fail git rev-parse --verify HEAD^2 &&
446 test_path_is_missing .git/MERGE_HEAD
447'
448
e145d993
JS
449test_expect_success '--rebase-merges with strategies' '
450 git checkout -b with-a-strategy F &&
451 test_tick &&
452 git merge -m "Merge conflicting-G" conflicting-G &&
453
454 : first, test with a merge strategy option &&
455 git rebase -ir -Xtheirs G &&
456 echo conflicting-G >expect &&
457 test_cmp expect G.t &&
458
459 : now, try with a merge strategy other than recursive &&
460 git reset --hard @{1} &&
461 write_script git-merge-override <<-\EOF &&
462 echo overridden$1 >>G.t
463 git add G.t
464 EOF
465 PATH="$PWD:$PATH" git rebase -ir -s override -Xxopt G &&
466 test_write_lines G overridden--xopt >expect &&
467 test_cmp expect G.t
468'
469
cd552227
MR
470test_expect_success '--rebase-merges with commit that can generate bad characters for filename' '
471 git checkout -b colon-in-label E &&
472 git merge -m "colon: this should work" G &&
473 git rebase --rebase-merges --force-rebase E
474'
475
e02058a7
ĐTCD
476test_expect_success '--rebase-merges with message matched with onto label' '
477 git checkout -b onto-label E &&
478 git merge -m onto G &&
479 git rebase --rebase-merges --force-rebase E &&
480 test_cmp_graph <<-\EOF
481 * onto
482 |\
483 | * G
484 | * F
485 * | E
486 |\ \
487 | * | B
488 * | | D
489 | |/
490 |/|
491 * | C
492 |/
493 * A
494 EOF
495'
496
8f6aed71 497test_done