notes: make expand_notes_ref globally accessible
[git] / builtin / notes.c
1 /*
2  * Builtin "git notes"
3  *
4  * Copyright (c) 2010 Johan Herland <johan@herland.net>
5  *
6  * Based on git-notes.sh by Johannes Schindelin,
7  * and builtin-tag.c by Kristian Høgsberg and Carlos Rica.
8  */
9
10 #include "cache.h"
11 #include "builtin.h"
12 #include "notes.h"
13 #include "blob.h"
14 #include "commit.h"
15 #include "refs.h"
16 #include "exec_cmd.h"
17 #include "run-command.h"
18 #include "parse-options.h"
19 #include "string-list.h"
20 #include "notes-merge.h"
21
22 static const char * const git_notes_usage[] = {
23         "git notes [--ref <notes_ref>] [list [<object>]]",
24         "git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
25         "git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>",
26         "git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
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         "git notes [--ref <notes_ref>] get-ref",
35         NULL
36 };
37
38 static const char * const git_notes_list_usage[] = {
39         "git notes [list [<object>]]",
40         NULL
41 };
42
43 static const char * const git_notes_add_usage[] = {
44         "git notes add [<options>] [<object>]",
45         NULL
46 };
47
48 static const char * const git_notes_copy_usage[] = {
49         "git notes copy [<options>] <from-object> <to-object>",
50         "git notes copy --stdin [<from-object> <to-object>]...",
51         NULL
52 };
53
54 static const char * const git_notes_append_usage[] = {
55         "git notes append [<options>] [<object>]",
56         NULL
57 };
58
59 static const char * const git_notes_edit_usage[] = {
60         "git notes edit [<object>]",
61         NULL
62 };
63
64 static const char * const git_notes_show_usage[] = {
65         "git notes show [<object>]",
66         NULL
67 };
68
69 static const char * const git_notes_merge_usage[] = {
70         "git notes merge [<options>] <notes_ref>",
71         "git notes merge --commit [<options>]",
72         "git notes merge --abort [<options>]",
73         NULL
74 };
75
76 static const char * const git_notes_remove_usage[] = {
77         "git notes remove [<object>]",
78         NULL
79 };
80
81 static const char * const git_notes_prune_usage[] = {
82         "git notes prune [<options>]",
83         NULL
84 };
85
86 static const char * const git_notes_get_ref_usage[] = {
87         "git notes get-ref",
88         NULL
89 };
90
91 static const char note_template[] =
92         "\n"
93         "#\n"
94         "# Write/edit the notes for the following object:\n"
95         "#\n";
96
97 struct msg_arg {
98         int given;
99         int use_editor;
100         struct strbuf buf;
101 };
102
103 static int list_each_note(const unsigned char *object_sha1,
104                 const unsigned char *note_sha1, char *note_path,
105                 void *cb_data)
106 {
107         printf("%s %s\n", sha1_to_hex(note_sha1), sha1_to_hex(object_sha1));
108         return 0;
109 }
110
111 static void write_note_data(int fd, const unsigned char *sha1)
112 {
113         unsigned long size;
114         enum object_type type;
115         char *buf = read_sha1_file(sha1, &type, &size);
116         if (buf) {
117                 if (size)
118                         write_or_die(fd, buf, size);
119                 free(buf);
120         }
121 }
122
123 static void write_commented_object(int fd, const unsigned char *object)
124 {
125         const char *show_args[5] =
126                 {"show", "--stat", "--no-notes", sha1_to_hex(object), NULL};
127         struct child_process show;
128         struct strbuf buf = STRBUF_INIT;
129         FILE *show_out;
130
131         /* Invoke "git show --stat --no-notes $object" */
132         memset(&show, 0, sizeof(show));
133         show.argv = show_args;
134         show.no_stdin = 1;
135         show.out = -1;
136         show.err = 0;
137         show.git_cmd = 1;
138         if (start_command(&show))
139                 die("unable to start 'show' for object '%s'",
140                     sha1_to_hex(object));
141
142         /* Open the output as FILE* so strbuf_getline() can be used. */
143         show_out = xfdopen(show.out, "r");
144         if (show_out == NULL)
145                 die_errno("can't fdopen 'show' output fd");
146
147         /* Prepend "# " to each output line and write result to 'fd' */
148         while (strbuf_getline(&buf, show_out, '\n') != EOF) {
149                 write_or_die(fd, "# ", 2);
150                 write_or_die(fd, buf.buf, buf.len);
151                 write_or_die(fd, "\n", 1);
152         }
153         strbuf_release(&buf);
154         if (fclose(show_out))
155                 die_errno("failed to close pipe to 'show' for object '%s'",
156                           sha1_to_hex(object));
157         if (finish_command(&show))
158                 die("failed to finish 'show' for object '%s'",
159                     sha1_to_hex(object));
160 }
161
162 static void create_note(const unsigned char *object, struct msg_arg *msg,
163                         int append_only, const unsigned char *prev,
164                         unsigned char *result)
165 {
166         char *path = NULL;
167
168         if (msg->use_editor || !msg->given) {
169                 int fd;
170
171                 /* write the template message before editing: */
172                 path = git_pathdup("NOTES_EDITMSG");
173                 fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
174                 if (fd < 0)
175                         die_errno("could not create file '%s'", path);
176
177                 if (msg->given)
178                         write_or_die(fd, msg->buf.buf, msg->buf.len);
179                 else if (prev && !append_only)
180                         write_note_data(fd, prev);
181                 write_or_die(fd, note_template, strlen(note_template));
182
183                 write_commented_object(fd, object);
184
185                 close(fd);
186                 strbuf_reset(&(msg->buf));
187
188                 if (launch_editor(path, &(msg->buf), NULL)) {
189                         die("Please supply the note contents using either -m" \
190                             " or -F option");
191                 }
192                 stripspace(&(msg->buf), 1);
193         }
194
195         if (prev && append_only) {
196                 /* Append buf to previous note contents */
197                 unsigned long size;
198                 enum object_type type;
199                 char *prev_buf = read_sha1_file(prev, &type, &size);
200
201                 strbuf_grow(&(msg->buf), size + 1);
202                 if (msg->buf.len && prev_buf && size)
203                         strbuf_insert(&(msg->buf), 0, "\n", 1);
204                 if (prev_buf && size)
205                         strbuf_insert(&(msg->buf), 0, prev_buf, size);
206                 free(prev_buf);
207         }
208
209         if (!msg->buf.len) {
210                 fprintf(stderr, "Removing note for object %s\n",
211                         sha1_to_hex(object));
212                 hashclr(result);
213         } else {
214                 if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
215                         error("unable to write note object");
216                         if (path)
217                                 error("The note contents has been left in %s",
218                                       path);
219                         exit(128);
220                 }
221         }
222
223         if (path) {
224                 unlink_or_warn(path);
225                 free(path);
226         }
227 }
228
229 static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
230 {
231         struct msg_arg *msg = opt->value;
232
233         strbuf_grow(&(msg->buf), strlen(arg) + 2);
234         if (msg->buf.len)
235                 strbuf_addch(&(msg->buf), '\n');
236         strbuf_addstr(&(msg->buf), arg);
237         stripspace(&(msg->buf), 0);
238
239         msg->given = 1;
240         return 0;
241 }
242
243 static int parse_file_arg(const struct option *opt, const char *arg, int unset)
244 {
245         struct msg_arg *msg = opt->value;
246
247         if (msg->buf.len)
248                 strbuf_addch(&(msg->buf), '\n');
249         if (!strcmp(arg, "-")) {
250                 if (strbuf_read(&(msg->buf), 0, 1024) < 0)
251                         die_errno("cannot read '%s'", arg);
252         } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
253                 die_errno("could not open or read '%s'", arg);
254         stripspace(&(msg->buf), 0);
255
256         msg->given = 1;
257         return 0;
258 }
259
260 static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
261 {
262         struct msg_arg *msg = opt->value;
263         char *buf;
264         unsigned char object[20];
265         enum object_type type;
266         unsigned long len;
267
268         if (msg->buf.len)
269                 strbuf_addch(&(msg->buf), '\n');
270
271         if (get_sha1(arg, object))
272                 die("Failed to resolve '%s' as a valid ref.", arg);
273         if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
274                 free(buf);
275                 die("Failed to read object '%s'.", arg);;
276         }
277         strbuf_add(&(msg->buf), buf, len);
278         free(buf);
279
280         msg->given = 1;
281         return 0;
282 }
283
284 static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
285 {
286         struct msg_arg *msg = opt->value;
287         msg->use_editor = 1;
288         return parse_reuse_arg(opt, arg, unset);
289 }
290
291 void commit_notes(struct notes_tree *t, const char *msg)
292 {
293         struct strbuf buf = STRBUF_INIT;
294         unsigned char commit_sha1[20];
295
296         if (!t)
297                 t = &default_notes_tree;
298         if (!t->initialized || !t->ref || !*t->ref)
299                 die("Cannot commit uninitialized/unreferenced notes tree");
300         if (!t->dirty)
301                 return; /* don't have to commit an unchanged tree */
302
303         /* Prepare commit message and reflog message */
304         strbuf_addstr(&buf, "notes: "); /* commit message starts at index 7 */
305         strbuf_addstr(&buf, msg);
306         if (buf.buf[buf.len - 1] != '\n')
307                 strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
308
309         create_notes_commit(t, NULL, buf.buf + 7, commit_sha1);
310         update_ref(buf.buf, t->ref, commit_sha1, NULL, 0, DIE_ON_ERR);
311
312         strbuf_release(&buf);
313 }
314
315 combine_notes_fn parse_combine_notes_fn(const char *v)
316 {
317         if (!strcasecmp(v, "overwrite"))
318                 return combine_notes_overwrite;
319         else if (!strcasecmp(v, "ignore"))
320                 return combine_notes_ignore;
321         else if (!strcasecmp(v, "concatenate"))
322                 return combine_notes_concatenate;
323         else if (!strcasecmp(v, "cat_sort_uniq"))
324                 return combine_notes_cat_sort_uniq;
325         else
326                 return NULL;
327 }
328
329 static int notes_rewrite_config(const char *k, const char *v, void *cb)
330 {
331         struct notes_rewrite_cfg *c = cb;
332         if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) {
333                 c->enabled = git_config_bool(k, v);
334                 return 0;
335         } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) {
336                 if (!v)
337                         config_error_nonbool(k);
338                 c->combine = parse_combine_notes_fn(v);
339                 if (!c->combine) {
340                         error("Bad notes.rewriteMode value: '%s'", v);
341                         return 1;
342                 }
343                 return 0;
344         } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) {
345                 /* note that a refs/ prefix is implied in the
346                  * underlying for_each_glob_ref */
347                 if (!prefixcmp(v, "refs/notes/"))
348                         string_list_add_refs_by_glob(c->refs, v);
349                 else
350                         warning("Refusing to rewrite notes in %s"
351                                 " (outside of refs/notes/)", v);
352                 return 0;
353         }
354
355         return 0;
356 }
357
358
359 struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
360 {
361         struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg));
362         const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT);
363         const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT);
364         c->cmd = cmd;
365         c->enabled = 1;
366         c->combine = combine_notes_concatenate;
367         c->refs = xcalloc(1, sizeof(struct string_list));
368         c->refs->strdup_strings = 1;
369         c->refs_from_env = 0;
370         c->mode_from_env = 0;
371         if (rewrite_mode_env) {
372                 c->mode_from_env = 1;
373                 c->combine = parse_combine_notes_fn(rewrite_mode_env);
374                 if (!c->combine)
375                         error("Bad " GIT_NOTES_REWRITE_MODE_ENVIRONMENT
376                               " value: '%s'", rewrite_mode_env);
377         }
378         if (rewrite_refs_env) {
379                 c->refs_from_env = 1;
380                 string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env);
381         }
382         git_config(notes_rewrite_config, c);
383         if (!c->enabled || !c->refs->nr) {
384                 string_list_clear(c->refs, 0);
385                 free(c->refs);
386                 free(c);
387                 return NULL;
388         }
389         c->trees = load_notes_trees(c->refs);
390         string_list_clear(c->refs, 0);
391         free(c->refs);
392         return c;
393 }
394
395 int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
396                           const unsigned char *from_obj, const unsigned char *to_obj)
397 {
398         int ret = 0;
399         int i;
400         for (i = 0; c->trees[i]; i++)
401                 ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret;
402         return ret;
403 }
404
405 void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c)
406 {
407         int i;
408         for (i = 0; c->trees[i]; i++) {
409                 commit_notes(c->trees[i], "Notes added by 'git notes copy'");
410                 free_notes(c->trees[i]);
411         }
412         free(c->trees);
413         free(c);
414 }
415
416 static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
417 {
418         struct strbuf buf = STRBUF_INIT;
419         struct notes_rewrite_cfg *c = NULL;
420         struct notes_tree *t = NULL;
421         int ret = 0;
422
423         if (rewrite_cmd) {
424                 c = init_copy_notes_for_rewrite(rewrite_cmd);
425                 if (!c)
426                         return 0;
427         } else {
428                 init_notes(NULL, NULL, NULL, 0);
429                 t = &default_notes_tree;
430         }
431
432         while (strbuf_getline(&buf, stdin, '\n') != EOF) {
433                 unsigned char from_obj[20], to_obj[20];
434                 struct strbuf **split;
435                 int err;
436
437                 split = strbuf_split(&buf, ' ');
438                 if (!split[0] || !split[1])
439                         die("Malformed input line: '%s'.", buf.buf);
440                 strbuf_rtrim(split[0]);
441                 strbuf_rtrim(split[1]);
442                 if (get_sha1(split[0]->buf, from_obj))
443                         die("Failed to resolve '%s' as a valid ref.", split[0]->buf);
444                 if (get_sha1(split[1]->buf, to_obj))
445                         die("Failed to resolve '%s' as a valid ref.", split[1]->buf);
446
447                 if (rewrite_cmd)
448                         err = copy_note_for_rewrite(c, from_obj, to_obj);
449                 else
450                         err = copy_note(t, from_obj, to_obj, force,
451                                         combine_notes_overwrite);
452
453                 if (err) {
454                         error("Failed to copy notes from '%s' to '%s'",
455                               split[0]->buf, split[1]->buf);
456                         ret = 1;
457                 }
458
459                 strbuf_list_free(split);
460         }
461
462         if (!rewrite_cmd) {
463                 commit_notes(t, "Notes added by 'git notes copy'");
464                 free_notes(t);
465         } else {
466                 finish_copy_notes_for_rewrite(c);
467         }
468         return ret;
469 }
470
471 static struct notes_tree *init_notes_check(const char *subcommand)
472 {
473         struct notes_tree *t;
474         init_notes(NULL, NULL, NULL, 0);
475         t = &default_notes_tree;
476
477         if (prefixcmp(t->ref, "refs/notes/"))
478                 die("Refusing to %s notes in %s (outside of refs/notes/)",
479                     subcommand, t->ref);
480         return t;
481 }
482
483 static int list(int argc, const char **argv, const char *prefix)
484 {
485         struct notes_tree *t;
486         unsigned char object[20];
487         const unsigned char *note;
488         int retval = -1;
489         struct option options[] = {
490                 OPT_END()
491         };
492
493         if (argc)
494                 argc = parse_options(argc, argv, prefix, options,
495                                      git_notes_list_usage, 0);
496
497         if (1 < argc) {
498                 error("too many parameters");
499                 usage_with_options(git_notes_list_usage, options);
500         }
501
502         t = init_notes_check("list");
503         if (argc) {
504                 if (get_sha1(argv[0], object))
505                         die("Failed to resolve '%s' as a valid ref.", argv[0]);
506                 note = get_note(t, object);
507                 if (note) {
508                         puts(sha1_to_hex(note));
509                         retval = 0;
510                 } else
511                         retval = error("No note found for object %s.",
512                                        sha1_to_hex(object));
513         } else
514                 retval = for_each_note(t, 0, list_each_note, NULL);
515
516         free_notes(t);
517         return retval;
518 }
519
520 static int add(int argc, const char **argv, const char *prefix)
521 {
522         int retval = 0, force = 0;
523         const char *object_ref;
524         struct notes_tree *t;
525         unsigned char object[20], new_note[20];
526         char logmsg[100];
527         const unsigned char *note;
528         struct msg_arg msg = { 0, 0, STRBUF_INIT };
529         struct option options[] = {
530                 { OPTION_CALLBACK, 'm', "message", &msg, "msg",
531                         "note contents as a string", PARSE_OPT_NONEG,
532                         parse_msg_arg},
533                 { OPTION_CALLBACK, 'F', "file", &msg, "file",
534                         "note contents in a file", PARSE_OPT_NONEG,
535                         parse_file_arg},
536                 { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
537                         "reuse and edit specified note object", PARSE_OPT_NONEG,
538                         parse_reedit_arg},
539                 { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
540                         "reuse specified note object", PARSE_OPT_NONEG,
541                         parse_reuse_arg},
542                 OPT__FORCE(&force, "replace existing notes"),
543                 OPT_END()
544         };
545
546         argc = parse_options(argc, argv, prefix, options, git_notes_add_usage,
547                              0);
548
549         if (1 < argc) {
550                 error("too many parameters");
551                 usage_with_options(git_notes_add_usage, options);
552         }
553
554         object_ref = argc ? argv[0] : "HEAD";
555
556         if (get_sha1(object_ref, object))
557                 die("Failed to resolve '%s' as a valid ref.", object_ref);
558
559         t = init_notes_check("add");
560         note = get_note(t, object);
561
562         if (note) {
563                 if (!force) {
564                         retval = error("Cannot add notes. Found existing notes "
565                                        "for object %s. Use '-f' to overwrite "
566                                        "existing notes", sha1_to_hex(object));
567                         goto out;
568                 }
569                 fprintf(stderr, "Overwriting existing notes for object %s\n",
570                         sha1_to_hex(object));
571         }
572
573         create_note(object, &msg, 0, note, new_note);
574
575         if (is_null_sha1(new_note))
576                 remove_note(t, object);
577         else if (add_note(t, object, new_note, combine_notes_overwrite))
578                 die("BUG: combine_notes_overwrite failed");
579
580         snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
581                  is_null_sha1(new_note) ? "removed" : "added", "add");
582         commit_notes(t, logmsg);
583 out:
584         free_notes(t);
585         strbuf_release(&(msg.buf));
586         return retval;
587 }
588
589 static int copy(int argc, const char **argv, const char *prefix)
590 {
591         int retval = 0, force = 0, from_stdin = 0;
592         const unsigned char *from_note, *note;
593         const char *object_ref;
594         unsigned char object[20], from_obj[20];
595         struct notes_tree *t;
596         const char *rewrite_cmd = NULL;
597         struct option options[] = {
598                 OPT__FORCE(&force, "replace existing notes"),
599                 OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
600                 OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command",
601                            "load rewriting config for <command> (implies "
602                            "--stdin)"),
603                 OPT_END()
604         };
605
606         argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage,
607                              0);
608
609         if (from_stdin || rewrite_cmd) {
610                 if (argc) {
611                         error("too many parameters");
612                         usage_with_options(git_notes_copy_usage, options);
613                 } else {
614                         return notes_copy_from_stdin(force, rewrite_cmd);
615                 }
616         }
617
618         if (argc < 2) {
619                 error("too few parameters");
620                 usage_with_options(git_notes_copy_usage, options);
621         }
622         if (2 < argc) {
623                 error("too many parameters");
624                 usage_with_options(git_notes_copy_usage, options);
625         }
626
627         if (get_sha1(argv[0], from_obj))
628                 die("Failed to resolve '%s' as a valid ref.", argv[0]);
629
630         object_ref = 1 < argc ? argv[1] : "HEAD";
631
632         if (get_sha1(object_ref, object))
633                 die("Failed to resolve '%s' as a valid ref.", object_ref);
634
635         t = init_notes_check("copy");
636         note = get_note(t, object);
637
638         if (note) {
639                 if (!force) {
640                         retval = error("Cannot copy notes. Found existing "
641                                        "notes for object %s. Use '-f' to "
642                                        "overwrite existing notes",
643                                        sha1_to_hex(object));
644                         goto out;
645                 }
646                 fprintf(stderr, "Overwriting existing notes for object %s\n",
647                         sha1_to_hex(object));
648         }
649
650         from_note = get_note(t, from_obj);
651         if (!from_note) {
652                 retval = error("Missing notes on source object %s. Cannot "
653                                "copy.", sha1_to_hex(from_obj));
654                 goto out;
655         }
656
657         if (add_note(t, object, from_note, combine_notes_overwrite))
658                 die("BUG: combine_notes_overwrite failed");
659         commit_notes(t, "Notes added by 'git notes copy'");
660 out:
661         free_notes(t);
662         return retval;
663 }
664
665 static int append_edit(int argc, const char **argv, const char *prefix)
666 {
667         const char *object_ref;
668         struct notes_tree *t;
669         unsigned char object[20], new_note[20];
670         const unsigned char *note;
671         char logmsg[100];
672         const char * const *usage;
673         struct msg_arg msg = { 0, 0, STRBUF_INIT };
674         struct option options[] = {
675                 { OPTION_CALLBACK, 'm', "message", &msg, "msg",
676                         "note contents as a string", PARSE_OPT_NONEG,
677                         parse_msg_arg},
678                 { OPTION_CALLBACK, 'F', "file", &msg, "file",
679                         "note contents in a file", PARSE_OPT_NONEG,
680                         parse_file_arg},
681                 { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
682                         "reuse and edit specified note object", PARSE_OPT_NONEG,
683                         parse_reedit_arg},
684                 { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
685                         "reuse specified note object", PARSE_OPT_NONEG,
686                         parse_reuse_arg},
687                 OPT_END()
688         };
689         int edit = !strcmp(argv[0], "edit");
690
691         usage = edit ? git_notes_edit_usage : git_notes_append_usage;
692         argc = parse_options(argc, argv, prefix, options, usage,
693                              PARSE_OPT_KEEP_ARGV0);
694
695         if (2 < argc) {
696                 error("too many parameters");
697                 usage_with_options(usage, options);
698         }
699
700         if (msg.given && edit)
701                 fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
702                         "for the 'edit' subcommand.\n"
703                         "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
704
705         object_ref = 1 < argc ? argv[1] : "HEAD";
706
707         if (get_sha1(object_ref, object))
708                 die("Failed to resolve '%s' as a valid ref.", object_ref);
709
710         t = init_notes_check(argv[0]);
711         note = get_note(t, object);
712
713         create_note(object, &msg, !edit, note, new_note);
714
715         if (is_null_sha1(new_note))
716                 remove_note(t, object);
717         else if (add_note(t, object, new_note, combine_notes_overwrite))
718                 die("BUG: combine_notes_overwrite failed");
719
720         snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
721                  is_null_sha1(new_note) ? "removed" : "added", argv[0]);
722         commit_notes(t, logmsg);
723         free_notes(t);
724         strbuf_release(&(msg.buf));
725         return 0;
726 }
727
728 static int show(int argc, const char **argv, const char *prefix)
729 {
730         const char *object_ref;
731         struct notes_tree *t;
732         unsigned char object[20];
733         const unsigned char *note;
734         int retval;
735         struct option options[] = {
736                 OPT_END()
737         };
738
739         argc = parse_options(argc, argv, prefix, options, git_notes_show_usage,
740                              0);
741
742         if (1 < argc) {
743                 error("too many parameters");
744                 usage_with_options(git_notes_show_usage, options);
745         }
746
747         object_ref = argc ? argv[0] : "HEAD";
748
749         if (get_sha1(object_ref, object))
750                 die("Failed to resolve '%s' as a valid ref.", object_ref);
751
752         t = init_notes_check("show");
753         note = get_note(t, object);
754
755         if (!note)
756                 retval = error("No note found for object %s.",
757                                sha1_to_hex(object));
758         else {
759                 const char *show_args[3] = {"show", sha1_to_hex(note), NULL};
760                 retval = execv_git_cmd(show_args);
761         }
762         free_notes(t);
763         return retval;
764 }
765
766 static int merge_abort(struct notes_merge_options *o)
767 {
768         int ret = 0;
769
770         /*
771          * Remove .git/NOTES_MERGE_PARTIAL and .git/NOTES_MERGE_REF, and call
772          * notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
773          */
774
775         if (delete_ref("NOTES_MERGE_PARTIAL", NULL, 0))
776                 ret += error("Failed to delete ref NOTES_MERGE_PARTIAL");
777         if (delete_ref("NOTES_MERGE_REF", NULL, REF_NODEREF))
778                 ret += error("Failed to delete ref NOTES_MERGE_REF");
779         if (notes_merge_abort(o))
780                 ret += error("Failed to remove 'git notes merge' worktree");
781         return ret;
782 }
783
784 static int merge_commit(struct notes_merge_options *o)
785 {
786         struct strbuf msg = STRBUF_INIT;
787         unsigned char sha1[20], parent_sha1[20];
788         struct notes_tree *t;
789         struct commit *partial;
790         struct pretty_print_context pretty_ctx;
791
792         /*
793          * Read partial merge result from .git/NOTES_MERGE_PARTIAL,
794          * and target notes ref from .git/NOTES_MERGE_REF.
795          */
796
797         if (get_sha1("NOTES_MERGE_PARTIAL", sha1))
798                 die("Failed to read ref NOTES_MERGE_PARTIAL");
799         else if (!(partial = lookup_commit_reference(sha1)))
800                 die("Could not find commit from NOTES_MERGE_PARTIAL.");
801         else if (parse_commit(partial))
802                 die("Could not parse commit from NOTES_MERGE_PARTIAL.");
803
804         if (partial->parents)
805                 hashcpy(parent_sha1, partial->parents->item->object.sha1);
806         else
807                 hashclr(parent_sha1);
808
809         t = xcalloc(1, sizeof(struct notes_tree));
810         init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
811
812         o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
813         if (!o->local_ref)
814                 die("Failed to resolve NOTES_MERGE_REF");
815
816         if (notes_merge_commit(o, t, partial, sha1))
817                 die("Failed to finalize notes merge");
818
819         /* Reuse existing commit message in reflog message */
820         memset(&pretty_ctx, 0, sizeof(pretty_ctx));
821         format_commit_message(partial, "%s", &msg, &pretty_ctx);
822         strbuf_trim(&msg);
823         strbuf_insert(&msg, 0, "notes: ", 7);
824         update_ref(msg.buf, o->local_ref, sha1,
825                    is_null_sha1(parent_sha1) ? NULL : parent_sha1,
826                    0, DIE_ON_ERR);
827
828         free_notes(t);
829         strbuf_release(&msg);
830         return merge_abort(o);
831 }
832
833 static int merge(int argc, const char **argv, const char *prefix)
834 {
835         struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
836         unsigned char result_sha1[20];
837         struct notes_tree *t;
838         struct notes_merge_options o;
839         int do_merge = 0, do_commit = 0, do_abort = 0;
840         int verbosity = 0, result;
841         const char *strategy = NULL;
842         struct option options[] = {
843                 OPT_GROUP("General options"),
844                 OPT__VERBOSITY(&verbosity),
845                 OPT_GROUP("Merge options"),
846                 OPT_STRING('s', "strategy", &strategy, "strategy",
847                            "resolve notes conflicts using the given strategy "
848                            "(manual/ours/theirs/union/cat_sort_uniq)"),
849                 OPT_GROUP("Committing unmerged notes"),
850                 { OPTION_BOOLEAN, 0, "commit", &do_commit, NULL,
851                         "finalize notes merge by committing unmerged notes",
852                         PARSE_OPT_NOARG | PARSE_OPT_NONEG },
853                 OPT_GROUP("Aborting notes merge resolution"),
854                 { OPTION_BOOLEAN, 0, "abort", &do_abort, NULL,
855                         "abort notes merge",
856                         PARSE_OPT_NOARG | PARSE_OPT_NONEG },
857                 OPT_END()
858         };
859
860         argc = parse_options(argc, argv, prefix, options,
861                              git_notes_merge_usage, 0);
862
863         if (strategy || do_commit + do_abort == 0)
864                 do_merge = 1;
865         if (do_merge + do_commit + do_abort != 1) {
866                 error("cannot mix --commit, --abort or -s/--strategy");
867                 usage_with_options(git_notes_merge_usage, options);
868         }
869
870         if (do_merge && argc != 1) {
871                 error("Must specify a notes ref to merge");
872                 usage_with_options(git_notes_merge_usage, options);
873         } else if (!do_merge && argc) {
874                 error("too many parameters");
875                 usage_with_options(git_notes_merge_usage, options);
876         }
877
878         init_notes_merge_options(&o);
879         o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;
880
881         if (do_abort)
882                 return merge_abort(&o);
883         if (do_commit)
884                 return merge_commit(&o);
885
886         o.local_ref = default_notes_ref();
887         strbuf_addstr(&remote_ref, argv[0]);
888         expand_notes_ref(&remote_ref);
889         o.remote_ref = remote_ref.buf;
890
891         if (strategy) {
892                 if (!strcmp(strategy, "manual"))
893                         o.strategy = NOTES_MERGE_RESOLVE_MANUAL;
894                 else if (!strcmp(strategy, "ours"))
895                         o.strategy = NOTES_MERGE_RESOLVE_OURS;
896                 else if (!strcmp(strategy, "theirs"))
897                         o.strategy = NOTES_MERGE_RESOLVE_THEIRS;
898                 else if (!strcmp(strategy, "union"))
899                         o.strategy = NOTES_MERGE_RESOLVE_UNION;
900                 else if (!strcmp(strategy, "cat_sort_uniq"))
901                         o.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;
902                 else {
903                         error("Unknown -s/--strategy: %s", strategy);
904                         usage_with_options(git_notes_merge_usage, options);
905                 }
906         }
907
908         t = init_notes_check("merge");
909
910         strbuf_addf(&msg, "notes: Merged notes from %s into %s",
911                     remote_ref.buf, default_notes_ref());
912         strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
913
914         result = notes_merge(&o, t, result_sha1);
915
916         if (result >= 0) /* Merge resulted (trivially) in result_sha1 */
917                 /* Update default notes ref with new commit */
918                 update_ref(msg.buf, default_notes_ref(), result_sha1, NULL,
919                            0, DIE_ON_ERR);
920         else { /* Merge has unresolved conflicts */
921                 /* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
922                 update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_sha1, NULL,
923                            0, DIE_ON_ERR);
924                 /* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
925                 if (create_symref("NOTES_MERGE_REF", default_notes_ref(), NULL))
926                         die("Failed to store link to current notes ref (%s)",
927                             default_notes_ref());
928                 printf("Automatic notes merge failed. Fix conflicts in %s and "
929                        "commit the result with 'git notes merge --commit', or "
930                        "abort the merge with 'git notes merge --abort'.\n",
931                        git_path(NOTES_MERGE_WORKTREE));
932         }
933
934         free_notes(t);
935         strbuf_release(&remote_ref);
936         strbuf_release(&msg);
937         return result < 0; /* return non-zero on conflicts */
938 }
939
940 static int remove_cmd(int argc, const char **argv, const char *prefix)
941 {
942         struct option options[] = {
943                 OPT_END()
944         };
945         const char *object_ref;
946         struct notes_tree *t;
947         unsigned char object[20];
948         int retval;
949
950         argc = parse_options(argc, argv, prefix, options,
951                              git_notes_remove_usage, 0);
952
953         if (1 < argc) {
954                 error("too many parameters");
955                 usage_with_options(git_notes_remove_usage, options);
956         }
957
958         object_ref = argc ? argv[0] : "HEAD";
959
960         if (get_sha1(object_ref, object))
961                 die("Failed to resolve '%s' as a valid ref.", object_ref);
962
963         t = init_notes_check("remove");
964
965         retval = remove_note(t, object);
966         if (retval)
967                 fprintf(stderr, "Object %s has no note\n", sha1_to_hex(object));
968         else {
969                 fprintf(stderr, "Removing note for object %s\n",
970                         sha1_to_hex(object));
971
972                 commit_notes(t, "Notes removed by 'git notes remove'");
973         }
974         free_notes(t);
975         return retval;
976 }
977
978 static int prune(int argc, const char **argv, const char *prefix)
979 {
980         struct notes_tree *t;
981         int show_only = 0, verbose = 0;
982         struct option options[] = {
983                 OPT__DRY_RUN(&show_only, "do not remove, show only"),
984                 OPT__VERBOSE(&verbose, "report pruned notes"),
985                 OPT_END()
986         };
987
988         argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage,
989                              0);
990
991         if (argc) {
992                 error("too many parameters");
993                 usage_with_options(git_notes_prune_usage, options);
994         }
995
996         t = init_notes_check("prune");
997
998         prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) |
999                 (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) );
1000         if (!show_only)
1001                 commit_notes(t, "Notes removed by 'git notes prune'");
1002         free_notes(t);
1003         return 0;
1004 }
1005
1006 static int get_ref(int argc, const char **argv, const char *prefix)
1007 {
1008         struct option options[] = { OPT_END() };
1009         argc = parse_options(argc, argv, prefix, options,
1010                              git_notes_get_ref_usage, 0);
1011
1012         if (argc) {
1013                 error("too many parameters");
1014                 usage_with_options(git_notes_get_ref_usage, options);
1015         }
1016
1017         puts(default_notes_ref());
1018         return 0;
1019 }
1020
1021 int cmd_notes(int argc, const char **argv, const char *prefix)
1022 {
1023         int result;
1024         const char *override_notes_ref = NULL;
1025         struct option options[] = {
1026                 OPT_STRING(0, "ref", &override_notes_ref, "notes_ref",
1027                            "use notes from <notes_ref>"),
1028                 OPT_END()
1029         };
1030
1031         git_config(git_default_config, NULL);
1032         argc = parse_options(argc, argv, prefix, options, git_notes_usage,
1033                              PARSE_OPT_STOP_AT_NON_OPTION);
1034
1035         if (override_notes_ref) {
1036                 struct strbuf sb = STRBUF_INIT;
1037                 strbuf_addstr(&sb, override_notes_ref);
1038                 expand_notes_ref(&sb);
1039                 setenv("GIT_NOTES_REF", sb.buf, 1);
1040                 strbuf_release(&sb);
1041         }
1042
1043         if (argc < 1 || !strcmp(argv[0], "list"))
1044                 result = list(argc, argv, prefix);
1045         else if (!strcmp(argv[0], "add"))
1046                 result = add(argc, argv, prefix);
1047         else if (!strcmp(argv[0], "copy"))
1048                 result = copy(argc, argv, prefix);
1049         else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
1050                 result = append_edit(argc, argv, prefix);
1051         else if (!strcmp(argv[0], "show"))
1052                 result = show(argc, argv, prefix);
1053         else if (!strcmp(argv[0], "merge"))
1054                 result = merge(argc, argv, prefix);
1055         else if (!strcmp(argv[0], "remove"))
1056                 result = remove_cmd(argc, argv, prefix);
1057         else if (!strcmp(argv[0], "prune"))
1058                 result = prune(argc, argv, prefix);
1059         else if (!strcmp(argv[0], "get-ref"))
1060                 result = get_ref(argc, argv, prefix);
1061         else {
1062                 result = error("Unknown subcommand: %s", argv[0]);
1063                 usage_with_options(git_notes_usage, options);
1064         }
1065
1066         return result ? 1 : 0;
1067 }