@matheusbsbs / matheus-bagliano / commits / 0691cff7dc
Fork 0

builtin-notes: Add -c/-C options for reusing notes

Inspired by the -c/-C options to "git commit", we teach these options to "git notes add/append" to allow reuse of note objects. With this patch in place, it is now easy to copy or move notes between objects. For example, to copy object A's notes to object B: git notes add [-f] -C $(git notes list A) B To move instead of copying, you simply remove the notes from the source object afterwards, e.g.: git notes remove A The patch includes tests verifying correct behaviour of the new functionality. Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johan Herland committed Feb 13, 2010 at 22:28 UTC 0691cff7dca6b68569183be991d59ebb72b6170e
3 files changed +179 -12
Documentation/git-notes.txt
+10 -2
@@ -9,8 +9,8 @@ SYNOPSIS
9 --------
10 [verse]
11 'git notes' [list [<object>]]
12 -'git notes' add [-f] [-F <file> | -m <msg>] [<object>]
13 -'git notes' append [-F <file> | -m <msg>] [<object>]
12 +'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
13 +'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
14 'git notes' edit [<object>]
15 'git notes' show [<object>]
16 'git notes' remove [<object>]
@@ -84,6 +84,14 @@ OPTIONS
84 Take the note message from the given file. Use '-' to
85 read the note message from the standard input.
86
87 +-C <object>::
88 +--reuse-message=<object>::
89 + Reuse the note message from the given note object.
90 +
91 +-c <object>::
92 +--reedit-message=<object>::
93 + Like '-C', but with '-c' the editor is invoked, so that
94 + the user can further edit the note message.
95
96 Author
97 ------
builtin-notes.c
+53 -10
@@ -19,8 +19,8 @@
19
20 static const char * const git_notes_usage[] = {
21 "git notes [list [<object>]]",
22 - "git notes add [-f] [-m <msg> | -F <file>] [<object>]",
23 - "git notes append [-m <msg> | -F <file>] [<object>]",
22 + "git notes add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
23 + "git notes append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
24 "git notes edit [<object>]",
25 "git notes show [<object>]",
26 "git notes remove [<object>]",
@@ -36,6 +36,7 @@ static const char note_template[] =
36
37 struct msg_arg {
38 int given;
39 + int use_editor;
40 struct strbuf buf;
41 };
42
@@ -104,7 +105,7 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
105 {
106 char *path = NULL;
107
107 - if (!msg->given) {
108 + if (msg->use_editor || !msg->given) {
109 int fd;
110
111 /* write the template message before editing: */
@@ -113,13 +114,16 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
114 if (fd < 0)
115 die_errno("could not create file '%s'", path);
116
116 - if (prev && !append_only)
117 + if (msg->given)
118 + write_or_die(fd, msg->buf.buf, msg->buf.len);
119 + else if (prev && !append_only)
120 write_note_data(fd, prev);
121 write_or_die(fd, note_template, strlen(note_template));
122
123 write_commented_object(fd, object);
124
125 close(fd);
126 + strbuf_reset(&(msg->buf));
127
128 if (launch_editor(path, &(msg->buf), NULL)) {
129 die("Please supply the note contents using either -m" \
@@ -199,6 +203,40 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)
203 return 0;
204 }
205
206 +static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
207 +{
208 + struct msg_arg *msg = opt->value;
209 + char *buf;
210 + unsigned char object[20];
211 + enum object_type type;
212 + unsigned long len;
213 +
214 + if (!arg)
215 + return -1;
216 +
217 + if (msg->buf.len)
218 + strbuf_addstr(&(msg->buf), "\n");
219 +
220 + if (get_sha1(arg, object))
221 + die("Failed to resolve '%s' as a valid ref.", arg);
222 + if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
223 + free(buf);
224 + die("Failed to read object '%s'.", arg);;
225 + }
226 + strbuf_add(&(msg->buf), buf, len);
227 + free(buf);
228 +
229 + msg->given = 1;
230 + return 0;
231 +}
232 +
233 +static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
234 +{
235 + struct msg_arg *msg = opt->value;
236 + msg->use_editor = 1;
237 + return parse_reuse_arg(opt, arg, unset);
238 +}
239 +
240 int commit_notes(struct notes_tree *t, const char *msg)
241 {
242 struct commit_list *parent;
@@ -250,13 +288,17 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
288 int list = 0, add = 0, append = 0, edit = 0, show = 0, remove = 0,
289 prune = 0, force = 0;
290 int given_object;
253 - struct msg_arg msg = { 0, STRBUF_INIT };
291 + struct msg_arg msg = { 0, 0, STRBUF_INIT };
292 struct option options[] = {
293 OPT_GROUP("Notes options"),
294 OPT_CALLBACK('m', "message", &msg, "MSG",
295 "note contents as a string", parse_msg_arg),
296 OPT_CALLBACK('F', "file", &msg, "FILE",
297 "note contents in a file", parse_file_arg),
298 + OPT_CALLBACK('c', "reedit-message", &msg, "OBJECT",
299 + "reuse and edit specified note object", parse_reedit_arg),
300 + OPT_CALLBACK('C', "reuse-message", &msg, "OBJECT",
301 + "reuse specified note object", parse_reuse_arg),
302 OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
303 OPT_END()
304 };
@@ -286,17 +328,17 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
328 usage_with_options(git_notes_usage, options);
329
330 if (msg.given && !(add || append || edit)) {
289 - error("cannot use -m/-F options with %s subcommand.", argv[0]);
331 + error("cannot use -m/-F/-c/-C options with %s subcommand.",
332 + argv[0]);
333 usage_with_options(git_notes_usage, options);
334 }
335
336 if (msg.given && edit) {
294 - fprintf(stderr, "The -m and -F options has been deprecated for"
295 - " the 'edit' subcommand.\n"
296 - "Please use 'git notes add -f -m/-F' instead.\n");
337 + fprintf(stderr, "The -m/-F/-c/-C options have been deprecated "
338 + "for the 'edit' subcommand.\n"
339 + "Please use 'git notes add -f -m/-F/-c/-C' instead.\n");
340 }
341
299 -
342 if (force && !add) {
343 error("cannot use -f option with %s subcommand.", argv[0]);
344 usage_with_options(git_notes_usage, options);
@@ -359,6 +401,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
401
402 if (remove) {
403 msg.given = 1;
404 + msg.use_editor = 0;
405 strbuf_reset(&(msg.buf));
406 }
407
t/t3301-notes.sh
+116
@@ -465,4 +465,120 @@ test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
465 test_cmp expect actual
466 '
467
468 +cat > expect << EOF
469 +commit 2ede89468182a62d0bde2583c736089bcf7d7e92
470 +Author: A U Thor <author@example.com>
471 +Date: Thu Apr 7 15:19:13 2005 -0700
472 +
473 + 7th
474 +
475 +Notes:
476 + other note
477 +EOF
478 +
479 +test_expect_success 'create note from other note with "git notes add -C"' '
480 + : > a7 &&
481 + git add a7 &&
482 + test_tick &&
483 + git commit -m 7th &&
484 + git notes add -C $(git notes list HEAD^) &&
485 + git log -1 > actual &&
486 + test_cmp expect actual &&
487 + test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
488 +'
489 +
490 +test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
491 + : > a8 &&
492 + git add a8 &&
493 + test_tick &&
494 + git commit -m 8th &&
495 + test_must_fail git notes add -C deadbeef &&
496 + test_must_fail git notes list HEAD
497 +'
498 +
499 +cat > expect << EOF
500 +commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
501 +Author: A U Thor <author@example.com>
502 +Date: Thu Apr 7 15:21:13 2005 -0700
503 +
504 + 9th
505 +
506 +Notes:
507 + yet another note
508 +EOF
509 +
510 +test_expect_success 'create note from other note with "git notes add -c"' '
511 + : > a9 &&
512 + git add a9 &&
513 + test_tick &&
514 + git commit -m 9th &&
515 + MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
516 + git log -1 > actual &&
517 + test_cmp expect actual
518 +'
519 +
520 +test_expect_success 'create note from non-existing note with "git notes add -c" fails' '
521 + : > a10 &&
522 + git add a10 &&
523 + test_tick &&
524 + git commit -m 10th &&
525 + test_must_fail MSG="yet another note" git notes add -c deadbeef &&
526 + test_must_fail git notes list HEAD
527 +'
528 +
529 +cat > expect << EOF
530 +commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
531 +Author: A U Thor <author@example.com>
532 +Date: Thu Apr 7 15:21:13 2005 -0700
533 +
534 + 9th
535 +
536 +Notes:
537 + yet another note
538 +$whitespace
539 + yet another note
540 +EOF
541 +
542 +test_expect_success 'append to note from other note with "git notes append -C"' '
543 + git notes append -C $(git notes list HEAD^) HEAD^ &&
544 + git log -1 HEAD^ > actual &&
545 + test_cmp expect actual
546 +'
547 +
548 +cat > expect << EOF
549 +commit ffed603236bfa3891c49644257a83598afe8ae5a
550 +Author: A U Thor <author@example.com>
551 +Date: Thu Apr 7 15:22:13 2005 -0700
552 +
553 + 10th
554 +
555 +Notes:
556 + other note
557 +EOF
558 +
559 +test_expect_success 'create note from other note with "git notes append -c"' '
560 + MSG="other note" git notes append -c $(git notes list HEAD^) &&
561 + git log -1 > actual &&
562 + test_cmp expect actual
563 +'
564 +
565 +cat > expect << EOF
566 +commit ffed603236bfa3891c49644257a83598afe8ae5a
567 +Author: A U Thor <author@example.com>
568 +Date: Thu Apr 7 15:22:13 2005 -0700
569 +
570 + 10th
571 +
572 +Notes:
573 + other note
574 +$whitespace
575 + yet another note
576 +EOF
577 +
578 +test_expect_success 'append to note from other note with "git notes append -c"' '
579 + MSG="yet another note" git notes append -c $(git notes list HEAD) &&
580 + git log -1 > actual &&
581 + test_cmp expect actual
582 +'
583 +
584 test_done