Skip to content

Commit 6bdcd0d

Browse files
mhaggergitster
authored andcommitted
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>
1 parent 6c4c44c commit 6bdcd0d

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

git-rebase--interactive.sh

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,21 @@ peek_next_command () {
408408
sed -n -e "/^#/d" -e "/^$/d" -e "s/ .*//p" -e "q" < "$TODO"
409409
}
410410

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+
411426
do_next () {
412427
rm -f "$MSG" "$AUTHOR_SCRIPT" "$AMEND" || exit
413428
read command sha1 rest < "$TODO"
@@ -465,58 +480,31 @@ do_next () {
465480

466481
mark_action_done
467482
update_squash_messages $squash_style $sha1
468-
failed=f
469483
author_script=$(get_author_ident_from_commit HEAD)
470484
echo "$author_script" > "$AUTHOR_SCRIPT"
471485
eval "$author_script"
472486
output git reset --soft HEAD^
473-
pick_one -n $sha1 || failed=t
487+
pick_one -n $sha1 || die_failed_squash $sha1 "$rest"
474488
case "$(peek_next_command)" in
475489
squash|s|fixup|f)
476490
# This is an intermediate commit; its message will only be
477491
# 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"
494494
;;
495495
*)
496496
# This is the final command of this squash/fixup group
497-
if test $failed = f
497+
if test -f "$FIXUP_MSG"
498498
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"
518506
fi
519-
rm -f "$SQUASH_MSG"
507+
rm -f "$SQUASH_MSG" "$FIXUP_MSG"
520508
;;
521509
esac
522510
;;

t/t3404-rebase-interactive.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,42 @@ test_expect_success 'multi-fixup does not fire up editor' '
264264
git branch -D multi-fixup
265265
'
266266

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+
267303
cat > expect-squash-fixup << EOF
268304
B
269305

0 commit comments

Comments
 (0)