commit: convert mergetag before computing the signature of a commit

It so happens that commit mergetag lines embed a tag object. So to compute the compatible signature of a commit object that has mergetag lines the compatible embedded tag must be computed first. Implement this by duplicating and converting the commit extra headers into the compatible version of the commit extra headers, that need to be passed to commit_tree_extended. To handle merge tags only the compatible extra headers need to be computed. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric W. Biederman committed Oct 1, 2023 at 21:40 UTC a3e8ae5473942c0d2621c5936685b6d98e63f006
1 file changed +41 -1
commit.c
+41 -1
@@ -1355,6 +1355,39 @@ void append_merge_tag_headers(struct commit_list *parents,
1355 }
1356 }
1357
1358 +static int convert_commit_extra_headers(struct commit_extra_header *orig,
1359 + struct commit_extra_header **result)
1360 +{
1361 + const struct git_hash_algo *compat = the_repository->compat_hash_algo;
1362 + const struct git_hash_algo *algo = the_repository->hash_algo;
1363 + struct commit_extra_header *extra = NULL, **tail = &extra;
1364 + struct strbuf out = STRBUF_INIT;
1365 + while (orig) {
1366 + struct commit_extra_header *new;
1367 + CALLOC_ARRAY(new, 1);
1368 + if (!strcmp(orig->key, "mergetag")) {
1369 + if (convert_object_file(&out, algo, compat,
1370 + orig->value, orig->len,
1371 + OBJ_TAG, 1)) {
1372 + free(new);
1373 + free_commit_extra_headers(extra);
1374 + return -1;
1375 + }
1376 + new->key = xstrdup("mergetag");
1377 + new->value = strbuf_detach(&out, &new->len);
1378 + } else {
1379 + new->key = xstrdup(orig->key);
1380 + new->len = orig->len;
1381 + new->value = xmemdupz(orig->value, orig->len);
1382 + }
1383 + *tail = new;
1384 + tail = &new->next;
1385 + orig = orig->next;
1386 + }
1387 + *result = extra;
1388 + return 0;
1389 +}
1390 +
1391 static void add_extra_header(struct strbuf *buffer,
1392 struct commit_extra_header *extra)
1393 {
@@ -1679,6 +1712,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1712 goto out;
1713 }
1714 if (r->compat_hash_algo) {
1715 + struct commit_extra_header *compat_extra = NULL;
1716 struct object_id mapped_tree;
1717 struct object_id *mapped_parents;
1718
@@ -1695,8 +1729,14 @@ int commit_tree_extended(const char *msg, size_t msg_len,
1729 free(mapped_parents);
1730 goto out;
1731 }
1732 + if (convert_commit_extra_headers(extra, &compat_extra)) {
1733 + result = -1;
1734 + free(mapped_parents);
1735 + goto out;
1736 + }
1737 write_commit_tree(&compat_buffer, msg, msg_len, &mapped_tree,
1699 - mapped_parents, nparents, author, committer, extra);
1738 + mapped_parents, nparents, author, committer, compat_extra);
1739 + free_commit_extra_headers(compat_extra);
1740 free(mapped_parents);
1741
1742 if (sign_commit && sign_commit_to_strbuf(&compat_sig, &compat_buffer, sign_commit)) {