builtin/notes: add --allow-empty, to allow storing empty notes

Although the "git notes" man page advertises that we support binary-safe notes addition (using the -C option), we currently do not support adding the empty note (i.e. using the empty blob to annotate an object). Instead, an empty note is always treated as an intent to remove the note altogether. Introduce the --allow-empty option to the add/append/edit subcommands, to explicitly allow an empty note to be stored into the notes tree. Also update the documentation, and add test cases for the new option. Reported-by: James H. Fisher <jhf@trifork.com> Improved-by: Kyle J. McKay <mackyle@gmail.com> Improved-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johan Herland committed Nov 12, 2014 at 01:40 UTC d73a5b933db1e722faa54d6709e89e2450d7c1e3
3 files changed +28 -11
Documentation/git-notes.txt
+8 -4
@@ -9,10 +9,10 @@ SYNOPSIS
9 --------
10 [verse]
11 'git notes' [list [<object>]]
12 -'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
12 +'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
13 'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
14 -'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
15 -'git notes' edit [<object>]
14 +'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
15 +'git notes' edit [--allow-empty] [<object>]
16 'git notes' show [<object>]
17 'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
18 'git notes' merge --commit [-v | -q]
@@ -155,6 +155,10 @@ OPTIONS
155 Like '-C', but with '-c' the editor is invoked, so that
156 the user can further edit the note message.
157
158 +--allow-empty::
159 + Allow an empty note object to be stored. The default behavior is
160 + to automatically remove empty notes.
161 +
162 --ref <ref>::
163 Manipulate the notes tree in <ref>. This overrides
164 'GIT_NOTES_REF' and the "core.notesRef" configuration. The ref
@@ -287,7 +291,7 @@ arbitrary files using 'git hash-object':
291 ------------
292 $ cc *.c
293 $ blob=$(git hash-object -w a.out)
290 -$ git notes --ref=built add -C "$blob" HEAD
294 +$ git notes --ref=built add --allow-empty -C "$blob" HEAD
295 ------------
296
297 (You cannot simply use `git notes --ref=built add -F a.out HEAD`
builtin/notes.c
+11 -6
@@ -22,10 +22,10 @@
22
23 static const char * const git_notes_usage[] = {
24 N_("git notes [--ref <notes_ref>] [list [<object>]]"),
25 - N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
25 + N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
26 N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
27 - N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
28 - N_("git notes [--ref <notes_ref>] edit [<object>]"),
27 + N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
28 + N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"),
29 N_("git notes [--ref <notes_ref>] show [<object>]"),
30 N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
31 N_("git notes merge --commit [-v | -q]"),
@@ -381,7 +381,7 @@ static int append_edit(int argc, const char **argv, const char *prefix);
381
382 static int add(int argc, const char **argv, const char *prefix)
383 {
384 - int force = 0;
384 + int force = 0, allow_empty = 0;
385 const char *object_ref;
386 struct notes_tree *t;
387 unsigned char object[20], new_note[20];
@@ -400,6 +400,8 @@ static int add(int argc, const char **argv, const char *prefix)
400 { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
401 N_("reuse specified note object"), PARSE_OPT_NONEG,
402 parse_reuse_arg},
403 + OPT_BOOL(0, "allow-empty", &allow_empty,
404 + N_("allow storing empty note")),
405 OPT__FORCE(&force, N_("replace existing notes")),
406 OPT_END()
407 };
@@ -445,7 +447,7 @@ static int add(int argc, const char **argv, const char *prefix)
447 }
448
449 prepare_note_data(object, &d, note);
448 - if (d.buf.len) {
450 + if (d.buf.len || allow_empty) {
451 write_note_data(&d, new_note);
452 if (add_note(t, object, new_note, combine_notes_overwrite))
453 die("BUG: combine_notes_overwrite failed");
@@ -540,6 +542,7 @@ out:
542
543 static int append_edit(int argc, const char **argv, const char *prefix)
544 {
545 + int allow_empty = 0;
546 const char *object_ref;
547 struct notes_tree *t;
548 unsigned char object[20], new_note[20];
@@ -560,6 +563,8 @@ static int append_edit(int argc, const char **argv, const char *prefix)
563 { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
564 N_("reuse specified note object"), PARSE_OPT_NONEG,
565 parse_reuse_arg},
566 + OPT_BOOL(0, "allow-empty", &allow_empty,
567 + N_("allow storing empty note")),
568 OPT_END()
569 };
570 int edit = !strcmp(argv[0], "edit");
@@ -602,7 +607,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
607 free(prev_buf);
608 }
609
605 - if (d.buf.len) {
610 + if (d.buf.len || allow_empty) {
611 write_note_data(&d, new_note);
612 if (add_note(t, object, new_note, combine_notes_overwrite))
613 die("BUG: combine_notes_overwrite failed");
t/t3301-notes.sh
+9 -1
@@ -1242,7 +1242,8 @@ test_expect_success 'git notes get-ref (--ref)' '
1242 test_expect_success 'setup testing of empty notes' '
1243 test_unconfig core.notesRef &&
1244 test_commit 16th &&
1245 - empty_blob=$(git hash-object -w /dev/null)
1245 + empty_blob=$(git hash-object -w /dev/null) &&
1246 + echo "$empty_blob" >expect_empty
1247 '
1248
1249 while read cmd
@@ -1252,6 +1253,13 @@ do
1253 MSG= git notes $cmd &&
1254 test_must_fail git notes list HEAD
1255 "
1256 +
1257 + test_expect_success "'git notes $cmd --allow-empty' stores empty note" "
1258 + test_might_fail git notes remove HEAD &&
1259 + MSG= git notes $cmd --allow-empty &&
1260 + git notes list HEAD >actual &&
1261 + test_cmp expect_empty actual
1262 + "
1263 done <<\EOF
1264 add
1265 add -F /dev/null