rebase: fix --onto A...B parsing and add tests
authorNanako Shiraishi <nanako3@lavabit.com>
Thu, 7 Jan 2010 11:05:02 +0000 (20:05 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 7 Jan 2010 19:14:39 +0000 (11:14 -0800)
The previous patch didn't parse "rebase --onto A...B" correctly when A
isn't an empty string. It also tried to be careful to notice a case in
which there are more than one merge bases, but forgot to give --all option
to merge-base, making the test pointless.

Fix these problems and add a test script to verify. Improvements to the
script to parse A...B syntax was taken from review comments by Johannes
Schindelin.

Signed-off-by: しらいし ななこ <nanako3@lavabit.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-rebase.sh
t/t3415-rebase-onto-threedots.sh [new file with mode: 0755]

index 6503113a84e6e01e15bfcddd427c359c597cd7d1..9bd89746ab6ab6999aeead41a59ca0f4c9b3a61a 100755 (executable)
@@ -419,22 +419,27 @@ fi
 
 # Make sure the branch to rebase onto is valid.
 onto_name=${newbase-"$upstream_name"}
-if     left=$(expr "$onto_name" : '\(.*\)\.\.\.') &&
-       right=$(expr "$onto_name" : '\.\.\.\(.*\)$') &&
-       : ${left:=HEAD} ${right:=HEAD} &&
-       onto=$(git merge-base "$left" "$right")
-then
-       case "$onto" in
-       ?*"$LF"?*)
-               die "$onto_name: there are more than one merge bases"
-               ;;
-       '')
+case "$onto_name" in
+*...*)
+       if      left=${onto_name%...*} right=${onto_name#*...} &&
+               onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
+       then
+               case "$onto" in
+               ?*"$LF"?*)
+                       die "$onto_name: there are more than one merge bases"
+                       ;;
+               '')
+                       die "$onto_name: there is no merge base"
+                       ;;
+               esac
+       else
                die "$onto_name: there is no merge base"
-               ;;
-       esac
-else
+       fi
+       ;;
+*)
        onto=$(git rev-parse --verify "${onto_name}^0") || exit
-fi
+       ;;
+esac
 
 # If a hook exists, give it a chance to interrupt
 run_pre_rebase_hook "$upstream_arg" "$@"
diff --git a/t/t3415-rebase-onto-threedots.sh b/t/t3415-rebase-onto-threedots.sh
new file mode 100755 (executable)
index 0000000..b09e907
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+test_description='git rebase --onto A...B'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-rebase.sh"
+
+# Rebase only the tip commit of "topic" on merge base between "master"
+# and "topic".  Cannot do this for "side" with "master" because there
+# is no single merge base.
+#
+#
+#          F---G topic                             G'
+#         /                                       /
+# A---B---C---D---E master      -->       A---B---C---D---E
+#      \   \ /
+#      \   x
+#       \ / \
+#        H---I---J---K side
+
+test_expect_success setup '
+       test_commit A &&
+       test_commit B &&
+       git branch side &&
+       test_commit C &&
+       git branch topic &&
+       git checkout side &&
+       test_commit H &&
+       git checkout master &&
+       test_tick &&
+       git merge H &&
+       git tag D &&
+       test_commit E &&
+       git checkout topic &&
+       test_commit F &&
+       test_commit G &&
+       git checkout side &&
+       test_tick &&
+       git merge C &&
+       git tag I &&
+       test_commit J &&
+       test_commit K
+'
+
+test_expect_success 'rebase --onto master...topic' '
+       git reset --hard &&
+       git checkout topic &&
+       git reset --hard G &&
+
+       git rebase --onto master...topic F &&
+       git rev-parse HEAD^1 >actual &&
+       git rev-parse C^0 >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rebase --onto master...' '
+       git reset --hard &&
+       git checkout topic &&
+       git reset --hard G &&
+
+       git rebase --onto master... F &&
+       git rev-parse HEAD^1 >actual &&
+       git rev-parse C^0 >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'rebase --onto master...side' '
+       git reset --hard &&
+       git checkout side &&
+       git reset --hard K &&
+
+       test_must_fail git rebase --onto master...side J
+'
+
+test_done