in src/merge.c [2666:2780]
static int write_merge_msg(
git_repository *repo,
const git_annotated_commit *heads[],
size_t heads_len)
{
git_filebuf file = GIT_FILEBUF_INIT;
git_buf file_path = GIT_BUF_INIT;
struct merge_msg_entry *entries;
git_vector matching = GIT_VECTOR_INIT;
size_t i;
char sep = 0;
int error = 0;
assert(repo && heads);
entries = git__calloc(heads_len, sizeof(struct merge_msg_entry));
GIT_ERROR_CHECK_ALLOC(entries);
if (git_vector_init(&matching, heads_len, NULL) < 0) {
git__free(entries);
return -1;
}
for (i = 0; i < heads_len; i++)
entries[i].merge_head = heads[i];
if ((error = git_buf_joinpath(&file_path, repo->gitdir, GIT_MERGE_MSG_FILE)) < 0 ||
(error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) < 0 ||
(error = git_filebuf_write(&file, "Merge ", 6)) < 0)
goto cleanup;
/*
* This is to emulate the format of MERGE_MSG by core git.
*
* Core git will write all the commits specified by OID, in the order
* provided, until the first named branch or tag is reached, at which
* point all branches will be written in the order provided, then all
* tags, then all remote tracking branches and finally all commits that
* were specified by OID that were not already written.
*
* Yes. Really.
*/
for (i = 0; i < heads_len; i++) {
if (!msg_entry_is_oid(&entries[i]))
break;
if ((error = git_filebuf_printf(&file,
"%scommit '%s'", (i > 0) ? "; " : "",
entries[i].merge_head->id_str)) < 0)
goto cleanup;
entries[i].written = 1;
}
if (i)
sep = ';';
if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_branch)) < 0 ||
(error = merge_msg_write_branches(&file, &matching, sep)) < 0)
goto cleanup;
if (matching.length)
sep =',';
if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tracking)) < 0 ||
(error = merge_msg_write_tracking(&file, &matching, sep)) < 0)
goto cleanup;
if (matching.length)
sep =',';
if ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_tag)) < 0 ||
(error = merge_msg_write_tags(&file, &matching, sep)) < 0)
goto cleanup;
if (matching.length)
sep =',';
/* We should never be called with multiple remote branches, but handle
* it in case we are... */
while ((error = merge_msg_entries(&matching, entries, heads_len, msg_entry_is_remote)) > 0) {
if ((error = merge_msg_write_remotes(&file, &matching, sep)) < 0)
goto cleanup;
if (matching.length)
sep =',';
}
if (error < 0)
goto cleanup;
for (i = 0; i < heads_len; i++) {
if (merge_msg_entry_written(&entries[i]))
continue;
if ((error = git_filebuf_printf(&file, "; commit '%s'",
entries[i].merge_head->id_str)) < 0)
goto cleanup;
}
if ((error = git_filebuf_printf(&file, "\n")) < 0 ||
(error = git_filebuf_commit(&file)) < 0)
goto cleanup;
cleanup:
if (error < 0)
git_filebuf_cleanup(&file);
git_buf_dispose(&file_path);
git_vector_free(&matching);
git__free(entries);
return error;
}