diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 124cb5846b..30e45237a2 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -37,6 +37,7 @@ DONE="$DOTEST"/done MSG="$DOTEST"/message SQUASH_MSG="$DOTEST"/message-squash REWRITTEN="$DOTEST"/rewritten +DROPPED="$DOTEST"/dropped PRESERVE_MERGES= STRATEGY= ONTO= @@ -179,8 +180,12 @@ pick_one_preserving_merges () { # rewrite parents; if none were rewritten, we can fast-forward. new_parents= - for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-) + pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)" + while [ "$pend" != "" ] do + p=$(expr "$pend" : ' \([^ ]*\)') + pend="${pend# $p}" + if test -f "$REWRITTEN"/$p then new_p=$(cat "$REWRITTEN"/$p) @@ -193,7 +198,13 @@ pick_one_preserving_merges () { ;; esac else - new_parents="$new_parents $p" + if test -f "$DROPPED"/$p + then + fast_forward=f + pend=" $(cat "$DROPPED"/$p)$pend" + else + new_parents="$new_parents $p" + fi fi done case $fast_forward in @@ -599,6 +610,28 @@ first and then run 'git rebase --continue' again." # EOF + # Watch for commits that been dropped by --cherry-pick + if test t = "$PRESERVE_MERGES" + then + mkdir "$DROPPED" + # drop the --cherry-pick parameter this time + git rev-list $MERGES_OPTION --abbrev-commit \ + --abbrev=7 $UPSTREAM...$HEAD --left-right | \ + sed -n "s/^>//p" | while read rev + do + grep --quiet "$rev" "$TODO" + if [ $? -ne 0 ] + then + # Use -f2 because if rev-list is telling this commit is not + # worthwhile, we don't want to track its multiple heads, + # just the history of its first-parent for others that will + # be rebasing on top of us + full=$(git rev-parse $rev) + git rev-list --parents -1 $rev | cut -d' ' -f2 > "$DROPPED"/$full + fi + done + fi + has_action "$TODO" || die_abort "Nothing to do" diff --git a/t/t3410-rebase-preserve-dropped-merges.sh b/t/t3410-rebase-preserve-dropped-merges.sh new file mode 100755 index 0000000000..5816415aaf --- /dev/null +++ b/t/t3410-rebase-preserve-dropped-merges.sh @@ -0,0 +1,139 @@ +#!/bin/sh +# +# Copyright (c) 2008 Stephen Haberman +# + +test_description='git rebase preserve merges + +This test runs git rebase with preserve merges and ensures commits +dropped by the --cherry-pick flag have their childrens parents +rewritten. +' +. ./test-lib.sh + +# set up two branches like this: +# +# A - B - C - D - E +# \ +# F - G - H +# \ +# I +# +# where B, D and G touch the same file. + +test_expect_success 'setup' ' + : > file1 && + git add file1 && + test_tick && + git commit -m A && + git tag A && + echo 1 > file1 && + test_tick && + git commit -m B file1 && + : > file2 && + git add file2 && + test_tick && + git commit -m C && + echo 2 > file1 && + test_tick && + git commit -m D file1 && + : > file3 && + git add file3 && + test_tick && + git commit -m E && + git tag E && + git checkout -b branch1 A && + : > file4 && + git add file4 && + test_tick && + git commit -m F && + git tag F && + echo 3 > file1 && + test_tick && + git commit -m G file1 && + git tag G && + : > file5 && + git add file5 && + test_tick && + git commit -m H && + git tag H && + git checkout -b branch2 F && + : > file6 && + git add file6 && + test_tick && + git commit -m I && + git tag I +' + +# A - B - C - D - E +# \ \ \ +# F - G - H -- L \ --> L +# \ | \ +# I -- G2 -- J -- K I -- K +# G2 = same changes as G +test_expect_success 'skip same-resolution merges with -p' ' + git checkout branch1 && + ! git merge E && + echo 23 > file1 && + git add file1 && + git commit -m L && + git checkout branch2 && + echo 3 > file1 && + git commit -a -m G2 && + ! git merge E && + echo 23 > file1 && + git add file1 && + git commit -m J && + echo file7 > file7 && + git add file7 && + git commit -m K && + GIT_EDITOR=: git rebase -i -p branch1 && + test $(git rev-parse branch2^^) = $(git rev-parse branch1) && + test "23" = "$(cat file1)" && + test "" = "$(cat file6)" && + test "file7" = "$(cat file7)" && + + git checkout branch1 && + git reset --hard H && + git checkout branch2 && + git reset --hard I +' + +# A - B - C - D - E +# \ \ \ +# F - G - H -- L \ --> L +# \ | \ +# I -- G2 -- J -- K I -- G2 -- K +# G2 = different changes as G +test_expect_success 'keep different-resolution merges with -p' ' + git checkout branch1 && + ! git merge E && + echo 23 > file1 && + git add file1 && + git commit -m L && + git checkout branch2 && + echo 4 > file1 && + git commit -a -m G2 && + ! git merge E && + echo 24 > file1 && + git add file1 && + git commit -m J && + echo file7 > file7 && + git add file7 && + git commit -m K && + ! GIT_EDITOR=: git rebase -i -p branch1 && + echo 234 > file1 && + git add file1 && + GIT_EDITOR=: git rebase --continue && + test $(git rev-parse branch2^^^) = $(git rev-parse branch1) && + test "234" = "$(cat file1)" && + test "" = "$(cat file6)" && + test "file7" = "$(cat file7)" && + + git checkout branch1 && + git reset --hard H && + git checkout branch2 && + git reset --hard I +' + +test_done