symbolic-ref --short: abbreviate the output unambiguously
[gitweb.git] / builtin / notes.c
index 1fb1f734397668280b444e63dc8d3c129d41e3b9..3644d140ece9f2cfc6381e1a60c5b4fc8f645e2a 100644 (file)
@@ -29,7 +29,7 @@ static const char * const git_notes_usage[] = {
        "git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
        "git notes merge --commit [-v | -q]",
        "git notes merge --abort [-v | -q]",
-       "git notes [--ref <notes_ref>] remove [<object>]",
+       "git notes [--ref <notes_ref>] remove [<object>...]",
        "git notes [--ref <notes_ref>] prune [-n | -v]",
        "git notes [--ref <notes_ref>] get-ref",
        NULL
@@ -301,12 +301,12 @@ void commit_notes(struct notes_tree *t, const char *msg)
                return; /* don't have to commit an unchanged tree */
 
        /* Prepare commit message and reflog message */
-       strbuf_addstr(&buf, "notes: "); /* commit message starts at index 7 */
        strbuf_addstr(&buf, msg);
        if (buf.buf[buf.len - 1] != '\n')
                strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
 
-       create_notes_commit(t, NULL, buf.buf + 7, commit_sha1);
+       create_notes_commit(t, NULL, &buf, commit_sha1);
+       strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
        update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR);
 
        strbuf_release(&buf);
@@ -804,6 +804,8 @@ static int merge_commit(struct notes_merge_options *o)
        struct notes_tree *t;
        struct commit *partial;
        struct pretty_print_context pretty_ctx;
+       void *local_ref_to_free;
+       int ret;
 
        /*
         * Read partial merge result from .git/NOTES_MERGE_PARTIAL,
@@ -825,7 +827,8 @@ static int merge_commit(struct notes_merge_options *o)
        t = xcalloc(1, sizeof(struct notes_tree));
        init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
-       o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
+       o->local_ref = local_ref_to_free =
+               resolve_refdup("NOTES_MERGE_REF", sha1, 0, NULL);
        if (!o->local_ref)
                die("Failed to resolve NOTES_MERGE_REF");
 
@@ -843,7 +846,9 @@ static int merge_commit(struct notes_merge_options *o)
 
        free_notes(t);
        strbuf_release(&msg);
-       return merge_abort(o);
+       ret = merge_abort(o);
+       free(local_ref_to_free);
+       return ret;
 }
 
 static int merge(int argc, const char **argv, const char *prefix)
@@ -953,40 +958,60 @@ static int merge(int argc, const char **argv, const char *prefix)
        return result < 0; /* return non-zero on conflicts */
 }
 
+#define IGNORE_MISSING 1
+
+static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag)
+{
+       int status;
+       unsigned char sha1[20];
+       if (get_sha1(name, sha1))
+               return error(_("Failed to resolve '%s' as a valid ref."), name);
+       status = remove_note(t, sha1);
+       if (status)
+               fprintf(stderr, _("Object %s has no note\n"), name);
+       else
+               fprintf(stderr, _("Removing note for object %s\n"), name);
+       return (flag & IGNORE_MISSING) ? 0 : status;
+}
+
 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,
+                       "attempt to remove non-existent note is not an error",
+                       IGNORE_MISSING),
+               OPT_BOOLEAN(0, "stdin", &from_stdin,
+                           "read object names from the standard input"),
                OPT_END()
        };
-       const char *object_ref;
        struct notes_tree *t;
-       unsigned char object[20];
-       int retval;
+       int retval = 0;
 
        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");
 
-       retval = remove_note(t, object);
-       if (retval)
-               fprintf(stderr, _("Object %s has no note\n"), sha1_to_hex(object));
-       else {
-               fprintf(stderr, _("Removing note for object %s\n"),
-                       sha1_to_hex(object));
-
-               commit_notes(t, "Notes removed by 'git notes 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;
 }