pull --rebase: be cleverer with rebased upstream branches
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Sat, 26 Jan 2008 18:04:37 +0000 (18:04 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sun, 27 Jan 2008 02:24:24 +0000 (18:24 -0800)
When the upstream branch is tracked, we can detect if that branch
was rebased since it was last fetched.  Teach git to use that
information to rebase from the old remote head onto the new remote head.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-pull.txt
git-pull.sh
t/t5520-pull.sh

index f9f1e0d30b5ba9842d5071d3d3fba3599cd96ebf..4cc633a5ec4c449e98ac9cb16fd125da6d336798 100644 (file)
@@ -35,7 +35,11 @@ include::urls-remotes.txt[]
 include::merge-strategies.txt[]
 
 \--rebase::
-       Instead of a merge, perform a rebase after fetching.
+       Instead of a merge, perform a rebase after fetching.  If
+       there is a remote ref for the upstream branch, and this branch
+       was rebased since last fetched, the rebase uses that information
+       to avoid rebasing non-local changes.
+
        *NOTE:* This is a potentially _dangerous_ mode of operation.
        It rewrites history, which does not bode well when you
        published that history already.  Do *not* use this option
index fa97b0f3562ab34b7cf1b7b68b293d9174121088..46da0f4ca2bfc2b30e4da8eb551565a06c876fb1 100755 (executable)
@@ -106,6 +106,15 @@ error_on_no_merge_candidates () {
        exit 1
 }
 
+test true = "$rebase" && {
+       . git-parse-remote &&
+       origin="$1"
+       test -z "$origin" && origin=$(get_default_remote)
+       reflist="$(get_remote_refs_for_fetch "$@" 2>/dev/null |
+               sed "s|refs/heads/\(.*\):|\1|")" &&
+       oldremoteref="$(git rev-parse --verify \
+               "refs/remotes/$origin/$reflist" 2>/dev/null)"
+}
 orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
 git-fetch --update-head-ok "$@" || exit 1
 
@@ -164,6 +173,7 @@ then
 fi
 
 merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
-test true = "$rebase" && exec git-rebase $merge_head
+test true = "$rebase" &&
+       exec git-rebase --onto $merge_head ${oldremoteref:-$merge_head}
 exec git-merge $no_summary $no_commit $squash $no_ff $strategy_args \
        "$merge_name" HEAD $merge_head
index 52b3a0c6dde59b8a955f28f4e9ffe037b0271513..9484129ca5aafab369a6ee1f7a1264d568f8cb44 100755 (executable)
@@ -71,8 +71,25 @@ test_expect_success 'branch.to-rebase.rebase' '
        git reset --hard before-rebase &&
        git config branch.to-rebase.rebase 1 &&
        git pull . copy &&
+       git config branch.to-rebase.rebase 0 &&
        test $(git rev-parse HEAD^) = $(git rev-parse copy) &&
        test new = $(git show HEAD:file2)
 '
 
+test_expect_success '--rebase with rebased upstream' '
+
+       git remote add -f me . &&
+       git checkout copy &&
+       git reset --hard HEAD^ &&
+       echo conflicting modification > file &&
+       git commit -m conflict file &&
+       git checkout to-rebase &&
+       echo file > file2 &&
+       git commit -m to-rebase file2 &&
+       git pull --rebase me copy &&
+       test "conflicting modification" = "$(cat file)" &&
+       test file = $(cat file2)
+
+'
+
 test_done