27
"git notes [--ref <notes_ref>] edit [<object>]",
28
"git notes [--ref <notes_ref>] show [<object>]",
29
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
30
+ "git notes merge --commit [-v | -q]",
31
+ "git notes merge --abort [-v | -q]",
32
"git notes [--ref <notes_ref>] remove [<object>]",
33
"git notes [--ref <notes_ref>] prune [-n | -v]",
34
NULL
67
68
static const char * const git_notes_merge_usage[] = {
69
"git notes merge [<options>] <notes_ref>",
70
+ "git notes merge --commit [<options>]",
71
+ "git notes merge --abort [<options>]",
72
NULL
73
};
74
765
return retval;
766
}
767
768
+static int merge_abort(struct notes_merge_options *o)
769
+{
770
+ int ret = 0;
771
+
772
+ /*
773
+ * Remove .git/NOTES_MERGE_PARTIAL and .git/NOTES_MERGE_REF, and call
774
+ * notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
775
+ */
776
+
777
+ if (delete_ref("NOTES_MERGE_PARTIAL", NULL, 0))
778
+ ret += error("Failed to delete ref NOTES_MERGE_PARTIAL");
779
+ if (delete_ref("NOTES_MERGE_REF", NULL, REF_NODEREF))
780
+ ret += error("Failed to delete ref NOTES_MERGE_REF");
781
+ if (notes_merge_abort(o))
782
+ ret += error("Failed to remove 'git notes merge' worktree");
783
+ return ret;
784
+}
785
+
786
+static int merge_commit(struct notes_merge_options *o)
787
+{
788
+ struct strbuf msg = STRBUF_INIT;
789
+ unsigned char sha1[20];
790
+ struct notes_tree *t;
791
+ struct commit *partial;
792
+ struct pretty_print_context pretty_ctx;
793
+
794
+ /*
795
+ * Read partial merge result from .git/NOTES_MERGE_PARTIAL,
796
+ * and target notes ref from .git/NOTES_MERGE_REF.
797
+ */
798
+
799
+ if (get_sha1("NOTES_MERGE_PARTIAL", sha1))
800
+ die("Failed to read ref NOTES_MERGE_PARTIAL");
801
+ else if (!(partial = lookup_commit_reference(sha1)))
802
+ die("Could not find commit from NOTES_MERGE_PARTIAL.");
803
+ else if (parse_commit(partial))
804
+ die("Could not parse commit from NOTES_MERGE_PARTIAL.");
805
+
806
+ t = xcalloc(1, sizeof(struct notes_tree));
807
+ init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
808
+
809
+ o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, 0);
810
+ if (!o->local_ref)
811
+ die("Failed to resolve NOTES_MERGE_REF");
812
+
813
+ if (notes_merge_commit(o, t, partial, sha1))
814
+ die("Failed to finalize notes merge");
815
+
816
+ /* Reuse existing commit message in reflog message */
817
+ memset(&pretty_ctx, 0, sizeof(pretty_ctx));
818
+ format_commit_message(partial, "%s", &msg, &pretty_ctx);
819
+ strbuf_trim(&msg);
820
+ strbuf_insert(&msg, 0, "notes: ", 7);
821
+ update_ref(msg.buf, o->local_ref, sha1, NULL, 0, DIE_ON_ERR);
822
+
823
+ free_notes(t);
824
+ strbuf_release(&msg);
825
+ return merge_abort(o);
826
+}
827
+
828
static int merge(int argc, const char **argv, const char *prefix)
829
{
830
struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
831
unsigned char result_sha1[20];
832
struct notes_tree *t;
833
struct notes_merge_options o;
834
+ int do_merge = 0, do_commit = 0, do_abort = 0;
835
int verbosity = 0, result;
836
const char *strategy = NULL;
837
struct option options[] = {
838
+ OPT_GROUP("General options"),
839
OPT__VERBOSITY(&verbosity),
840
+ OPT_GROUP("Merge options"),
841
OPT_STRING('s', "strategy", &strategy, "strategy",
842
"resolve notes conflicts using the given "
843
"strategy (manual/ours/theirs/union)"),
844
+ OPT_GROUP("Committing unmerged notes"),
845
+ { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
846
+ "finalize notes merge by committing unmerged notes",
847
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG },
848
+ OPT_GROUP("Aborting notes merge resolution"),
849
+ { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
850
+ "abort notes merge",
851
+ PARSE_OPT_NOARG | PARSE_OPT_NONEG },
852
OPT_END()
853
};
854
855
argc = parse_options(argc, argv, prefix, options,
856
git_notes_merge_usage, 0);
857
783
- if (argc != 1) {
858
+ if (strategy || do_commit + do_abort == 0)
859
+ do_merge = 1;
860
+ if (do_merge + do_commit + do_abort != 1) {
861
+ error("cannot mix --commit, --abort or -s/--strategy");
862
+ usage_with_options(git_notes_merge_usage, options);
863
+ }
864
+
865
+ if (do_merge && argc != 1) {
866
error("Must specify a notes ref to merge");
867
usage_with_options(git_notes_merge_usage, options);
868
+ } else if (!do_merge && argc) {
869
+ error("too many parameters");
870
+ usage_with_options(git_notes_merge_usage, options);
871
}
872
873
init_notes_merge_options(&o);
874
o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;
875
876
+ if (do_abort)
877
+ return merge_abort(&o);
878
+ if (do_commit)
879
+ return merge_commit(&o);
880
+
881
o.local_ref = default_notes_ref();
882
strbuf_addstr(&remote_ref, argv[0]);
883
expand_notes_ref(&remote_ref);
910
/* Update default notes ref with new commit */
911
update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
912
0, DIE_ON_ERR);
823
- else /* Merge has unresolved conflicts */
824
- printf("Automatic notes merge failed. Fix conflicts in %s.\n",
913
+ else { /* Merge has unresolved conflicts */
914
+ /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
915
+ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
916
+ 0, DIE_ON_ERR);
917
+ /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
918
+ if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
919
+ die("Failed to store link to current notes ref (%s)",
920
+ default_notes_ref());
921
+ printf("Automatic notes merge failed. Fix conflicts in %s and "
922
+ "commit the result with 'git notes merge --commit', or "
923
+ "abort the merge with 'git notes merge --abort'.\n",
924
git_path(NOTES_MERGE_WORKTREE));
925
+ }
926
927
free_notes(t);
928
strbuf_release(&remote_ref);