From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>, <santi@agolina.net>,
Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
Subject: [PATCH] rebase: be cleverer with rebased upstream branches
Date: Mon, 14 Feb 2011 08:51:21 -0500 [thread overview]
Message-ID: <1297691481-3308-1-git-send-email-martin.von.zweigbergk@gmail.com> (raw)
Since c85c792 (pull --rebase: be cleverer with rebased upstream
branches, 2008-01-26), 'git pull --rebase' has used the reflog to try
to rebase from the old upstream onto the new upstream.
However, if, instead of 'git pull --rebase', the user were to do 'git
fetch' followed by 'git rebase', the reflog would not be walked. This
patch teaches "git rebase" the same reflog-walking tricks that 'git
pull --rebase' already knows.
This may be useful for rebasing one branch against another local
branch that has been rebased. Currently, you would have to do that
using 'git rebase --onto' or by configuring it on the branch.
It might seem like most of the related code in git-pull.sh can be
removed once git-rebase.sh supports reflog walking. Unfortunately, not
much of it can be removed, though. The reason is that git-pull.sh
simulates one step of "reflog walking" by keeping track of the
position of the remote-tracking branch before and after the fetch
operation. This does not rely on reflogs. There are at least two cases
where the reflog is not used: a) when it is disabled, b) when the
remote branch was specified on the command line (as in 'git pull
--rebase origin master'). In both of these cases, git-pull.sh
remembers the position of the reference before the fetch and uses that
as a kind of '$upstream@{1}'.
Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
---
This applies on top of mz/rebase.
I have been using this in combination with the patch for defaulting
rebase to @{upstream} for a few months now. I find it very convenient
e.g. when Junio has published some changes and I want to rebase my
branches. Then I just go to each of my branches and run 'git rebase'
without any arguments, and they get rebased correctly, whether they
are based on origin/master, origin/pu (they shouldn't be, but let's
say they are anyway), or on a local branch that is in turn based on
e.g. origin/master.
HOWEVER, this causes a very noticable delay in some cases. With this
patch, 'git rebase' walks the reflog of the upstream ref until it
finds a commit that the branch-to-rebase contains. If the upstream ref
has moved a lot since the branch was last rebased, there may be quite
a few commits to test before the old upstream commit is found.
The same thing can already occur with 'git pull --rebase' for exactly
the same reasons. For example, assume that your upstream remote branch
changes quite frequently and that you often fetch from the remote so
that your origin/master gets a long reflog. If you then checkout some
branch you had not been working on for a while, and run 'git pull',
you get into the same situation. The delay is probably less likely to
be noticed in the case of 'git pull --rebase', however, since most
users will probably assume it is a problem with the network or the
server.
Of course, 'git pull --rebase' can also be used with a local branch
configured as upstream. In this case, the behavior today is just like
what this patch introduces for 'git rebase'.
What do you think? I think it's a useful feature, but how do we handle
the delay problem? Maybe simply by making it configurable?
Should such a configuration variable apply to 'git pull --rebase' as
well? It would seem inconsistent otherwise, but maybe that's ok since
'git pull --rebase' is usually used with remote-tracking branches,
which probably change less frequently. Btw, is this a correct
assumption? It is definitely true for my own work on git, but I
actually think it's the other way around for my work at $dayjob. Am I
missing some part to the puzzle that explains why I had not noticed
the delay until I started using this patch?
Documentation/git-rebase.txt | 7 ++++++-
git-rebase.sh | 13 +++++++++++++
t/t3400-rebase.sh | 26 ++++++++++++++++++++++++++
3 files changed, 45 insertions(+), 1 deletions(-)
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 095a67f..d4dbe28 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -24,7 +24,12 @@ it remains on the current branch.
All changes made by commits in the current branch but that are not
in <upstream> are saved to a temporary area. This is the same set
of commits that would be shown by `git log <upstream>..HEAD` (or
-`git log HEAD`, if --root is specified).
+`git log HEAD`, if --root is specified). If, however, there is a ref
+for the upstream branch, and this branch was rebased since the
+current branch was last rebased, the rebase uses that information to
+avoid rebasing changes done on the upstream branch. If you do not want
+'git rebase' to use this intelligence, refer to the upstream without
+using a reference (e.g. 'master~0').
The current branch is reset to <upstream>, or <newbase> if the
--onto option was supplied. This has the exact same effect as
diff --git a/git-rebase.sh b/git-rebase.sh
index 5abfeac..1bc0c29 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -466,6 +466,19 @@ esac
require_clean_work_tree "rebase" "Please commit or stash them."
+test -n "$upstream_name" && for reflog in \
+ $(git rev-list -g $upstream_name 2>/dev/null)
+do
+ if test $reflog = $(git merge-base $reflog $orig_head)
+ then
+ if test $reflog != $(git merge-base $onto $reflog)
+ then
+ upstream=$reflog
+ fi
+ break
+ fi
+done
+
# Now we are rebasing commits $upstream..$orig_head (or with --root,
# everything leading up to $orig_head) on top of $onto
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index 349eebd..b64df31 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -209,4 +209,30 @@ test_expect_success 'rebase -m can copy notes' '
test "a note" = "$(git notes show HEAD)"
'
+test_expect_success 'rebase against rebased upstream uses reflog' '
+ git checkout my-topic-branch &&
+ echo "Conflicting modification" > B &&
+ git add B &&
+ git commit -m "Modify B" &&
+ git reset --hard nonlinear &&
+ git checkout -b old-topic my-topic-branch@{1} &&
+ echo def > D &&
+ git add D &&
+ git commit -m "Add D" &&
+ git rebase my-topic-branch &&
+ test $(git rev-parse HEAD^) = $(git rev-parse my-topic-branch)
+'
+
+test_expect_success 'rebase against forwarded upstream does not reapply patches' '
+ git checkout my-topic-branch &&
+ echo abc > B &&
+ git add B &&
+ git commit -m "Conficting B" &&
+ git reset HEAD~2 &&
+ git reset HEAD@{1} &&
+ git checkout old-topic &&
+ git rebase my-topic-branch &&
+ test $(git rev-parse HEAD^) = $(git rev-parse my-topic-branch)
+'
+
test_done
--
1.7.4.rc2.33.g8a14f
next reply other threads:[~2011-02-14 13:51 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-02-14 13:51 Martin von Zweigbergk [this message]
2011-02-15 11:28 ` [PATCH] rebase: be cleverer with rebased upstream branches Santi Béjar
2011-02-16 1:37 ` Martin von Zweigbergk
2011-02-16 9:26 ` Santi Béjar
2011-02-15 20:30 ` Junio C Hamano
2011-02-16 3:03 ` Martin von Zweigbergk
2011-02-16 12:10 ` Santi Béjar
2011-02-16 13:22 ` Santi Béjar
2011-02-16 19:07 ` Junio C Hamano
2011-02-16 21:16 ` Santi Béjar
2011-02-16 16:45 ` Martin von Zweigbergk
2011-02-17 10:24 ` Santi Béjar
2011-03-12 21:15 ` Martin von Zweigbergk
2011-03-12 23:51 ` Santi Béjar
2011-03-13 1:32 ` Martin von Zweigbergk
2011-03-13 3:14 ` Martin von Zweigbergk
2011-03-13 22:57 ` Junio C Hamano
2011-03-13 23:42 ` Santi Béjar
2011-03-13 23:09 ` Santi Béjar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1297691481-3308-1-git-send-email-martin.von.zweigbergk@gmail.com \
--to=martin.von.zweigbergk@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=santi@agolina.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).