merge: make usage of commit->util more extensible

The merge-recursive code uses the commit->util field directly to annotate the commit objects given from the command line, i.e. the remote heads to be merged, with a single string to be used to describe it in its trace messages and conflict markers. Correct this short-signtedness by redefining the field to be a pointer to a structure "struct merge_remote_desc" that later enhancements can add more information. Store the original objects we were told to merge in a field "obj" in this struct, so that we can recover the tag we were told to merge. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Nov 7, 2011 at 13:26 UTC ae8e4c9ce10ea9439a88b79a40aeff4696d40416
4 files changed +61 -47
builtin/merge.c
+23 -40
@@ -406,20 +406,10 @@ static void finish(struct commit *head_commit,
406 strbuf_release(&reflog_message);
407 }
408
409 -static struct object *want_commit(const char *name)
410 -{
411 - struct object *obj;
412 - unsigned char sha1[20];
413 - if (get_sha1(name, sha1))
414 - return NULL;
415 - obj = parse_object(sha1);
416 - return peel_to_type(name, 0, obj, OBJ_COMMIT);
417 -}
418 -
409 /* Get the name for the merge commit's message. */
410 static void merge_name(const char *remote, struct strbuf *msg)
411 {
422 - struct object *remote_head;
412 + struct commit *remote_head;
413 unsigned char branch_head[20], buf_sha[20];
414 struct strbuf buf = STRBUF_INIT;
415 struct strbuf bname = STRBUF_INIT;
@@ -431,7 +421,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
421 remote = bname.buf;
422
423 memset(branch_head, 0, sizeof(branch_head));
434 - remote_head = want_commit(remote);
424 + remote_head = get_merge_parent(remote);
425 if (!remote_head)
426 die(_("'%s' does not point to a commit"), remote);
427
@@ -487,7 +477,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
477 if (resolve_ref(truname.buf, buf_sha, 1, NULL)) {
478 strbuf_addf(msg,
479 "%s\t\tbranch '%s'%s of .\n",
490 - sha1_to_hex(remote_head->sha1),
480 + sha1_to_hex(remote_head->object.sha1),
481 truname.buf + 11,
482 (early ? " (early part)" : ""));
483 strbuf_release(&truname);
@@ -515,7 +505,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
505 goto cleanup;
506 }
507 strbuf_addf(msg, "%s\t\tcommit '%s'\n",
518 - sha1_to_hex(remote_head->sha1), remote);
508 + sha1_to_hex(remote_head->object.sha1), remote);
509 cleanup:
510 strbuf_release(&buf);
511 strbuf_release(&bname);
@@ -719,7 +709,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
709 die(_("Unknown option for merge-recursive: -X%s"), xopts[x]);
710
711 o.branch1 = head_arg;
722 - o.branch2 = remoteheads->item->util;
712 + o.branch2 = merge_remote_util(remoteheads->item)->name;
713
714 for (j = common; j; j = j->next)
715 commit_list_insert(j->item, &reversed);
@@ -1190,7 +1180,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1180 argv += 2;
1181 argc -= 2;
1182 } else if (!head_commit) {
1193 - struct object *remote_head;
1183 + struct commit *remote_head;
1184 /*
1185 * If the merged head is a valid one there is no reason
1186 * to forbid "git merge" into a branch yet to be born.
@@ -1204,12 +1194,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1194 if (!allow_fast_forward)
1195 die(_("Non-fast-forward commit does not make sense into "
1196 "an empty head"));
1207 - remote_head = want_commit(argv[0]);
1197 + remote_head = get_merge_parent(argv[0]);
1198 if (!remote_head)
1199 die(_("%s - not something we can merge"), argv[0]);
1210 - read_empty(remote_head->sha1, 0);
1211 - update_ref("initial pull", "HEAD", remote_head->sha1, NULL, 0,
1212 - DIE_ON_ERR);
1200 + read_empty(remote_head->object.sha1, 0);
1201 + update_ref("initial pull", "HEAD", remote_head->object.sha1,
1202 + NULL, 0, DIE_ON_ERR);
1203 return 0;
1204 } else {
1205 struct strbuf merge_names = STRBUF_INIT;
@@ -1218,12 +1208,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1208 head_arg = "HEAD";
1209
1210 /*
1221 - * All the rest are the commits being merged;
1222 - * prepare the standard merge summary message to
1223 - * be appended to the given message. If remote
1224 - * is invalid we will die later in the common
1225 - * codepath so we discard the error in this
1226 - * loop.
1211 + * All the rest are the commits being merged; prepare
1212 + * the standard merge summary message to be appended
1213 + * to the given message.
1214 */
1215 for (i = 0; i < argc; i++)
1216 merge_name(argv[i], &merge_names);
@@ -1251,17 +1238,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1238 strbuf_reset(&buf);
1239
1240 for (i = 0; i < argc; i++) {
1254 - struct object *o;
1255 - struct commit *commit;
1256 -
1257 - o = want_commit(argv[i]);
1258 - if (!o)
1241 + struct commit *commit = get_merge_parent(argv[i]);
1242 + if (!commit)
1243 die(_("%s - not something we can merge"), argv[i]);
1260 - commit = lookup_commit(o->sha1);
1261 - commit->util = (void *)argv[i];
1244 remotes = &commit_list_insert(commit, remotes)->next;
1263 -
1264 - strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1));
1245 + strbuf_addf(&buf, "GITHEAD_%s",
1246 + sha1_to_hex(commit->object.sha1));
1247 setenv(buf.buf, argv[i], 1);
1248 strbuf_reset(&buf);
1249 }
@@ -1307,7 +1289,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1289 !hashcmp(common->item->object.sha1, head_commit->object.sha1)) {
1290 /* Again the most common case of merging one remote. */
1291 struct strbuf msg = STRBUF_INIT;
1310 - struct object *o;
1292 + struct commit *commit;
1293 char hex[41];
1294
1295 strcpy(hex, find_unique_abbrev(head_commit->object.sha1, DEFAULT_ABBREV));
@@ -1321,14 +1303,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1303 if (have_message)
1304 strbuf_addstr(&msg,
1305 " (no commit created; -m option ignored)");
1324 - o = want_commit(sha1_to_hex(remoteheads->item->object.sha1));
1325 - if (!o)
1306 + commit = remoteheads->item;
1307 + if (!commit)
1308 return 1;
1309
1328 - if (checkout_fast_forward(head_commit->object.sha1, remoteheads->item->object.sha1))
1310 + if (checkout_fast_forward(head_commit->object.sha1,
1311 + commit->object.sha1))
1312 return 1;
1313
1331 - finish(head_commit, o->sha1, msg.buf);
1314 + finish(head_commit, commit->object.sha1, msg.buf);
1315 drop_save();
1316 return 0;
1317 } else if (!remoteheads->next && common->next)
commit.c
+19
@@ -894,3 +894,22 @@ int commit_tree(const char *msg, unsigned char *tree,
894 strbuf_release(&buffer);
895 return result;
896 }
897 +
898 +struct commit *get_merge_parent(const char *name)
899 +{
900 + struct object *obj;
901 + struct commit *commit;
902 + unsigned char sha1[20];
903 + if (get_sha1(name, sha1))
904 + return NULL;
905 + obj = parse_object(sha1);
906 + commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
907 + if (commit && !commit->util) {
908 + struct merge_remote_desc *desc;
909 + desc = xmalloc(sizeof(*desc));
910 + desc->obj = obj;
911 + desc->name = strdup(name);
912 + commit->util = desc;
913 + }
914 + return commit;
915 +}
commit.h
+13
@@ -185,4 +185,17 @@ extern int commit_tree(const char *msg, unsigned char *tree,
185 struct commit_list *parents, unsigned char *ret,
186 const char *author);
187
188 +struct merge_remote_desc {
189 + struct object *obj; /* the named object, could be a tag */
190 + const char *name;
191 +};
192 +#define merge_remote_util(commit) ((struct merge_remote_desc *)((commit)->util))
193 +
194 +/*
195 + * Given "name" from the command line to merge, find the commit object
196 + * and return it, while storing merge_remote_desc in its ->util field,
197 + * to allow callers to tell if we are told to merge a tag.
198 + */
199 +struct commit *get_merge_parent(const char *name);
200 +
201 #endif /* COMMIT_H */
merge-recursive.c
+6 -7
@@ -38,16 +38,15 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
38 return lookup_tree(shifted);
39 }
40
41 -/*
42 - * A virtual commit has (const char *)commit->util set to the name.
43 - */
44 -
41 static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
42 {
43 struct commit *commit = xcalloc(1, sizeof(struct commit));
44 + struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
45 +
46 + desc->name = comment;
47 + desc->obj = (struct object *)commit;
48 commit->tree = tree;
49 - commit->util = (void*)comment;
50 - /* avoid warnings */
49 + commit->util = desc;
50 commit->object.parsed = 1;
51 return commit;
52 }
@@ -184,7 +183,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
183 for (i = o->call_depth; i--;)
184 fputs(" ", stdout);
185 if (commit->util)
187 - printf("virtual %s\n", (char *)commit->util);
186 + printf("virtual %s\n", merge_remote_util(commit)->name);
187 else {
188 printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
189 if (parse_commit(commit) != 0)