Merge branch 'sh/maint-rebase3'
authorJunio C Hamano <gitster@pobox.com>
Sun, 19 Oct 2008 23:07:29 +0000 (16:07 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 19 Oct 2008 23:07:29 +0000 (16:07 -0700)
* sh/maint-rebase3:
rebase--interactive: fix parent rewriting for dropped commits

git-rebase--interactive.sh
t/t3410-rebase-preserve-dropped-merges.sh [new file with mode: 0755]
index 86290f63b25f921de5c78b087e111e6b872676fb..39f8d73dfa4377922fd8ebc406643d73338916d0 100755 (executable)
@@ -38,6 +38,7 @@ DONE="$DOTEST"/done
 MSG="$DOTEST"/message
 SQUASH_MSG="$DOTEST"/message-squash
 REWRITTEN="$DOTEST"/rewritten
+DROPPED="$DOTEST"/dropped
 PRESERVE_MERGES=
 STRATEGY=
 ONTO=
@@ -182,8 +183,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)
@@ -196,7 +201,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
@@ -607,6 +618,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 (executable)
index 0000000..5816415
--- /dev/null
@@ -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