From: Junio C Hamano <gitster@pobox.com>
To: Git Mailing List <git@vger.kernel.org>
Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com>,
Linus Torvalds <torvalds@linux-foundation.org>
Subject: [PATCH] merge: allow fast-forward when merging a tracked tag
Date: Thu, 15 Feb 2018 14:45:51 -0800 [thread overview]
Message-ID: <xmqqy3jt7ty8.fsf_-_@gitster-ct.c.googlers.com> (raw)
In-Reply-To: <xmqqfu63o2xv.fsf@gitster-ct.c.googlers.com> (Junio C. Hamano's message of "Wed, 14 Feb 2018 10:12:44 -0800")
Long time ago at fab47d05 ("merge: force edit and no-ff mode when
merging a tag object", 2011-11-07), "git merge" was made to always
create a merge commit when merging a tag, even when the side branch
being merged is a descendant of the current branch.
This default is good for merges made by upstream maintainers to
integrate work signed by downstream contributors, but will leave
pointless no-ff merges when downstream contributors pull a newer
release tag to make their long-running topic branches catch up with
the upstream. When there is no local work left on the topic, such a
merge should simply fast-forward to the commit pointed at by the
release tag.
Update the default (again) for "git merge" that merges a tag object
to (1) --no-ff (i.e. create a merge commit even when side branch
fast forwards) if the tag being merged is not at its expected place
in refs/tags/ hierarchy and (2) --ff (i.e. allow fast-forward update
when able) otherwise.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
> There are a few fallouts in the testsuite if we go this route. I am
> not quite decided if I like the approach.
This time with a few tests for the new default, and minimum
adjustement to the documentation.
Documentation/merge-options.txt | 3 ++-
builtin/merge.c | 42 +++++++++++++++++++++++++++++++++++++----
t/t6200-fmt-merge-msg.sh | 2 +-
t/t7600-merge.sh | 38 ++++++++++++++++++++++++++++++++++++-
4 files changed, 78 insertions(+), 7 deletions(-)
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 3888c3ff85..63a3fc0954 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -35,7 +35,8 @@ set to `no` at the beginning of them.
--no-ff::
Create a merge commit even when the merge resolves as a
fast-forward. This is the default behaviour when merging an
- annotated (and possibly signed) tag.
+ annotated (and possibly signed) tag that is not stored in
+ its natural place in 'refs/tags/' hierarchy.
--ff-only::
Refuse to merge and exit with a non-zero status unless the
diff --git a/builtin/merge.c b/builtin/merge.c
index 30264cfd7c..45c7916505 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -33,6 +33,7 @@
#include "sequencer.h"
#include "string-list.h"
#include "packfile.h"
+#include "tag.h"
#define DEFAULT_TWOHEAD (1<<0)
#define DEFAULT_OCTOPUS (1<<1)
@@ -1125,6 +1126,42 @@ static struct commit_list *collect_parents(struct commit *head_commit,
return remoteheads;
}
+static int merging_a_throwaway_tag(struct commit *commit)
+{
+ const char *tag_ref;
+ struct object_id oid;
+
+ /* Are we merging a tag? */
+ if (!merge_remote_util(commit) ||
+ !merge_remote_util(commit)->obj ||
+ merge_remote_util(commit)->obj->type != OBJ_TAG)
+ return 0;
+
+ /*
+ * Now we know we are merging a tag object. Are we downstream
+ * and following the tags from upstream? If so, we must have
+ * the tag object pointed at by "refs/tags/$T" where $T is the
+ * tagname recorded in the tag object. We want to allow such
+ * a "just to catch up" merge to fast-forward.
+ */
+ tag_ref = xstrfmt("refs/tags/%s",
+ ((struct tag *)merge_remote_util(commit)->obj)->tag);
+
+ if (!read_ref(tag_ref, &oid) &&
+ !oidcmp(&oid, &merge_remote_util(commit)->obj->oid))
+ return 0;
+
+ /*
+ * Otherwise, we are playing an integrator's role, making a
+ * merge with a throw-away tag from a contributor with
+ * something like "git pull $contributor $signed_tag".
+ * We want to forbid such a merge from fast-forwarding
+ * by default; otherwise we would not keep the signature
+ * anywhere.
+ */
+ return 1;
+}
+
int cmd_merge(int argc, const char **argv, const char *prefix)
{
struct object_id result_tree, stash, head_oid;
@@ -1322,10 +1359,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
oid_to_hex(&commit->object.oid));
setenv(buf.buf, merge_remote_util(commit)->name, 1);
strbuf_reset(&buf);
- if (fast_forward != FF_ONLY &&
- merge_remote_util(commit) &&
- merge_remote_util(commit)->obj &&
- merge_remote_util(commit)->obj->type == OBJ_TAG)
+ if (fast_forward != FF_ONLY && merging_a_throwaway_tag(commit))
fast_forward = FF_NO;
}
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 2e2fb0e957..a54a52aaa4 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -512,7 +512,7 @@ test_expect_success 'merge-msg with "merging" an annotated tag' '
test_when_finished "git reset --hard" &&
annote=$(git rev-parse annote) &&
- git merge --no-commit $annote &&
+ git merge --no-commit --no-ff $annote &&
{
cat <<-EOF
Merge tag '\''$annote'\''
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index dfde6a675a..6736d8d131 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -700,6 +700,42 @@ test_expect_success 'merge --no-ff --edit' '
test_cmp expected actual
'
+test_expect_success 'merge annotated/signed tag w/o tracking' '
+ test_when_finished "rm -rf dst; git tag -d anno1" &&
+ git tag -a -m "anno c1" anno1 c1 &&
+ git init dst &&
+ git rev-parse c1 >dst/expect &&
+ (
+ # c0 fast-forwards to c1 but because this repository
+ # is not a "downstream" whose refs/tags follows along
+ # tag from the "upstream", this pull defaults to --no-ff
+ cd dst &&
+ git pull .. c0 &&
+ git pull .. anno1 &&
+ git rev-parse HEAD^2 >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'merge annotated/signed tag w/ tracking' '
+ test_when_finished "rm -rf dst; git tag -d anno1" &&
+ git tag -a -m "anno c1" anno1 c1 &&
+ git init dst &&
+ git rev-parse c1 >dst/expect &&
+ (
+ # c0 fast-forwards to c1 and because this repository
+ # is a "downstream" whose refs/tags follows along
+ # tag from the "upstream", this pull defaults to --ff
+ cd dst &&
+ git remote add origin .. &&
+ git pull origin c0 &&
+ git fetch origin &&
+ git merge anno1 &&
+ git rev-parse HEAD >actual &&
+ test_cmp expect actual
+ )
+'
+
test_expect_success GPG 'merge --ff-only tag' '
git reset --hard c0 &&
git commit --allow-empty -m "A newer commit" &&
@@ -718,7 +754,7 @@ test_expect_success GPG 'merge --no-edit tag should skip editor' '
git tag -f -s -m "A newer commit" signed &&
git reset --hard c0 &&
- EDITOR=false git merge --no-edit signed &&
+ EDITOR=false git merge --no-edit --no-ff signed &&
git rev-parse signed^0 >expect &&
git rev-parse HEAD^2 >actual &&
test_cmp expect actual
--
2.16.1-194-gb2e45c695d
next prev parent reply other threads:[~2018-02-15 22:45 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20180213080036.3bf3a908@canb.auug.org.au>
2018-02-12 21:15 ` linux-next: unnecessary merge in the v4l-dvb tree Linus Torvalds
2018-02-12 21:36 ` Mauro Carvalho Chehab
2018-02-12 21:37 ` Linus Torvalds
2018-02-12 21:44 ` Junio C Hamano
2018-02-12 21:59 ` Linus Torvalds
2018-02-12 23:42 ` Junio C Hamano
2018-02-13 0:21 ` Mauro Carvalho Chehab
2018-02-13 17:18 ` Junio C Hamano
2018-02-13 17:33 ` Linus Torvalds
2018-02-14 18:12 ` Junio C Hamano
2018-02-15 22:45 ` Junio C Hamano [this message]
2018-02-15 23:34 ` [PATCH] merge: allow fast-forward when merging a tracked tag Eric Sunshine
2018-02-16 18:06 ` Junio C Hamano
2018-02-16 21:27 ` [PATCH v2] " Junio C Hamano
2018-02-12 21:37 ` linux-next: unnecessary merge in the v4l-dvb tree Junio C Hamano
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
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqqy3jt7ty8.fsf_-_@gitster-ct.c.googlers.com \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=mchehab@osg.samsung.com \
--cc=torvalds@linux-foundation.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.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
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 read-only IMAP folder(s) and NNTP newsgroup(s).