Raw
1 #!/bin/sh
2
3 test_description='tests for git-history squash subcommand'
4
5 . ./test-lib.sh
6
7 stage_file () {
8 printf "%s\n" "$1" >file &&
9 git add file
10 }
11
12 commit_with_message () {
13 printf "%b" "$1" >msg &&
14 git commit --allow-empty -qF msg
15 }
16
17 check_commit_count () {
18 git rev-list --count "$1" >actual &&
19 echo "$2" >expect &&
20 test_cmp expect actual
21 }
22
23 check_log_subjects () {
24 git log --format="%s" "$1" >actual &&
25 cat >expect &&
26 test_cmp expect actual
27 }
28
29 check_log_messages () {
30 git log --format="%B" "$1" >actual &&
31 cat >expect &&
32 test_cmp expect actual
33 }
34
35 test_expect_success 'setup linear history touching two files' '
36 test_commit base file a &&
37 git tag start &&
38 GIT_AUTHOR_NAME=Squasher GIT_AUTHOR_EMAIL=squash@example.com \
39 test_commit --no-tag one other x &&
40 test_commit --no-tag two file c &&
41 test_commit three file d
42 '
43
44 test_expect_success 'errors on missing range argument' '
45 test_must_fail git history squash 2>err &&
46 test_grep "expects a revision range" err
47 '
48
49 test_expect_success 'errors on an empty range' '
50 test_must_fail git history squash HEAD..HEAD 2>err &&
51 test_grep "the revision range is empty" err
52 '
53
54 test_expect_success 'errors on a single revision that is not a range' '
55 test_must_fail git history squash HEAD 2>err &&
56 test_grep "not a .*range" err &&
57 test_must_fail git history squash HEAD~1 2>err &&
58 test_grep "not a .*range" err
59 '
60
61 test_expect_success 'errors on a range holding a single commit' '
62 git reset --hard three &&
63 head_before=$(git rev-parse HEAD) &&
64
65 test_must_fail git history squash "HEAD^!" 2>err &&
66 test_grep "single commit; nothing to squash" err &&
67 test_cmp_rev "$head_before" HEAD
68 '
69
70 test_expect_success 'accepts multiple revision arguments with an exclusion' '
71 git reset --hard three &&
72 git branch -f keep HEAD~2 &&
73 tip_tree=$(git rev-parse HEAD^{tree}) &&
74
75 git history squash --no-edit start..HEAD ^keep &&
76
77 git reflog -1 --format=%gs >actual &&
78 echo "squash: updating start..HEAD ^keep" >expect &&
79 test_cmp expect actual &&
80
81 check_log_subjects start..HEAD <<-\EOF &&
82 two
83 one
84 EOF
85 test_cmp_rev keep HEAD~1 &&
86 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
87
88 git branch -D keep
89 '
90
91 test_expect_success 'refuses a range with more than one tip' '
92 git reset --hard start &&
93 main=$(git symbolic-ref --short HEAD) &&
94 test_commit --no-tag main-one file b &&
95 test_commit --no-tag main-two file c &&
96 git checkout -b other-tip start &&
97 test_commit --no-tag other-tip other d &&
98 git checkout "$main" &&
99 main_before=$(git rev-parse HEAD) &&
100 other_before=$(git rev-parse other-tip) &&
101
102 test_must_fail git history squash ^start HEAD other-tip 2>err &&
103 test_grep "more than one tip" err &&
104 test_cmp_rev "$main_before" HEAD &&
105 test_cmp_rev "$other_before" other-tip &&
106
107 git branch -D other-tip
108 '
109
110 test_expect_success 'refuses a range that reaches a root commit' '
111 git reset --hard three &&
112 root=$(printf "unrelated root\n" |
113 git commit-tree "$(git rev-parse HEAD^{tree})") &&
114 head_before=$(git rev-parse HEAD) &&
115
116 test_must_fail git history squash --ancestry-path="$root" \
117 ^start HEAD "$root" 2>err &&
118 test_grep "reaches a root commit" err &&
119 test_cmp_rev "$head_before" HEAD
120 '
121
122 test_expect_success 'squashes a branch the current branch is not on' '
123 git reset --hard three &&
124 main=$(git symbolic-ref --short HEAD) &&
125 head_before=$(git rev-parse HEAD) &&
126 git checkout -b off-history start &&
127 test_commit --no-tag off-one off a &&
128 test_commit --no-tag off-two off b &&
129 git checkout "$main" &&
130
131 git history squash --no-edit start..off-history &&
132
133 check_commit_count start..off-history 1 &&
134 test_cmp_rev "$head_before" HEAD &&
135
136 git branch -D off-history
137 '
138
139 test_expect_success 'squashes a range preserving its tree and oldest authorship' '
140 git reset --hard three &&
141 head_before=$(git rev-parse HEAD) &&
142 tip_tree=$(git rev-parse HEAD^{tree}) &&
143
144 git history squash --dry-run start.. >out &&
145 predicted=$(awk "/^update refs\/heads\// {print \$3}" out) &&
146 test_cmp_rev "$head_before" HEAD &&
147
148 git history squash start.. &&
149
150 test "$predicted" = "$(git rev-parse HEAD)" &&
151 check_commit_count start..HEAD 1 &&
152 test_cmp_rev start HEAD^ &&
153 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
154 check_log_subjects -1 <<-\EOF &&
155 one
156 EOF
157 git log -1 --format="%an <%ae>" >actual &&
158 echo "Squasher <squash@example.com>" >expect &&
159 test_cmp expect actual &&
160 git reflog >reflog &&
161 test_grep "squash: updating" reflog
162 '
163
164 test_expect_success 'sanitizes rev-list walk options, before and after --' '
165 git reset --hard three &&
166 tip_tree=$(git rev-parse HEAD^{tree}) &&
167
168 git history squash --no-edit --date-order start.. 2>err &&
169 test_grep "ignoring rev-list options" err &&
170 test_cmp_rev start HEAD^ &&
171 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
172
173 git reset --hard three &&
174 git history squash --no-edit -- --reverse start.. 2>err &&
175 test_grep "ignoring rev-list options" err &&
176 test_cmp_rev start HEAD^ &&
177 test "$tip_tree" = "$(git rev-parse HEAD^{tree})"
178 '
179
180 test_expect_success 'squashes an interior range and replays descendants verbatim' '
181 git reset --hard three &&
182 final_tree=$(git rev-parse HEAD^{tree}) &&
183
184 git history squash --no-edit start..@~1 &&
185
186 check_log_subjects start..HEAD <<-\EOF &&
187 three
188 one
189 EOF
190
191 test_cmp_rev start HEAD~2 &&
192 test "$final_tree" = "$(git rev-parse HEAD^{tree})"
193 '
194
195 test_expect_success 'squashes when the base is the root commit' '
196 git reset --hard three &&
197 root=$(git rev-list --max-parents=0 HEAD) &&
198 tip_tree=$(git rev-parse HEAD^{tree}) &&
199
200 git history squash --no-edit "$root.." &&
201
202 check_commit_count "$root..HEAD" 1 &&
203 test_cmp_rev "$root" HEAD^ &&
204 test "$tip_tree" = "$(git rev-parse HEAD^{tree})"
205 '
206
207
208 test_expect_success 'folds fixups whose target is in the range' '
209 git reset --hard start &&
210 test_commit --no-tag target file b &&
211 git commit --allow-empty -m "fixup! target" &&
212 git commit --allow-empty -m "fixup! target" &&
213 test_commit --no-tag later file c &&
214
215 git history squash --no-edit start.. &&
216
217 check_commit_count start..HEAD 1 &&
218 check_log_subjects -1 <<-\EOF
219 target
220 EOF
221 '
222
223 test_expect_success 'refuses a below-range fixup! after an in-range commit' '
224 git reset --hard start &&
225 test_commit --no-tag inside file b &&
226 test_commit --no-tag "fixup! outside" file c &&
227 head_before=$(git rev-parse HEAD) &&
228
229 test_must_fail git history squash start.. 2>err &&
230 test_grep "target is not in the range" err &&
231 test_cmp_rev "$head_before" HEAD
232 '
233
234 test_expect_success 'combines a run of fixups for one commit below the range' '
235 git reset --hard start &&
236 stage_file b && git commit -m "fixup! base" &&
237 stage_file c && git commit -m "fixup! base" &&
238
239 git history squash --no-edit start.. &&
240
241 check_commit_count start..HEAD 1 &&
242 check_log_subjects -1 <<-\EOF
243 fixup! base
244 EOF
245 '
246
247 test_expect_success 'combining below-range markers offers every message' '
248 git reset --hard start &&
249 stage_file b && git commit -m "fixup! base" &&
250 stage_file c &&
251 commit_with_message "amend! base\n\namended body\n" &&
252
253 git history squash start.. &&
254
255 check_commit_count start..HEAD 1 &&
256 check_log_messages -1 <<-\EOF
257 fixup! base
258
259 amend! base
260
261 amended body
262
263 EOF
264 '
265
266 test_expect_success 'refuses fixups for two different commits below the range' '
267 git reset --hard start &&
268 stage_file b && git commit -m "fixup! aaa" &&
269 stage_file c && git commit -m "fixup! bbb" &&
270 head_before=$(git rev-parse HEAD) &&
271
272 test_must_fail git history squash start.. 2>err &&
273 test_grep "target is not in the range" err &&
274 test_cmp_rev "$head_before" HEAD
275 '
276
277 test_expect_success 'does not discard squash! or amend! message bodies' '
278 git reset --hard start &&
279 test_commit --no-tag marker-oldest file b &&
280 git commit --allow-empty -m "squash! marker-oldest" &&
281 commit_with_message "amend! marker-oldest\n\nearlier message\n" &&
282 commit_with_message \
283 "amend! marker-oldest\n\namended subject\n\namended body\n" &&
284 test_commit --no-tag marker-later file c &&
285 commit_with_message "amend! marker-later\n\nwrong message\n" &&
286
287 git history squash start.. &&
288
289 check_commit_count start..HEAD 1 &&
290 check_log_messages -1 <<-\EOF
291 marker-oldest
292
293 earlier message
294
295 amended subject
296
297 amended body
298
299 wrong message
300
301 EOF
302 '
303
304 test_expect_success '--no-edit keeps the selected message without an editor' '
305 git reset --hard start &&
306 test_commit --no-tag no-edit-target file b &&
307 git commit --allow-empty -m "squash! no-edit-target" &&
308 commit_with_message "amend! no-edit-target\n\namended subject\n\namended body\n" &&
309
310 write_script editor <<-\EOF &&
311 exit 1
312 EOF
313 test_set_editor "$(pwd)/editor" &&
314 git history squash --no-edit start.. &&
315
316 check_log_messages -1 <<-\EOF &&
317 amended subject
318
319 amended body
320
321 EOF
322 test_set_editor :
323 '
324
325 test_expect_success 'edits every message and aborts on an empty result' '
326 git reset --hard start &&
327 stage_file b &&
328 git commit -m "re-one subject" -m "re-one body line" &&
329 test_commit --no-tag re-two file c &&
330 test_commit re-three file d &&
331 head_before=$(git rev-parse HEAD) &&
332
333 write_script empty-editor <<-\EOF &&
334 >"$1"
335 EOF
336 test_set_editor "$(pwd)/empty-editor" &&
337 test_must_fail git history squash start.. 2>err &&
338 test_grep "Aborting commit due to empty commit message" err &&
339 test_cmp_rev "$head_before" HEAD &&
340
341 write_script editor <<-\EOF &&
342 cat "$1" >edited &&
343 echo combined >"$1"
344 EOF
345 test_set_editor "$(pwd)/editor" &&
346 git history squash start.. &&
347
348 cat >expect <<-EOF &&
349 # This is a combination of 3 commits.
350 # This is the 1st commit message:
351
352 re-one subject
353
354 re-one body line
355
356 # This is the commit message #2:
357
358 re-two
359
360 # This is the commit message #3:
361
362 re-three
363
364 # Please enter the commit message for the squash changes. Lines starting
365 # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
366 # Changes to be committed:
367 # modified: file
368 #
369 EOF
370 test_cmp expect edited &&
371 check_log_subjects -1 <<-\EOF
372 combined
373 EOF
374 '
375
376 test_expect_success 'handles fixup!, squash! and amend! messages like rebase' '
377 git reset --hard start &&
378 test_commit --no-tag mark-base file b &&
379 stage_file c &&
380 commit_with_message "fixup! mark-base\n\nfixup body\n" &&
381 stage_file d &&
382 commit_with_message "squash! mark-base\n\nsquash remark\n" &&
383 stage_file e &&
384 commit_with_message "amend! mark-base\n\namended message\n" &&
385
386 write_script editor <<-\EOF &&
387 cat "$1" >edited
388 EOF
389 test_set_editor "$(pwd)/editor" &&
390 git history squash start.. &&
391
392 cat >expect <<-EOF &&
393 # This is a combination of 4 commits.
394 # This is the 1st commit message:
395
396 mark-base
397
398 # The commit message #2 will be skipped:
399
400 # fixup! mark-base
401 #
402 # fixup body
403
404 # This is the commit message #3:
405
406 # squash! mark-base
407
408 squash remark
409
410 # This is the commit message #4:
411
412 # amend! mark-base
413
414 amended message
415
416 # Please enter the commit message for the squash changes. Lines starting
417 # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
418 # Changes to be committed:
419 # modified: file
420 #
421 EOF
422 test_cmp expect edited &&
423 check_log_messages -1 <<-\EOF
424 mark-base
425
426 squash remark
427
428 amended message
429
430 EOF
431 '
432
433 test_expect_success 'groups fixups under their targets in the editor' '
434 git reset --hard start &&
435 test_commit --no-tag alpha file a1 &&
436 test_commit --no-tag beta file b1 &&
437 stage_file a2 &&
438 commit_with_message "fixup! alpha\n" &&
439 stage_file b2 &&
440 commit_with_message "fixup! beta\n" &&
441
442 write_script editor <<-\EOF &&
443 cat "$1" >edited
444 EOF
445 test_set_editor "$(pwd)/editor" &&
446 git history squash start.. &&
447
448 cat >expect <<-EOF &&
449 # This is a combination of 4 commits.
450 # This is the 1st commit message:
451
452 alpha
453
454 # The commit message #2 will be skipped:
455
456 # fixup! alpha
457
458 # This is the commit message #3:
459
460 beta
461
462 # The commit message #4 will be skipped:
463
464 # fixup! beta
465
466 # Please enter the commit message for the squash changes. Lines starting
467 # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
468 # Changes to be committed:
469 # modified: file
470 #
471 EOF
472 test_cmp expect edited
473 '
474
475 test_expect_success 'lets amend! replace its target message in the editor' '
476 git reset --hard start &&
477 test_commit --no-tag mark-base file b &&
478 stage_file c &&
479 commit_with_message "amend! mark-base\n\namended message\n" &&
480 stage_file d &&
481 commit_with_message "squash! mark-base\n\nsquash remark\n" &&
482
483 write_script editor <<-\EOF &&
484 cat "$1" >edited
485 EOF
486 test_set_editor "$(pwd)/editor" &&
487 git history squash start.. &&
488
489 cat >expect <<-EOF &&
490 # This is a combination of 3 commits.
491 # The 1st commit message will be skipped:
492
493 # mark-base
494
495 # This is the commit message #2:
496
497 # amend! mark-base
498
499 amended message
500
501 # This is the commit message #3:
502
503 # squash! mark-base
504
505 squash remark
506
507 # Please enter the commit message for the squash changes. Lines starting
508 # with ${SQ}#${SQ} will be ignored, and an empty message aborts the commit.
509 # Changes to be committed:
510 # modified: file
511 #
512 EOF
513 test_cmp expect edited &&
514 check_log_messages -1 <<-\EOF
515 amended message
516
517 squash remark
518
519 EOF
520 '
521
522 test_expect_success 'handles branches pointing at the squashed range' '
523 git reset --hard three &&
524 git branch -f other HEAD &&
525 git branch -f mid HEAD~1 &&
526 other_before=$(git rev-parse other) &&
527 mid_before=$(git rev-parse mid) &&
528 head_before=$(git rev-parse HEAD) &&
529
530 test_must_fail git history squash start.. 2>err &&
531 test_grep "error: .* points into the squashed range" err &&
532 test_grep "hint: .*--update-refs=head" err &&
533 test_cmp_rev "$head_before" HEAD &&
534
535 test_must_fail git -c advice.historyUpdateRefs=false \
536 history squash start.. 2>err &&
537 test_grep "points into the squashed range" err &&
538 test_grep ! "hint:" err &&
539 test_cmp_rev "$head_before" HEAD &&
540
541 git history squash --no-edit --update-refs=head start.. &&
542
543 check_commit_count start..HEAD 1 &&
544 test_cmp_rev "$other_before" other &&
545 test_cmp_rev "$mid_before" mid &&
546
547 git branch -D other mid
548 '
549
550 test_expect_success 'leaves tags and remote-tracking refs unchanged' '
551 git reset --hard three &&
552 git tag -f mark HEAD~1 &&
553 git update-ref refs/remotes/origin/mark HEAD~1 &&
554 mark_before=$(git rev-parse mark) &&
555
556 git history squash --no-edit start.. &&
557
558 test_cmp_rev "$mark_before" mark &&
559 test_cmp_rev "$mark_before" refs/remotes/origin/mark &&
560
561 git tag -d mark &&
562 git update-ref -d refs/remotes/origin/mark
563 '
564
565 test_expect_success 'handles a branch pointing at an internal merge' '
566 git reset --hard start &&
567 main=$(git symbolic-ref --short HEAD) &&
568 test_commit --no-tag before-side file b &&
569 git checkout -b inner-side &&
570 test_commit --no-tag on-inner-side inner x &&
571 git checkout "$main" &&
572 test_commit --no-tag after-side file c &&
573 git merge --no-ff -m merge inner-side &&
574 git branch -D inner-side &&
575 git branch at-merge HEAD &&
576 test_commit --no-tag after-merge file d &&
577 head_before=$(git rev-parse HEAD) &&
578 tip_tree=$(git rev-parse HEAD^{tree}) &&
579
580 test_must_fail git history squash start.. 2>err &&
581 test_grep "at-merge" err &&
582 test_grep "points into the squashed range" err &&
583 test_cmp_rev "$head_before" HEAD &&
584 git branch -D at-merge &&
585
586 git history squash --no-edit start.. &&
587
588 check_commit_count start..HEAD 1 &&
589 check_log_subjects -1 <<-\EOF &&
590 before-side
591 EOF
592 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
593 test_path_is_file inner
594 '
595
596 test_expect_success 'folds a merge of a branch that forked at the base' '
597 git reset --hard start &&
598 main=$(git symbolic-ref --short HEAD) &&
599 git checkout -b base-fork-side &&
600 test_commit --no-tag base-fork-side side x &&
601 git checkout "$main" &&
602 test_commit --no-tag base-fork-main file b &&
603 git merge --no-ff -m "merge base-fork-side" base-fork-side &&
604 git branch -D base-fork-side &&
605 test_commit --no-tag base-fork-tail file c &&
606 tip_tree=$(git rev-parse HEAD^{tree}) &&
607
608 git history squash --no-edit start.. &&
609
610 check_commit_count start..HEAD 1 &&
611 test_cmp_rev start HEAD^ &&
612 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
613 test_path_is_file side
614 '
615
616 test_expect_success 'refuses a merge whose other parent is outside the range' '
617 git reset --hard start &&
618 main=$(git symbolic-ref --short HEAD) &&
619 git checkout -b outside-parent &&
620 test_commit --no-tag outside-parent outside x &&
621 git checkout "$main" &&
622 test_commit --no-tag outside-main file b &&
623 base=$(git rev-parse HEAD) &&
624 test_commit --no-tag outside-mid file c &&
625 git merge --no-ff -m "merge outside-parent" outside-parent &&
626 git branch -D outside-parent &&
627 merged=$(git rev-parse HEAD) &&
628
629 test_must_fail git history squash "$base.." 2>err &&
630 test_grep "more than one base" err &&
631 test_cmp_rev "$merged" HEAD
632 '
633
634 test_expect_success 'folds a range whose tip is a merge commit' '
635 git reset --hard start &&
636 main=$(git symbolic-ref --short HEAD) &&
637 test_commit --no-tag tipmerge-base file b &&
638 git checkout -b tipmerge-side &&
639 test_commit --no-tag tipmerge-side side x &&
640 git checkout "$main" &&
641 test_commit --no-tag tipmerge-main file c &&
642 git merge --no-ff -m "merge tipmerge-side" tipmerge-side &&
643 git branch -D tipmerge-side &&
644 tip_tree=$(git rev-parse HEAD^{tree}) &&
645
646 git history squash --no-edit start.. &&
647
648 check_commit_count start..HEAD 1 &&
649 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
650 test_path_is_file side
651 '
652
653 test_expect_success 'folds a range whose base is a merge commit' '
654 git reset --hard start &&
655 main=$(git symbolic-ref --short HEAD) &&
656 git checkout -b basemerge-side &&
657 test_commit --no-tag basemerge-side side x &&
658 git checkout "$main" &&
659 test_commit --no-tag basemerge-main file b &&
660 git merge --no-ff -m "merge basemerge-side" basemerge-side &&
661 git branch -D basemerge-side &&
662 base=$(git rev-parse HEAD) &&
663 test_commit --no-tag basemerge-one file c &&
664 test_commit --no-tag basemerge-two file d &&
665 tip_tree=$(git rev-parse HEAD^{tree}) &&
666
667 git history squash --no-edit "$base.." &&
668
669 check_commit_count "$base..HEAD" 1 &&
670 test_cmp_rev "$base" HEAD^ &&
671 test "$tip_tree" = "$(git rev-parse HEAD^{tree})"
672 '
673
674 test_expect_success 'folds a range with a nested merge' '
675 git reset --hard start &&
676 main=$(git symbolic-ref --short HEAD) &&
677 git checkout -b nested-outer &&
678 test_commit --no-tag nested-outer outer x &&
679 git checkout -b nested-inner &&
680 test_commit --no-tag nested-inner inner y &&
681 git checkout nested-outer &&
682 git merge --no-ff -m "merge inner" nested-inner &&
683 git checkout "$main" &&
684 test_commit --no-tag nested-main file b1 &&
685 git merge --no-ff -m "merge outer" nested-outer &&
686 git branch -D nested-outer nested-inner &&
687 tip_tree=$(git rev-parse HEAD^{tree}) &&
688
689 git history squash --no-edit start.. &&
690
691 check_commit_count start..HEAD 1 &&
692 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
693 test_path_is_file outer &&
694 test_path_is_file inner
695 '
696
697 test_expect_success 'folds a range with an octopus merge' '
698 git reset --hard start &&
699 main=$(git symbolic-ref --short HEAD) &&
700 test_commit --no-tag octo-base file a1 &&
701 git checkout -b octo-1 &&
702 test_commit --no-tag octo-1 o1 x &&
703 git checkout "$main" &&
704 git checkout -b octo-2 &&
705 test_commit --no-tag octo-2 o2 y &&
706 git checkout "$main" &&
707 git merge --no-ff -m octopus octo-1 octo-2 &&
708 git branch -D octo-1 octo-2 &&
709 tip_tree=$(git rev-parse HEAD^{tree}) &&
710
711 git history squash --no-edit start.. &&
712
713 check_commit_count start..HEAD 1 &&
714 test "$tip_tree" = "$(git rev-parse HEAD^{tree})" &&
715 test_path_is_file o1 &&
716 test_path_is_file o2
717 '
718
719 test_expect_success 'refuses an octopus merge with an arm forked before the base' '
720 git reset --hard start &&
721 main=$(git symbolic-ref --short HEAD) &&
722 git checkout -b octo-pre &&
723 test_commit octo-pre-side pside x &&
724 git checkout "$main" &&
725 test_commit octo-pre-main file b1 &&
726 octo_base=$(git rev-parse HEAD) &&
727 git checkout -b octo-within &&
728 test_commit --no-tag octo-within wside y &&
729 git checkout "$main" &&
730 git merge --no-ff -m octopus octo-pre octo-within &&
731 merged=$(git rev-parse HEAD) &&
732 git branch -D octo-pre octo-within &&
733
734 test_must_fail git history squash "$octo_base.." 2>err &&
735 test_grep "more than one base" err &&
736 test_cmp_rev "$merged" HEAD
737 '
738
739 test_expect_success 'refuses when a descendant above the range is a merge' '
740 git reset --hard start &&
741 main=$(git symbolic-ref --short HEAD) &&
742 test_commit --no-tag desc-one file b &&
743 test_commit --no-tag desc-two file c &&
744 git tag desc-tip &&
745 git checkout -b desc-above &&
746 test_commit --no-tag desc-above above x &&
747 git checkout "$main" &&
748 test_commit --no-tag desc-main file d &&
749 git merge --no-ff -m "merge desc-above" desc-above &&
750 git branch -D desc-above &&
751 head_before=$(git rev-parse HEAD) &&
752
753 test_must_fail git history squash --no-edit start..desc-tip 2>err &&
754 test_grep "merge commits is not supported" err &&
755 test_cmp_rev "$head_before" HEAD
756 '
757
758 test_done