From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
To: git@vger.kernel.org
Cc: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
Subject: [PATCH 5/5] rebase [-m]: calculate patches in upstream correctly
Date: Tue, 26 Jun 2012 07:51:58 -0700 [thread overview]
Message-ID: <1340722318-24392-6-git-send-email-martin.von.zweigbergk@gmail.com> (raw)
In-Reply-To: <1340722318-24392-1-git-send-email-martin.von.zweigbergk@gmail.com>
Plain 'git rebase' (without -m/-i/-p) applies the patches from
git format-patch --ignore-if-in-upstream $upstream..$orig_head
, while 'git rebase -m' finds the commits using
git rev-list $upstream..$orig_head
As Knut Franke reported in [1], the fact that there is no
--ignore-if-in-upstream or equivalent when using merge-based rebase
means that unnecessary conflicts can arise due to commits
cherry-picked between $orig_head and $upstream.
There is a second problem with the above method of calculating the
upstream commits. Copying the example history from [1]:
.-c
/
a---b---d---e---f
\
.-g---E
Commit E is here a cherry-pick of e. If we now run 'git rebase --onto
c f E', the revisions that will be applied onto 'c' are given by 'git
format-patch --ignore-if-in-upstream f..E'. In this case that would be
only 'g' and NOT 'E'.
To solve both of the above problems, we want to find the commits in
$upstream..$orig_head that are not cherry-picked in
$upstream..$onto. There is unfortunately no direct way of finding
these commits using 'git rev-list', so we will have to resort to using
'git cherry' and filter for lines starting with '+'.
To reduce the risk of 'git rebase' and 'git rebase -m' behaving
differently (with respect to the commits chosen) in the future,
perform the calculation already in git-rebase.sh.
As a side-effect, we also avoid the cost of formatting patches.
Test case updates for 'rebase -m' by Knut, the rest by Martin.
[1] http://thread.gmane.org/gmane.comp.version-control.git/161917
Helped-by: Knut Franke <Knut.Franke@gmx.de>
Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
---
git-rebase--am.sh | 6 ++----
git-rebase--merge.sh | 2 +-
git-rebase.sh | 7 +------
t/t3401-rebase-partial.sh | 17 +++++++++++++++++
t/t3406-rebase-message.sh | 14 +++++++-------
5 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index 392ebc9..89e0ab4 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -16,7 +16,6 @@ skip)
;;
esac
-test -n "$rebase_root" && root_flag=--root
if test -n "$keep_empty"
then
@@ -26,9 +25,8 @@ then
# makes this easy
git cherry-pick --allow-empty "$revisions"
else
- git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- --src-prefix=a/ --dst-prefix=b/ \
- --no-renames $root_flag "$revisions" |
+ echo "$revisions" |
+ sed -e 's/\([0-9a-f]\{40\}\)/From \1 Mon Sep 17 00:00:00 2001/' |
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg"
fi && move_to_original_branch
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index b10f2cf..7ea33e3 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -131,7 +131,7 @@ echo "$onto_name" > "$state_dir/onto_name"
write_basic_state
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$revisions"`
+for cmt in $revisions
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$state_dir/cmt.$msgnum"
diff --git a/git-rebase.sh b/git-rebase.sh
index 6df06c4..47e75cb 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -522,11 +522,6 @@ then
exit 0
fi
-if test -n "$rebase_root"
-then
- revisions="$onto..$orig_head"
-else
- revisions="$upstream..$orig_head"
-fi
+revisions="$(git cherry $onto $orig_head $upstream | sed -ne 's/^+ //p')"
run_specific_rebase
diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh
index 7ba1797..ce555fa 100755
--- a/t/t3401-rebase-partial.sh
+++ b/t/t3401-rebase-partial.sh
@@ -42,4 +42,21 @@ test_expect_success 'rebase --merge topic branch that was partially merged upstr
test_path_is_missing .git/rebase-merge
'
+test_expect_success 'rebase --onto does not re-apply patches in $onto' '
+ git checkout C &&
+ test_commit C2 C.t &&
+ git checkout -B my-topic-branch master &&
+ test_commit D &&
+ git rebase --onto C2 A2 &&
+ test "$(git log --format=%s C2..)" = D
+'
+
+test_expect_success 'rebase --onto does not lose patches in $upstream' '
+ git rebase --onto A2 D &&
+ test "$(git log --format=%s A2..)" = "D
+C2
+C
+B"
+'
+
test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 6898377..3eecc66 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -5,8 +5,10 @@ test_description='messages from rebase operation'
. ./test-lib.sh
quick_one () {
- echo "$1" >"file$1" &&
- git add "file$1" &&
+ fileno=$2
+ test -z "$fileno" && fileno=$1
+ echo "$1" >"file$fileno" &&
+ git add "file$fileno" &&
test_tick &&
git commit -m "$1"
}
@@ -16,21 +18,19 @@ test_expect_success setup '
git branch topic &&
quick_one X &&
quick_one A &&
- quick_one B &&
+ quick_one B A &&
quick_one Y &&
git checkout topic &&
quick_one A &&
- quick_one B &&
+ quick_one B A &&
quick_one Z &&
git tag start
'
cat >expect <<\EOF
-Already applied: 0001 A
-Already applied: 0002 B
-Committed: 0003 Z
+Committed: 0001 Z
EOF
test_expect_success 'rebase -m' '
--
1.7.9.3.327.g2980b
next prev parent reply other threads:[~2012-06-26 14:52 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-26 14:51 [PATCH 0/5] rebase: calculate patches in upstream correctly Martin von Zweigbergk
2012-06-26 14:51 ` [PATCH 1/5] rebase: don't source git-sh-setup twice Martin von Zweigbergk
2012-06-26 14:51 ` [PATCH 2/5] rebase --root: print usage on too many args Martin von Zweigbergk
2012-06-26 14:51 ` [PATCH 3/5] am --rebasing: get patch body from commit, not from mailbox Martin von Zweigbergk
2012-06-26 14:51 ` [PATCH 4/5] am: don't call mailinfo if $rebasing Martin von Zweigbergk
2012-06-26 14:51 ` Martin von Zweigbergk [this message]
2012-06-26 21:13 ` [PATCH 5/5] rebase [-m]: calculate patches in upstream correctly Junio C Hamano
2012-06-27 16:17 ` Martin von Zweigbergk
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=1340722318-24392-6-git-send-email-martin.von.zweigbergk@gmail.com \
--to=martin.von.zweigbergk@gmail.com \
--cc=git@vger.kernel.org \
/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).