static int remove_cmd(int argc, const char **argv, const char *prefix) { struct option options[] = { OPT_END() }; const char *object_ref; struct notes_tree *t; unsigned char object[20]; argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); if (1 < argc) { error("too many parameters"); usage_with_options(git_notes_remove_usage, options); } object_ref = argc ? argv[0] : "HEAD"; if (get_sha1(object_ref, object)) die("Failed to resolve '%s' as a valid ref.", object_ref); t = init_notes_check("remove"); fprintf(stderr, "Removing note for object %s\n", sha1_to_hex(object)); remove_note(t, object); commit_notes(t, "Notes removed by 'git notes remove'"); free_notes(t); return 0; }
static int prune(int argc, const char **argv, const char *prefix) { struct notes_tree *t; int show_only = 0, verbose = 0; struct option options[] = { OPT_BOOLEAN('n', "dry-run", &show_only, "do not remove, show only"), OPT_BOOLEAN('v', "verbose", &verbose, "report pruned notes"), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage, 0); if (argc) { error("too many parameters"); usage_with_options(git_notes_prune_usage, options); } t = init_notes_check("prune"); prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) | (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) ); if (!show_only) commit_notes(t, "Notes removed by 'git notes prune'"); free_notes(t); return 0; }
static int remove_cmd(int argc, const char **argv, const char *prefix) { unsigned flag = 0; int from_stdin = 0; struct option options[] = { OPT_BIT(0, "ignore-missing", &flag, N_("attempt to remove non-existent note is not an error"), IGNORE_MISSING), OPT_BOOL(0, "stdin", &from_stdin, N_("read object names from the standard input")), OPT_END() }; struct notes_tree *t; int retval = 0; argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); t = init_notes_check("remove"); if (!argc && !from_stdin) { retval = remove_one_note(t, "HEAD", flag); } else { while (*argv) { retval |= remove_one_note(t, *argv, flag); argv++; } } if (from_stdin) { struct strbuf sb = STRBUF_INIT; while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) { strbuf_rtrim(&sb); retval |= remove_one_note(t, sb.buf, flag); } strbuf_release(&sb); } if (!retval) commit_notes(t, "Notes removed by 'git notes remove'"); free_notes(t); return retval; }
static int show(int argc, const char **argv, const char *prefix) { const char *object_ref; struct notes_tree *t; unsigned char object[20]; const unsigned char *note; int retval; struct option options[] = { OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_show_usage, 0); if (1 < argc) { error("too many parameters"); usage_with_options(git_notes_show_usage, options); } object_ref = argc ? argv[0] : "HEAD"; if (get_sha1(object_ref, object)) die("Failed to resolve '%s' as a valid ref.", object_ref); t = init_notes_check("show"); note = get_note(t, object); if (!note) retval = error("No note found for object %s.", sha1_to_hex(object)); else { const char *show_args[3] = {"show", sha1_to_hex(note), NULL}; retval = execv_git_cmd(show_args); } free_notes(t); return retval; }
static int list(int argc, const char **argv, const char *prefix) { struct notes_tree *t; unsigned char object[20]; const unsigned char *note; int retval = -1; struct option options[] = { OPT_END() }; if (argc) argc = parse_options(argc, argv, prefix, options, git_notes_list_usage, 0); if (1 < argc) { error("too many parameters"); usage_with_options(git_notes_list_usage, options); } t = init_notes_check("list"); if (argc) { if (get_sha1(argv[0], object)) die("Failed to resolve '%s' as a valid ref.", argv[0]); note = get_note(t, object); if (note) { puts(sha1_to_hex(note)); retval = 0; } else retval = error("No note found for object %s.", sha1_to_hex(object)); } else retval = for_each_note(t, 0, list_each_note, NULL); free_notes(t); return retval; }
static int list(int argc, const char **argv, const char *prefix) { struct notes_tree *t; struct object_id object; const struct object_id *note; int retval = -1; struct option options[] = { OPT_END() }; if (argc) argc = parse_options(argc, argv, prefix, options, git_notes_list_usage, 0); if (1 < argc) { error(_("too many parameters")); usage_with_options(git_notes_list_usage, options); } t = init_notes_check("list", 0); if (argc) { if (get_oid(argv[0], &object)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); note = get_note(t, &object); if (note) { puts(oid_to_hex(note)); retval = 0; } else retval = error(_("no note found for object %s."), oid_to_hex(&object)); } else retval = for_each_note(t, 0, list_each_note, NULL); free_notes(t); return retval; }
static int append_edit(int argc, const char **argv, const char *prefix) { const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; const unsigned char *note; char logmsg[100]; const char * const *usage; struct msg_arg msg = { 0, 0, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &msg, "MSG", "note contents as a string", PARSE_OPT_NONEG, parse_msg_arg}, { OPTION_CALLBACK, 'F', "file", &msg, "FILE", "note contents in a file", PARSE_OPT_NONEG, parse_file_arg}, { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT", "reuse and edit specified note object", PARSE_OPT_NONEG, parse_reedit_arg}, { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT", "reuse specified note object", PARSE_OPT_NONEG, parse_reuse_arg}, OPT_END() }; int edit = !strcmp(argv[0], "edit"); usage = edit ? git_notes_edit_usage : git_notes_append_usage; argc = parse_options(argc, argv, prefix, options, usage, PARSE_OPT_KEEP_ARGV0); if (2 < argc) { error("too many parameters"); usage_with_options(usage, options); } if (msg.given && edit) fprintf(stderr, "The -m/-F/-c/-C options have been deprecated " "for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"); object_ref = 1 < argc ? argv[1] : "HEAD"; if (get_sha1(object_ref, object)) die("Failed to resolve '%s' as a valid ref.", object_ref); t = init_notes_check(argv[0]); note = get_note(t, object); create_note(object, &msg, !edit, note, new_note); if (is_null_sha1(new_note)) remove_note(t, object); else add_note(t, object, new_note, combine_notes_overwrite); snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", is_null_sha1(new_note) ? "removed" : "added", argv[0]); commit_notes(t, logmsg); free_notes(t); strbuf_release(&(msg.buf)); return 0; }
static int copy(int argc, const char **argv, const char *prefix) { int retval = 0, force = 0, from_stdin = 0; const unsigned char *from_note, *note; const char *object_ref; unsigned char object[20], from_obj[20]; struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { OPT_BOOLEAN('f', "force", &force, "replace existing notes"), OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"), OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command", "load rewriting config for <command> (implies " "--stdin)"), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage, 0); if (from_stdin || rewrite_cmd) { if (argc) { error("too many parameters"); usage_with_options(git_notes_copy_usage, options); } else { return notes_copy_from_stdin(force, rewrite_cmd); } } if (argc < 2) { error("too few parameters"); usage_with_options(git_notes_copy_usage, options); } if (2 < argc) { error("too many parameters"); usage_with_options(git_notes_copy_usage, options); } if (get_sha1(argv[0], from_obj)) die("Failed to resolve '%s' as a valid ref.", argv[0]); object_ref = 1 < argc ? argv[1] : "HEAD"; if (get_sha1(object_ref, object)) die("Failed to resolve '%s' as a valid ref.", object_ref); t = init_notes_check("copy"); note = get_note(t, object); if (note) { if (!force) { retval = error("Cannot copy notes. Found existing " "notes for object %s. Use '-f' to " "overwrite existing notes", sha1_to_hex(object)); goto out; } fprintf(stderr, "Overwriting existing notes for object %s\n", sha1_to_hex(object)); } from_note = get_note(t, from_obj); if (!from_note) { retval = error("Missing notes on source object %s. Cannot " "copy.", sha1_to_hex(from_obj)); goto out; } add_note(t, object, from_note, combine_notes_overwrite); commit_notes(t, "Notes added by 'git notes copy'"); out: free_notes(t); return retval; }
static int add(int argc, const char **argv, const char *prefix) { int retval = 0, force = 0; const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; char logmsg[100]; const unsigned char *note; struct msg_arg msg = { 0, 0, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &msg, "MSG", "note contents as a string", PARSE_OPT_NONEG, parse_msg_arg}, { OPTION_CALLBACK, 'F', "file", &msg, "FILE", "note contents in a file", PARSE_OPT_NONEG, parse_file_arg}, { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT", "reuse and edit specified note object", PARSE_OPT_NONEG, parse_reedit_arg}, { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT", "reuse specified note object", PARSE_OPT_NONEG, parse_reuse_arg}, OPT_BOOLEAN('f', "force", &force, "replace existing notes"), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_add_usage, 0); if (1 < argc) { error("too many parameters"); usage_with_options(git_notes_add_usage, options); } object_ref = argc ? argv[0] : "HEAD"; if (get_sha1(object_ref, object)) die("Failed to resolve '%s' as a valid ref.", object_ref); t = init_notes_check("add"); note = get_note(t, object); if (note) { if (!force) { retval = error("Cannot add notes. Found existing notes " "for object %s. Use '-f' to overwrite " "existing notes", sha1_to_hex(object)); goto out; } fprintf(stderr, "Overwriting existing notes for object %s\n", sha1_to_hex(object)); } create_note(object, &msg, 0, note, new_note); if (is_null_sha1(new_note)) remove_note(t, object); else add_note(t, object, new_note, combine_notes_overwrite); snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", is_null_sha1(new_note) ? "removed" : "added", "add"); commit_notes(t, logmsg); out: free_notes(t); strbuf_release(&(msg.buf)); return retval; }
static int merge(int argc, const char **argv, const char *prefix) { struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT; unsigned char result_sha1[20]; struct notes_tree *t; struct notes_merge_options o; int do_merge = 0, do_commit = 0, do_abort = 0; int verbosity = 0, result; const char *strategy = NULL; struct option options[] = { OPT_GROUP(N_("General options")), OPT__VERBOSITY(&verbosity), OPT_GROUP(N_("Merge options")), OPT_STRING('s', "strategy", &strategy, N_("strategy"), N_("resolve notes conflicts using the given strategy " "(manual/ours/theirs/union/cat_sort_uniq)")), OPT_GROUP(N_("Committing unmerged notes")), { OPTION_SET_INT, 0, "commit", &do_commit, NULL, N_("finalize notes merge by committing unmerged notes"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1}, OPT_GROUP(N_("Aborting notes merge resolution")), { OPTION_SET_INT, 0, "abort", &do_abort, NULL, N_("abort notes merge"), PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1}, OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_merge_usage, 0); if (strategy || do_commit + do_abort == 0) do_merge = 1; if (do_merge + do_commit + do_abort != 1) { error("cannot mix --commit, --abort or -s/--strategy"); usage_with_options(git_notes_merge_usage, options); } if (do_merge && argc != 1) { error("Must specify a notes ref to merge"); usage_with_options(git_notes_merge_usage, options); } else if (!do_merge && argc) { error("too many parameters"); usage_with_options(git_notes_merge_usage, options); } init_notes_merge_options(&o); o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT; if (do_abort) return merge_abort(&o); if (do_commit) return merge_commit(&o); o.local_ref = default_notes_ref(); strbuf_addstr(&remote_ref, argv[0]); expand_notes_ref(&remote_ref); o.remote_ref = remote_ref.buf; t = init_notes_check("merge"); if (strategy) { if (parse_notes_merge_strategy(strategy, &o.strategy)) { error("Unknown -s/--strategy: %s", strategy); usage_with_options(git_notes_merge_usage, options); } } else { struct strbuf merge_key = STRBUF_INIT; const char *short_ref = NULL; if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref)) die("BUG: local ref %s is outside of refs/notes/", o.local_ref); strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref); if (git_config_get_notes_strategy(merge_key.buf, &o.strategy)) git_config_get_notes_strategy("notes.mergeStrategy", &o.strategy); strbuf_release(&merge_key); } strbuf_addf(&msg, "notes: Merged notes from %s into %s", remote_ref.buf, default_notes_ref()); strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */ result = notes_merge(&o, t, result_sha1); if (result >= 0) /* Merge resulted (trivially) in result_sha1 */ /* Update default notes ref with new commit */ update_ref(msg.buf, default_notes_ref(), result_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); else { /* Merge has unresolved conflicts */ char *existing; /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL, 0, UPDATE_REFS_DIE_ON_ERR); /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */ existing = find_shared_symref("NOTES_MERGE_REF", default_notes_ref()); if (existing) die(_("A notes merge into %s is already in-progress at %s"), default_notes_ref(), existing); if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL)) die("Failed to store link to current notes ref (%s)", default_notes_ref()); printf("Automatic notes merge failed. Fix conflicts in %s and " "commit the result with 'git notes merge --commit', or " "abort the merge with 'git notes merge --abort'.\n", git_path(NOTES_MERGE_WORKTREE)); } free_notes(t); strbuf_release(&remote_ref); strbuf_release(&msg); return result < 0; /* return non-zero on conflicts */ }
static int append_edit(int argc, const char **argv, const char *prefix) { int allow_empty = 0; const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; const unsigned char *note; char logmsg[100]; const char * const *usage; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &d, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, { OPTION_CALLBACK, 'F', "file", &d, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), OPT_END() }; int edit = !strcmp(argv[0], "edit"); usage = edit ? git_notes_edit_usage : git_notes_append_usage; argc = parse_options(argc, argv, prefix, options, usage, PARSE_OPT_KEEP_ARGV0); if (2 < argc) { error(_("too many parameters")); usage_with_options(usage, options); } if (d.given && edit) fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " "for the 'edit' subcommand.\n" "Please use 'git notes add -f -m/-F/-c/-C' instead.\n")); object_ref = 1 < argc ? argv[1] : "HEAD"; if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check(argv[0]); note = get_note(t, object); prepare_note_data(object, &d, edit ? note : NULL); if (note && !edit) { /* Append buf to previous note contents */ unsigned long size; enum object_type type; char *prev_buf = read_sha1_file(note, &type, &size); strbuf_grow(&d.buf, size + 1); if (d.buf.len && prev_buf && size) strbuf_insert(&d.buf, 0, "\n", 1); if (prev_buf && size) strbuf_insert(&d.buf, 0, prev_buf, size); free(prev_buf); } if (d.buf.len || allow_empty) { write_note_data(&d, new_note); if (add_note(t, object, new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); snprintf(logmsg, sizeof(logmsg), "Notes added by 'git notes %s'", argv[0]); } else { fprintf(stderr, _("Removing note for object %s\n"), sha1_to_hex(object)); remove_note(t, object); snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'", argv[0]); } commit_notes(t, logmsg); free_note_data(&d); free_notes(t); return 0; }
static int add(int argc, const char **argv, const char *prefix) { int force = 0, allow_empty = 0; const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; const unsigned char *note; struct note_data d = { 0, 0, NULL, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &d, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, { OPTION_CALLBACK, 'F', "file", &d, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), OPT__FORCE(&force, N_("replace existing notes")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_add_usage, PARSE_OPT_KEEP_ARGV0); if (2 < argc) { error(_("too many parameters")); usage_with_options(git_notes_add_usage, options); } object_ref = argc > 1 ? argv[1] : "HEAD"; if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("add"); note = get_note(t, object); if (note) { if (!force) { free_notes(t); if (d.given) { free_note_data(&d); return error(_("Cannot add notes. " "Found existing notes for object %s. " "Use '-f' to overwrite existing notes"), sha1_to_hex(object)); } /* * Redirect to "edit" subcommand. * * We only end up here if none of -m/-F/-c/-C or -f are * given. The original args are therefore still in * argv[0-1]. */ argv[0] = "edit"; return append_edit(argc, argv, prefix); } fprintf(stderr, _("Overwriting existing notes for object %s\n"), sha1_to_hex(object)); } prepare_note_data(object, &d, note); if (d.buf.len || allow_empty) { write_note_data(&d, new_note); if (add_note(t, object, new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes add'"); } else { fprintf(stderr, _("Removing note for object %s\n"), sha1_to_hex(object)); remove_note(t, object); commit_notes(t, "Notes removed by 'git notes add'"); } free_note_data(&d); free_notes(t); return 0; }
static int add(int argc, const char **argv, const char *prefix) { int retval = 0, force = 0; const char *object_ref; struct notes_tree *t; unsigned char object[20], new_note[20]; char logmsg[100]; const unsigned char *note; struct msg_arg msg = { 0, 0, STRBUF_INIT }; struct option options[] = { { OPTION_CALLBACK, 'm', "message", &msg, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg}, { OPTION_CALLBACK, 'F', "file", &msg, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg}, { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"), N_("reuse and edit specified note object"), PARSE_OPT_NONEG, parse_reedit_arg}, { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"), N_("reuse specified note object"), PARSE_OPT_NONEG, parse_reuse_arg}, OPT__FORCE(&force, N_("replace existing notes")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_add_usage, PARSE_OPT_KEEP_ARGV0); if (2 < argc) { error(_("too many parameters")); usage_with_options(git_notes_add_usage, options); } object_ref = argc > 1 ? argv[1] : "HEAD"; if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("add"); note = get_note(t, object); if (note) { if (!force) { if (!msg.given) { /* * Redirect to "edit" subcommand. * * We only end up here if none of -m/-F/-c/-C * or -f are given. The original args are * therefore still in argv[0-1]. */ argv[0] = "edit"; free_notes(t); return append_edit(argc, argv, prefix); } retval = error(_("Cannot add notes. Found existing notes " "for object %s. Use '-f' to overwrite " "existing notes"), sha1_to_hex(object)); goto out; } fprintf(stderr, _("Overwriting existing notes for object %s\n"), sha1_to_hex(object)); } create_note(object, &msg, 0, note, new_note); if (is_null_sha1(new_note)) remove_note(t, object); else if (add_note(t, object, new_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'", is_null_sha1(new_note) ? "removed" : "added", "add"); commit_notes(t, logmsg); out: free_notes(t); strbuf_release(&(msg.buf)); return retval; }
static int copy(int argc, const char **argv, const char *prefix) { int retval = 0, force = 0, from_stdin = 0; const struct object_id *from_note, *note; const char *object_ref; struct object_id object, from_obj; struct notes_tree *t; const char *rewrite_cmd = NULL; struct option options[] = { OPT__FORCE(&force, N_("replace existing notes")), OPT_BOOL(0, "stdin", &from_stdin, N_("read objects from stdin")), OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"), N_("load rewriting config for <command> (implies " "--stdin)")), OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage, 0); if (from_stdin || rewrite_cmd) { if (argc) { error(_("too many parameters")); usage_with_options(git_notes_copy_usage, options); } else { return notes_copy_from_stdin(force, rewrite_cmd); } } if (argc < 2) { error(_("too few parameters")); usage_with_options(git_notes_copy_usage, options); } if (2 < argc) { error(_("too many parameters")); usage_with_options(git_notes_copy_usage, options); } if (get_oid(argv[0], &from_obj)) die(_("failed to resolve '%s' as a valid ref."), argv[0]); object_ref = 1 < argc ? argv[1] : "HEAD"; if (get_oid(object_ref, &object)) die(_("failed to resolve '%s' as a valid ref."), object_ref); t = init_notes_check("copy", NOTES_INIT_WRITABLE); note = get_note(t, &object); if (note) { if (!force) { retval = error(_("Cannot copy notes. Found existing " "notes for object %s. Use '-f' to " "overwrite existing notes"), oid_to_hex(&object)); goto out; } fprintf(stderr, _("Overwriting existing notes for object %s\n"), oid_to_hex(&object)); } from_note = get_note(t, &from_obj); if (!from_note) { retval = error(_("missing notes on source object %s. Cannot " "copy."), oid_to_hex(&from_obj)); goto out; } if (add_note(t, &object, from_note, combine_notes_overwrite)) die("BUG: combine_notes_overwrite failed"); commit_notes(t, "Notes added by 'git notes copy'"); out: free_notes(t); return retval; }
static int merge(int argc, const char **argv, const char *prefix) { struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT; unsigned char result_sha1[20]; struct notes_tree *t; struct notes_merge_options o; int do_merge = 0, do_commit = 0, do_abort = 0; int verbosity = 0, result; const char *strategy = NULL; struct option options[] = { OPT_GROUP("General options"), OPT__VERBOSITY(&verbosity), OPT_GROUP("Merge options"), OPT_STRING('s', "strategy", &strategy, "strategy", "resolve notes conflicts using the given strategy " "(manual/ours/theirs/union/cat_sort_uniq)"), OPT_GROUP("Committing unmerged notes"), { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL, "finalize notes merge by committing unmerged notes", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, OPT_GROUP("Aborting notes merge resolution"), { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL, "abort notes merge", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, OPT_END() }; argc = parse_options(argc, argv, prefix, options, git_notes_merge_usage, 0); if (strategy || do_commit + do_abort == 0) do_merge = 1; if (do_merge + do_commit + do_abort != 1) { error("cannot mix --commit, --abort or -s/--strategy"); usage_with_options(git_notes_merge_usage, options); } if (do_merge && argc != 1) { error("Must specify a notes ref to merge"); usage_with_options(git_notes_merge_usage, options); } else if (!do_merge && argc) { error("too many parameters"); usage_with_options(git_notes_merge_usage, options); } init_notes_merge_options(&o); o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT; if (do_abort) return merge_abort(&o); if (do_commit) return merge_commit(&o); o.local_ref = default_notes_ref(); strbuf_addstr(&remote_ref, argv[0]); expand_notes_ref(&remote_ref); o.remote_ref = remote_ref.buf; if (strategy) { if (!strcmp(strategy, "manual")) o.strategy = NOTES_MERGE_RESOLVE_MANUAL; else if (!strcmp(strategy, "ours")) o.strategy = NOTES_MERGE_RESOLVE_OURS; else if (!strcmp(strategy, "theirs")) o.strategy = NOTES_MERGE_RESOLVE_THEIRS; else if (!strcmp(strategy, "union")) o.strategy = NOTES_MERGE_RESOLVE_UNION; else if (!strcmp(strategy, "cat_sort_uniq")) o.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ; else { error("Unknown -s/--strategy: %s", strategy); usage_with_options(git_notes_merge_usage, options); } } t = init_notes_check("merge"); strbuf_addf(&msg, "notes: Merged notes from %s into %s", remote_ref.buf, default_notes_ref()); strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */ result = notes_merge(&o, t, result_sha1); if (result >= 0) /* Merge resulted (trivially) in result_sha1 */ /* Update default notes ref with new commit */ update_ref(msg.buf, default_notes_ref(), result_sha1, NULL, 0, DIE_ON_ERR); else { /* Merge has unresolved conflicts */ /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL, 0, DIE_ON_ERR); /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */ if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL)) die("Failed to store link to current notes ref (%s)", default_notes_ref()); printf("Automatic notes merge failed. Fix conflicts in %s and " "commit the result with 'git notes merge --commit', or " "abort the merge with 'git notes merge --abort'.\n", git_path(NOTES_MERGE_WORKTREE)); } free_notes(t); strbuf_release(&remote_ref); strbuf_release(&msg); return result < 0; /* return non-zero on conflicts */ }