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)