git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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

             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).