rebase -i: Retain user-edited commit messages after squash/fixup conflicts
When a squash/fixup fails due to a conflict, the user is required to edit the commit message. Previously, if further squash/fixup commands followed the conflicting squash/fixup, this user-edited message was discarded and a new automatically-generated commit message was suggested. Change the handling of conflicts within squash/fixup command series: Whenever the user is required to intervene, consider the resulting commit to be a new basis for the following squash/fixups and use its commit message in later suggested combined commit messages. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Haggerty committed
Jan 14, 2010 at 06:54 UTC
6bdcd0d2fcca7c3985a078c8d343a863136fb675
2 files changed
+63
-39
git-rebase--interactive.sh
+27
-39
@@ -408,6 +408,21 @@ peek_next_command () {
408
sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO"
409
}
410
411
+# A squash/fixup has failed. Prepare the long version of the squash
412
+# commit message, then die_with_patch. This code path requires the
413
+# user to edit the combined commit message for all commits that have
414
+# been squashed/fixedup so far. So also erase the old squash
415
+# messages, effectively causing the combined commit to be used as the
416
+# new basis for any further squash/fixups. Args: sha1 rest
417
+die_failed_squash() {
418
+ mv "$SQUASH_MSG" "$MSG" || exit
419
+ rm -f "$FIXUP_MSG"
420
+ cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
421
+ warn
422
+ warn "Could not apply $1... $2"
423
+ die_with_patch $1 ""
424
+}
425
+
426
do_next () {
427
rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
428
read command sha1 rest < "$TODO"
@@ -465,58 +480,31 @@ do_next () {
480
481
mark_action_done
482
update_squash_messages $squash_style $sha1
468
- failed=f
483
author_script=$(get_author_ident_from_commit HEAD)
484
echo "$author_script" > "$AUTHOR_SCRIPT"
485
eval "$author_script"
486
output git reset --soft HEAD^
473
- pick_one -n $sha1 || failed=t
487
+ pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
488
case "$(peek_next_command)" in
489
squash|s|fixup|f)
490
# This is an intermediate commit; its message will only be
491
# used in case of trouble. So use the long version:
478
- if test $failed = f
479
- then
480
- do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
481
- failed=t
482
- fi
483
- if test $failed = t
484
- then
485
- cp "$SQUASH_MSG" "$MSG" || exit
486
- # After any kind of hiccup, prevent committing without
487
- # opening the commit message editor:
488
- rm -f "$FIXUP_MSG"
489
- cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
490
- warn
491
- warn "Could not apply $sha1... $rest"
492
- die_with_patch $sha1 ""
493
- fi
492
+ do_with_author output git commit --no-verify -F "$SQUASH_MSG" ||
493
+ die_failed_squash $sha1 "$rest"
494
;;
495
*)
496
# This is the final command of this squash/fixup group
497
- if test $failed = f
497
+ if test -f "$FIXUP_MSG"
498
then
499
- if test -f "$FIXUP_MSG"
500
- then
501
- do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
502
- failed=t
503
- else
504
- cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
505
- rm -f "$GIT_DIR"/MERGE_MSG
506
- do_with_author git commit --no-verify -e ||
507
- failed=t
508
- fi
509
- fi
510
- rm -f "$FIXUP_MSG"
511
- if test $failed = t
512
- then
513
- mv "$SQUASH_MSG" "$MSG" || exit
514
- cp "$MSG" "$GIT_DIR"/MERGE_MSG || exit
515
- warn
516
- warn "Could not apply $sha1... $rest"
517
- die_with_patch $sha1 ""
499
+ do_with_author git commit --no-verify -F "$FIXUP_MSG" ||
500
+ die_failed_squash $sha1 "$rest"
501
+ else
502
+ cp "$SQUASH_MSG" "$GIT_DIR"/SQUASH_MSG || exit
503
+ rm -f "$GIT_DIR"/MERGE_MSG
504
+ do_with_author git commit --no-verify -e ||
505
+ die_failed_squash $sha1 "$rest"
506
fi
519
- rm -f "$SQUASH_MSG"
507
+ rm -f "$SQUASH_MSG" "$FIXUP_MSG"
508
;;
509
esac
510
;;
t/t3404-rebase-interactive.sh
+36
@@ -264,6 +264,42 @@ test_expect_success 'multi-fixup does not fire up editor' '
264
git branch -D multi-fixup
265
'
266
267
+test_expect_success 'commit message used after conflict' '
268
+ git checkout -b conflict-fixup conflict-branch &&
269
+ base=$(git rev-parse HEAD~4) &&
270
+ (
271
+ FAKE_LINES="1 fixup 3 fixup 4" &&
272
+ export FAKE_LINES &&
273
+ test_must_fail git rebase -i $base
274
+ ) &&
275
+ echo three > conflict &&
276
+ git add conflict &&
277
+ FAKE_COMMIT_AMEND="ONCE" EXPECT_HEADER_COUNT=2 \
278
+ git rebase --continue &&
279
+ test $base = $(git rev-parse HEAD^) &&
280
+ test 1 = $(git show | grep ONCE | wc -l) &&
281
+ git checkout to-be-rebased &&
282
+ git branch -D conflict-fixup
283
+'
284
+
285
+test_expect_success 'commit message retained after conflict' '
286
+ git checkout -b conflict-squash conflict-branch &&
287
+ base=$(git rev-parse HEAD~4) &&
288
+ (
289
+ FAKE_LINES="1 fixup 3 squash 4" &&
290
+ export FAKE_LINES &&
291
+ test_must_fail git rebase -i $base
292
+ ) &&
293
+ echo three > conflict &&
294
+ git add conflict &&
295
+ FAKE_COMMIT_AMEND="TWICE" EXPECT_HEADER_COUNT=2 \
296
+ git rebase --continue &&
297
+ test $base = $(git rev-parse HEAD^) &&
298
+ test 2 = $(git show | grep TWICE | wc -l) &&
299
+ git checkout to-be-rebased &&
300
+ git branch -D conflict-squash
301
+'
302
+
303
cat > expect-squash-fixup << EOF
304
B
305