git notes merge: Manual conflict resolution, part 2/2
When the notes merge conflicts in .git/NOTES_MERGE_WORKTREE have been resolved, we need to record a new notes commit on the appropriate notes ref with the resolved notes. This patch implements 'git notes merge --commit' which the user should run after resolving conflicts in the notes merge worktree. This command finalizes the notes merge by recombining the partial notes tree from part 1 with the now-resolved conflicts in the notes merge worktree in a merge commit, and updating the appropriate ref to this merge commit. In order to correctly finalize the merge, we need to keep track of three things: - The partial merge result from part 1, containing the auto-merged notes. This is now stored into a ref called .git/NOTES_MERGE_PARTIAL. - The unmerged notes. These are already stored in .git/NOTES_MERGE_WORKTREE, thanks to part 1. - The notes ref to be updated by the finalized merge result. This is now stored in a symref called .git/NOTES_MERGE_REF. In addition to "git notes merge --commit", which uses the above details to create the finalized notes merge commit, this patch also implements "git notes merge --reset", which aborts the ongoing notes merge by simply removing the files/directory described above. FTR, "git notes merge --commit" reuses "git notes merge --reset" to remove the information described above (.git/NOTES_MERGE_*) after the notes merge have been successfully finalized. The patch also contains documentation and testcases for the two new options. This patch has been improved by the following contributions: - Ævar Arnfjörð Bjarmason: Fix nonsense sentence in --commit description - Sverre Rabbelier: Rename --reset to --abort Thanks-to: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Thanks-to: Sverre Rabbelier <srabbelier@gmail.com> Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
809f38c8ab
commit
6abb3655ef
@ -278,7 +278,7 @@ static void check_notes_merge_worktree(struct notes_merge_options *o)
|
||||
die("You have not concluded your previous "
|
||||
"notes merge (%s exists).\nPlease, use "
|
||||
"'git notes merge --commit' or 'git notes "
|
||||
"merge --reset' to commit/abort the "
|
||||
"merge --abort' to commit/abort the "
|
||||
"previous merge before you start a new "
|
||||
"notes merge.", git_path("NOTES_MERGE_*"));
|
||||
else
|
||||
@ -650,3 +650,72 @@ found_result:
|
||||
result, sha1_to_hex(result_sha1));
|
||||
return result;
|
||||
}
|
||||
|
||||
int notes_merge_commit(struct notes_merge_options *o,
|
||||
struct notes_tree *partial_tree,
|
||||
struct commit *partial_commit,
|
||||
unsigned char *result_sha1)
|
||||
{
|
||||
/*
|
||||
* Iterate through files in .git/NOTES_MERGE_WORKTREE and add all
|
||||
* found notes to 'partial_tree'. Write the updates notes tree to
|
||||
* the DB, and commit the resulting tree object while reusing the
|
||||
* commit message and parents from 'partial_commit'.
|
||||
* Finally store the new commit object SHA1 into 'result_sha1'.
|
||||
*/
|
||||
struct dir_struct dir;
|
||||
const char *path = git_path(NOTES_MERGE_WORKTREE "/");
|
||||
int path_len = strlen(path), i;
|
||||
const char *msg = strstr(partial_commit->buffer, "\n\n");
|
||||
|
||||
OUTPUT(o, 3, "Committing notes in notes merge worktree at %.*s",
|
||||
path_len - 1, path);
|
||||
|
||||
if (!msg || msg[2] == '\0')
|
||||
die("partial notes commit has empty message");
|
||||
msg += 2;
|
||||
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
read_directory(&dir, path, path_len, NULL);
|
||||
for (i = 0; i < dir.nr; i++) {
|
||||
struct dir_entry *ent = dir.entries[i];
|
||||
struct stat st;
|
||||
const char *relpath = ent->name + path_len;
|
||||
unsigned char obj_sha1[20], blob_sha1[20];
|
||||
|
||||
if (ent->len - path_len != 40 || get_sha1_hex(relpath, obj_sha1)) {
|
||||
OUTPUT(o, 3, "Skipping non-SHA1 entry '%s'", ent->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* write file as blob, and add to partial_tree */
|
||||
if (stat(ent->name, &st))
|
||||
die_errno("Failed to stat '%s'", ent->name);
|
||||
if (index_path(blob_sha1, ent->name, &st, 1))
|
||||
die("Failed to write blob object from '%s'", ent->name);
|
||||
if (add_note(partial_tree, obj_sha1, blob_sha1, NULL))
|
||||
die("Failed to add resolved note '%s' to notes tree",
|
||||
ent->name);
|
||||
OUTPUT(o, 4, "Added resolved note for object %s: %s",
|
||||
sha1_to_hex(obj_sha1), sha1_to_hex(blob_sha1));
|
||||
}
|
||||
|
||||
create_notes_commit(partial_tree, partial_commit->parents, msg,
|
||||
result_sha1);
|
||||
OUTPUT(o, 4, "Finalized notes merge commit: %s",
|
||||
sha1_to_hex(result_sha1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int notes_merge_abort(struct notes_merge_options *o)
|
||||
{
|
||||
/* Remove .git/NOTES_MERGE_WORKTREE directory and all files within */
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int ret;
|
||||
|
||||
strbuf_addstr(&buf, git_path(NOTES_MERGE_WORKTREE));
|
||||
OUTPUT(o, 3, "Removing notes merge worktree at %s", buf.buf);
|
||||
ret = remove_dir_recursively(&buf, 0);
|
||||
strbuf_release(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user