From 62b6f48388faf0ac2432a07cfc53aa904c591f8f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 11 Jan 2007 22:21:38 -0500 Subject: [PATCH] Support creation of merge commits in fast-import. Some importers are able to determine when branch merges occurred within their source data. In these cases they will want to supply the correct commits to fast-import so that a proper merge commit will exist in Git. This is now supported by supplying a 'merge ' command after the commit message and optional from command. A merge is not actually performed by fast-import, its assumed that the frontend performed any sort of merging activity already and that fast-import should simply be storing its result. Signed-off-by: Shawn O. Pearce --- fast-import.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/fast-import.c b/fast-import.c index e9a46c6c3a..15db4b39d1 100644 --- a/fast-import.c +++ b/fast-import.c @@ -20,6 +20,7 @@ Format of STDIN stream: 'committer' sp name '<' email '>' ts tz lf commit_msg ('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)? + ('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)* file_change* lf; commit_msg ::= data; @@ -202,6 +203,11 @@ struct dbuf size_t capacity; }; +struct hash_list +{ + struct hash_list *next; + unsigned char sha1[20]; +}; /* Stats and misc. counters */ static unsigned long max_depth = 10; @@ -1502,6 +1508,48 @@ static void cmd_from(struct branch *b) read_next_command(); } +static struct hash_list* cmd_merge(unsigned int *count) +{ + struct hash_list *list = NULL, *n, *e; + const char *from, *endp; + char *str_uq; + struct branch *s; + + *count = 0; + while (!strncmp("merge ", command_buf.buf, 6)) { + from = strchr(command_buf.buf, ' ') + 1; + str_uq = unquote_c_style(from, &endp); + if (str_uq) { + if (*endp) + die("Garbage after string in: %s", command_buf.buf); + from = str_uq; + } + + n = xmalloc(sizeof(*n)); + s = lookup_branch(from); + if (s) + hashcpy(n->sha1, s->sha1); + else if (*from == ':') { + unsigned long idnum = strtoul(from + 1, NULL, 10); + struct object_entry *oe = find_mark(idnum); + if (oe->type != OBJ_COMMIT) + die("Mark :%lu not a commit", idnum); + hashcpy(n->sha1, oe->sha1); + } else if (get_sha1(from, n->sha1)) + die("Invalid ref name or SHA1 expression: %s", from); + + n->next = NULL; + if (list) + e->next = n; + else + list = n; + e = n; + *count++; + read_next_command(); + } + return list; +} + static void cmd_new_commit() { struct branch *b; @@ -1512,6 +1560,8 @@ static void cmd_new_commit() char *sp; char *author = NULL; char *committer = NULL; + struct hash_list *merge_list = NULL; + unsigned int merge_count; /* Obtain the branch name from the rest of our command */ sp = strchr(command_buf.buf, ' ') + 1; @@ -1542,6 +1592,7 @@ static void cmd_new_commit() msg = cmd_data(&msglen); read_next_command(); cmd_from(b); + merge_list = cmd_merge(&merge_count); /* ensure the branch is active/loaded */ if (!b->branch_tree.tree || !max_active_branches) { @@ -1567,6 +1618,7 @@ static void cmd_new_commit() hashcpy(b->branch_tree.versions[0].sha1, b->branch_tree.versions[1].sha1); size_dbuf(&new_data, 97 + msglen + + merge_count * 49 + (author ? strlen(author) + strlen(committer) : 2 * strlen(committer))); @@ -1575,6 +1627,12 @@ static void cmd_new_commit() sha1_to_hex(b->branch_tree.versions[1].sha1)); if (!is_null_sha1(b->sha1)) sp += sprintf(sp, "parent %s\n", sha1_to_hex(b->sha1)); + while (merge_list) { + struct hash_list *next = merge_list->next; + sp += sprintf(sp, "parent %s\n", sha1_to_hex(merge_list->sha1)); + free(merge_list); + merge_list = next; + } if (author) sp += sprintf(sp, "%s\n", author); else