1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-09 13:46:08 +02:00

commit: copy merged signed tags to headers of merge commit

Now MERGE_HEAD records the tag objects without peeling, we could record
the result of manual conflict resolution via "git commit" without losing
the tag information. Introduce a new "mergetag" multi-line header field to
the commit object, and use it to store the entire contents of each signed
tag merged.

A commit header that has a multi-line payload begins with the header tag
(e.g. "mergetag" in this case), SP, the first line of payload, LF, and all
the remaining lines have a SP inserted at the beginning.

In hindsight, it would have been better to make "merge --continue" as the
way to continue from such an interrupted merge, not "commit", but this is
a backward compatibility baggage we would need to carry around for now.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2011-11-07 16:21:32 -08:00
parent 274a5c06d5
commit 5231c633f2
3 changed files with 116 additions and 11 deletions

View File

@ -1425,7 +1425,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
pptr = &commit_list_insert(c->item, pptr)->next; pptr = &commit_list_insert(c->item, pptr)->next;
} else if (whence == FROM_MERGE) { } else if (whence == FROM_MERGE) {
struct strbuf m = STRBUF_INIT; struct strbuf m = STRBUF_INIT;
struct commit *commit;
FILE *fp; FILE *fp;
if (!reflog_msg) if (!reflog_msg)
@ -1436,11 +1435,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
die_errno(_("could not open '%s' for reading"), die_errno(_("could not open '%s' for reading"),
git_path("MERGE_HEAD")); git_path("MERGE_HEAD"));
while (strbuf_getline(&m, fp, '\n') != EOF) { while (strbuf_getline(&m, fp, '\n') != EOF) {
unsigned char sha1[20]; struct commit *parent;
if (get_sha1_hex(m.buf, sha1) < 0)
parent = get_merge_parent(m.buf);
if (!parent)
die(_("Corrupt MERGE_HEAD file (%s)"), m.buf); die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
commit = lookup_commit_or_die(sha1, "MERGE_HEAD"); pptr = &commit_list_insert(parent, pptr)->next;
pptr = &commit_list_insert(commit, pptr)->next;
} }
fclose(fp); fclose(fp);
strbuf_release(&m); strbuf_release(&m);

View File

@ -840,14 +840,95 @@ struct commit_list *reduce_heads(struct commit_list *heads)
return result; return result;
} }
static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
{
struct merge_remote_desc *desc;
struct commit_extra_header *mergetag;
char *buf;
unsigned long size, len;
enum object_type type;
desc = merge_remote_util(parent);
if (!desc || !desc->obj)
return;
buf = read_sha1_file(desc->obj->sha1, &type, &size);
if (!buf || type != OBJ_TAG)
goto free_return;
len = parse_signature(buf, size);
if (size == len)
goto free_return;
/*
* We could verify this signature and either omit the tag when
* it does not validate, but the integrator may not have the
* public key of the signer of the tag he is merging, while a
* later auditor may have it while auditing, so let's not run
* verify-signed-buffer here for now...
*
* if (verify_signed_buffer(buf, len, buf + len, size - len, ...))
* warn("warning: signed tag unverified.");
*/
mergetag = xcalloc(1, sizeof(*mergetag));
mergetag->key = xstrdup("mergetag");
mergetag->value = buf;
mergetag->len = size;
**tail = mergetag;
*tail = &mergetag->next;
return;
free_return:
free(buf);
}
void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail)
{
while (parents) {
struct commit *parent = parents->item;
handle_signed_tag(parent, tail);
parents = parents->next;
}
}
static void add_extra_header(struct strbuf *buffer,
struct commit_extra_header *extra)
{
strbuf_addstr(buffer, extra->key);
strbuf_add_lines(buffer, " ", extra->value, extra->len);
}
void free_commit_extra_headers(struct commit_extra_header *extra)
{
while (extra) {
struct commit_extra_header *next = extra->next;
free(extra->key);
free(extra->value);
free(extra);
extra = next;
}
}
int commit_tree(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author)
{
struct commit_extra_header *extra = NULL, **tail = &extra;
int result;
append_merge_tag_headers(parents, &tail);
result = commit_tree_extended(msg, tree, parents, ret, author, extra);
free_commit_extra_headers(extra);
return result;
}
static const char commit_utf8_warn[] = static const char commit_utf8_warn[] =
"Warning: commit message does not conform to UTF-8.\n" "Warning: commit message does not conform to UTF-8.\n"
"You may want to amend it after fixing the message, or set the config\n" "You may want to amend it after fixing the message, or set the config\n"
"variable i18n.commitencoding to the encoding your project uses.\n"; "variable i18n.commitencoding to the encoding your project uses.\n";
int commit_tree(const char *msg, unsigned char *tree, int commit_tree_extended(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret, struct commit_list *parents, unsigned char *ret,
const char *author) const char *author, struct commit_extra_header *extra)
{ {
int result; int result;
int encoding_is_utf8; int encoding_is_utf8;
@ -868,8 +949,10 @@ int commit_tree(const char *msg, unsigned char *tree,
*/ */
while (parents) { while (parents) {
struct commit_list *next = parents->next; struct commit_list *next = parents->next;
struct commit *parent = parents->item;
strbuf_addf(&buffer, "parent %s\n", strbuf_addf(&buffer, "parent %s\n",
sha1_to_hex(parents->item->object.sha1)); sha1_to_hex(parent->object.sha1));
free(parents); free(parents);
parents = next; parents = next;
} }
@ -881,6 +964,11 @@ int commit_tree(const char *msg, unsigned char *tree,
strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME));
if (!encoding_is_utf8) if (!encoding_is_utf8)
strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding); strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding);
while (extra) {
add_extra_header(&buffer, extra);
extra = extra->next;
}
strbuf_addch(&buffer, '\n'); strbuf_addch(&buffer, '\n');
/* And add the comment */ /* And add the comment */

View File

@ -181,9 +181,26 @@ static inline int single_parent(struct commit *commit)
struct commit_list *reduce_heads(struct commit_list *heads); struct commit_list *reduce_heads(struct commit_list *heads);
struct commit_extra_header {
struct commit_extra_header *next;
char *key;
char *value;
size_t len;
};
extern void append_merge_tag_headers(struct commit_list *parents,
struct commit_extra_header ***tail);
extern int commit_tree(const char *msg, unsigned char *tree, extern int commit_tree(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret, struct commit_list *parents, unsigned char *ret,
const char *author); const char *author);
extern int commit_tree_extended(const char *msg, unsigned char *tree,
struct commit_list *parents, unsigned char *ret,
const char *author,
struct commit_extra_header *);
extern void free_commit_extra_headers(struct commit_extra_header *extra);
struct merge_remote_desc { struct merge_remote_desc {
struct object *obj; /* the named object, could be a tag */ struct object *obj; /* the named object, could be a tag */