Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2018-02-14 21:18:55 +0300
committerJunio C Hamano <gitster@pobox.com>2018-02-16 22:22:43 +0300
commitadcc94a0aa7055be4133ebda8b25f4af63285c6d (patch)
tree1411bcf159e21cf3fa6d6551d9aaa132025cdf62 /builtin
parentb2e45c695d09f6a31ce09347ae0a5d2cdfe9dd4e (diff)
merge: allow fast-forward when merging a tracked tag
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>
Diffstat (limited to 'builtin')
-rw-r--r--builtin/merge.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/builtin/merge.c b/builtin/merge.c
index 30264cfd7c..532522a854 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,43 @@ static struct commit_list *collect_parents(struct commit *head_commit,
return remoteheads;
}
+static int merging_a_throwaway_tag(struct commit *commit)
+{
+ char *tag_ref;
+ struct object_id oid;
+ int is_throwaway_tag = 0;
+
+ /* Are we merging a tag? */
+ if (!merge_remote_util(commit) ||
+ !merge_remote_util(commit)->obj ||
+ merge_remote_util(commit)->obj->type != OBJ_TAG)
+ return is_throwaway_tag;
+
+ /*
+ * 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.
+ *
+ * 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.
+ */
+ 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))
+ is_throwaway_tag = 0;
+ else
+ is_throwaway_tag = 1;
+ free(tag_ref);
+ return is_throwaway_tag;
+}
+
int cmd_merge(int argc, const char **argv, const char *prefix)
{
struct object_id result_tree, stash, head_oid;
@@ -1322,10 +1360,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;
}