cache-tree: convert write_*_as_tree to object_id
[gitweb.git] / builtin / merge.c
index 92ba99a1a5efff8598251c2ed806bae12832ae0a..0c7437f53677b6cef7e9d65334aa93fe3b052f76 100644 (file)
@@ -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)
@@ -520,7 +521,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
                if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
                        strbuf_addf(msg, "%s\t\t%s '%s'\n",
                                    oid_to_hex(&desc->obj->oid),
-                                   typename(desc->obj->type),
+                                   type_name(desc->obj->type),
                                    remote);
                        goto cleanup;
                }
@@ -638,7 +639,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
 
 static void write_tree_trivial(struct object_id *oid)
 {
-       if (write_cache_as_tree(oid->hash, 0, NULL))
+       if (write_cache_as_tree(oid, 0, NULL))
                die(_("git write-tree failed to write a tree"));
 }
 
@@ -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;
        }