diff options
author | Johan Herland <johan@herland.net> | 2010-11-09 22:49:52 +0100 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2010-11-17 13:22:49 -0800 |
commit | 6abb3655efe364cf0375b5cdae2729af7562ed45 (patch) | |
tree | 71cd673957836ee63fd0a3ca6271dab5716d9454 /notes-merge.c | |
parent | git notes merge: Manual conflict resolution, part 1/2 (diff) | |
download | tgif-6abb3655efe364cf0375b5cdae2729af7562ed45.tar.xz |
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>
Diffstat (limited to 'notes-merge.c')
-rw-r--r-- | notes-merge.c | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/notes-merge.c b/notes-merge.c index ada29067bd..a2feab6d1b 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -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; +} |