Skip to content

Commit c85c792

Browse files
dschogitster
authored andcommitted
pull --rebase: be cleverer with rebased upstream branches
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>
1 parent e509db9 commit c85c792

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

Documentation/git-pull.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ include::urls-remotes.txt[]
3535
include::merge-strategies.txt[]
3636

3737
\--rebase::
38-
Instead of a merge, perform a rebase after fetching.
38+
Instead of a merge, perform a rebase after fetching. If
39+
there is a remote ref for the upstream branch, and this branch
40+
was rebased since last fetched, the rebase uses that information
41+
to avoid rebasing non-local changes.
42+
3943
*NOTE:* This is a potentially _dangerous_ mode of operation.
4044
It rewrites history, which does not bode well when you
4145
published that history already. Do *not* use this option

git-pull.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ error_on_no_merge_candidates () {
106106
exit 1
107107
}
108108

109+
test true = "$rebase" && {
110+
. git-parse-remote &&
111+
origin="$1"
112+
test -z "$origin" && origin=$(get_default_remote)
113+
reflist="$(get_remote_refs_for_fetch "$@" 2>/dev/null |
114+
sed "s|refs/heads/\(.*\):|\1|")" &&
115+
oldremoteref="$(git rev-parse --verify \
116+
"refs/remotes/$origin/$reflist" 2>/dev/null)"
117+
}
109118
orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
110119
git-fetch --update-head-ok "$@" || exit 1
111120

@@ -164,6 +173,7 @@ then
164173
fi
165174

166175
merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
167-
test true = "$rebase" && exec git-rebase $merge_head
176+
test true = "$rebase" &&
177+
exec git-rebase --onto $merge_head ${oldremoteref:-$merge_head}
168178
exec git-merge $no_summary $no_commit $squash $no_ff $strategy_args \
169179
"$merge_name" HEAD $merge_head

t/t5520-pull.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,25 @@ test_expect_success 'branch.to-rebase.rebase' '
7171
git reset --hard before-rebase &&
7272
git config branch.to-rebase.rebase 1 &&
7373
git pull . copy &&
74+
git config branch.to-rebase.rebase 0 &&
7475
test $(git rev-parse HEAD^) = $(git rev-parse copy) &&
7576
test new = $(git show HEAD:file2)
7677
'
7778

79+
test_expect_success '--rebase with rebased upstream' '
80+
81+
git remote add -f me . &&
82+
git checkout copy &&
83+
git reset --hard HEAD^ &&
84+
echo conflicting modification > file &&
85+
git commit -m conflict file &&
86+
git checkout to-rebase &&
87+
echo file > file2 &&
88+
git commit -m to-rebase file2 &&
89+
git pull --rebase me copy &&
90+
test "conflicting modification" = "$(cat file)" &&
91+
test file = $(cat file2)
92+
93+
'
94+
7895
test_done

0 commit comments

Comments
 (0)