From: Teng Long <dyroneteng@xxxxxxxxx> When adding new notes or appending to an existing notes, we will insert a blank line between the paragraphs, like: $ git notes add -m foo -m bar $ git notes show HEAD | cat foo bar The default behavour sometimes is not enough, the user may want to use a custom delimiter between paragraphs, like when specifiy one or more '-m' or '-F' options. So this commit introduces a new '--separator' option for 'git-notes-add' and 'git-notes-append', for example when execute: $ git notes add -m foo -m bar --separator="-" $ git notes show HEAD | cat foo - bar We will check the option value and if the value doesn't contail a trailing '\n', will add it automatically, so execute $ git notes add -m foo -m bar --separator="-" and $ export LF=" " $ git notes add -m foo -m bar --separator="-$LF" have the same behavour. Signed-off-by: Teng Long <dyroneteng@xxxxxxxxx> --- Documentation/git-notes.txt | 20 ++++++-- builtin/notes.c | 72 ++++++++++++++++++-------- t/t3301-notes.sh | 100 ++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 26 deletions(-) diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index efbc10f0..53d63888 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -9,9 +9,9 @@ SYNOPSIS -------- [verse] 'git notes' [list [<object>]] -'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>] +'git notes' add [-f] [--allow-empty] [--separator=<paragraph-break>] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>] 'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] ) -'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>] +'git notes' append [--allow-empty] [--separator=<paragraph-break>] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>] 'git notes' edit [--allow-empty] [<object>] 'git notes' show [<object>] 'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref> @@ -65,7 +65,9 @@ add:: However, if you're using `add` interactively (using an editor to supply the notes contents), then - instead of aborting - the existing notes will be opened in the editor (like the `edit` - subcommand). + subcommand). If you specify multiple `-m` and `-F`, a blank + line will be inserted between the messages. Use the `--separator` + option to insert other delimiters. copy:: Copy the notes for the first object onto the second object (defaults to @@ -86,7 +88,13 @@ the command can read the input given to the `post-rewrite` hook.) append:: Append to the notes of an existing object (defaults to HEAD). - Creates a new notes object if needed. + Creates a new notes object if needed. + The default delimiter is a blank line, use the `--separator` + option to insert other delimiters. More specifically, if the + note and the message are not empty, the delimiter will be + inserted between them. If you specify multiple `-m` and `-F` + options, the delimiter will be inserted between the messages + too. edit:: Edit the notes for a given object (defaults to HEAD). @@ -159,6 +167,10 @@ OPTIONS Allow an empty note object to be stored. The default behavior is to automatically remove empty notes. +--separator <paragraph-break>:: + The '<paragraph-break>' inserted between paragraphs. + A blank line by default. + --ref <ref>:: Manipulate the notes tree in <ref>. This overrides `GIT_NOTES_REF` and the "core.notesRef" configuration. The ref diff --git a/builtin/notes.c b/builtin/notes.c index 553ae2bd..e0ada862 100644 --- a/builtin/notes.c +++ b/builtin/notes.c @@ -24,11 +24,12 @@ #include "notes-utils.h" #include "worktree.h" +static char *separator = NULL; static const char * const git_notes_usage[] = { N_("git notes [--ref <notes-ref>] [list [<object>]]"), - N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"), - N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), + N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"), N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"), N_("git notes [--ref <notes-ref>] show [<object>]"), N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"), @@ -209,37 +210,55 @@ static void write_note_data(struct note_data *d, struct object_id *oid) } } +static void insert_separator(struct strbuf *message, size_t pos) +{ + if (!separator) + strbuf_insertstr(message, pos, "\n"); + else if (separator[strlen(separator) - 1] == '\n') + strbuf_insertstr(message, pos, separator); + else + strbuf_insertf(message, pos, "%s%s", separator, "\n"); +} + +static void parse_messages(struct string_list *messages, struct note_data *d) +{ + size_t i; + for (i = 0; i < messages->nr; i++) { + if (d->buf.len) + insert_separator(&d->buf, d->buf.len); + strbuf_insertstr(&d->buf, d->buf.len, + messages->items[i].string); + strbuf_stripspace(&d->buf, 0); + d->given = 1; + } +} + static int parse_msg_arg(const struct option *opt, const char *arg, int unset) { - struct note_data *d = opt->value; + struct string_list *msg = opt->value; BUG_ON_OPT_NEG(unset); - if (d->buf.len) - strbuf_addch(&d->buf, '\n'); - strbuf_addstr(&d->buf, arg); - strbuf_stripspace(&d->buf, 0); - - d->given = 1; + string_list_append(msg, arg); return 0; } + static int parse_file_arg(const struct option *opt, const char *arg, int unset) { - struct note_data *d = opt->value; + struct string_list *msg = opt->value; + struct strbuf buf = STRBUF_INIT; BUG_ON_OPT_NEG(unset); - if (d->buf.len) - strbuf_addch(&d->buf, '\n'); if (!strcmp(arg, "-")) { - if (strbuf_read(&d->buf, 0, 1024) < 0) + if (strbuf_read(&buf, 0, 1024) < 0) die_errno(_("cannot read '%s'"), arg); - } else if (strbuf_read_file(&d->buf, arg, 1024) < 0) + } else if (strbuf_read_file(&buf, arg, 1024) < 0) die_errno(_("could not open or read '%s'"), arg); - strbuf_stripspace(&d->buf, 0); - d->given = 1; + string_list_append(msg, buf.buf); + strbuf_release(&buf); return 0; } @@ -402,11 +421,12 @@ static int add(int argc, const char **argv, const char *prefix) struct object_id object, new_note; const struct object_id *note; struct note_data d = { .buf = STRBUF_INIT }; + struct string_list messages = STRING_LIST_INIT_DUP; struct option options[] = { - OPT_CALLBACK_F('m', "message", &d, N_("message"), + OPT_CALLBACK_F('m', "message", &messages, N_("message"), N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg), - OPT_CALLBACK_F('F', "file", &d, N_("file"), + OPT_CALLBACK_F('F', "file", &messages, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg), OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"), @@ -418,6 +438,8 @@ static int add(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE), + OPT_STRING(0, "separator", &separator, N_("separator"), + N_("insert <paragraph-break> between paragraphs")), OPT_END() }; @@ -429,6 +451,7 @@ static int add(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_add_usage, options); } + parse_messages(&messages, &d); object_ref = argc > 1 ? argv[1] : "HEAD"; if (get_oid(object_ref, &object)) @@ -568,11 +591,12 @@ static int append_edit(int argc, const char **argv, const char *prefix) char *logmsg; const char * const *usage; struct note_data d = { .buf = STRBUF_INIT }; + struct string_list messages = STRING_LIST_INIT_DUP; struct option options[] = { - OPT_CALLBACK_F('m', "message", &d, N_("message"), - N_("note contents as a string"), PARSE_OPT_NONEG, + OPT_CALLBACK_F('m', "message", &messages, N_("message"), + N_("note contents as a string"), PARSE_OPT_NONEG, parse_msg_arg), - OPT_CALLBACK_F('F', "file", &d, N_("file"), + OPT_CALLBACK_F('F', "file", &messages, N_("file"), N_("note contents in a file"), PARSE_OPT_NONEG, parse_file_arg), OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"), @@ -583,6 +607,8 @@ static int append_edit(int argc, const char **argv, const char *prefix) parse_reuse_arg), OPT_BOOL(0, "allow-empty", &allow_empty, N_("allow storing empty note")), + OPT_STRING(0, "separator", &separator, N_("separator"), + N_("insert <paragraph-break> between paragraphs")), OPT_END() }; int edit = !strcmp(argv[0], "edit"); @@ -596,6 +622,8 @@ static int append_edit(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); } + parse_messages(&messages, &d); + if (d.given && edit) fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated " "for the 'edit' subcommand.\n" @@ -618,7 +646,7 @@ static int append_edit(int argc, const char **argv, const char *prefix) char *prev_buf = read_object_file(note, &type, &size); if (d.buf.len && prev_buf && size) - strbuf_insertstr(&d.buf, 0, "\n"); + insert_separator(&d.buf, 0); if (prev_buf && size) strbuf_insert(&d.buf, 0, prev_buf, size); free(prev_buf); diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index 3288aaec..c2c09f32 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -362,6 +362,7 @@ test_expect_success 'do not create empty note with -m ""' ' ' test_expect_success 'create note with combination of -m and -F' ' + test_when_finished git notes remove HEAD && cat >expect-combine_m_and_F <<-EOF && foo @@ -380,6 +381,26 @@ test_expect_success 'create note with combination of -m and -F' ' test_cmp expect-combine_m_and_F actual ' +test_expect_success 'create note with combination of -m and -F and --separator' ' + cat >expect-combine_m_and_F <<-\EOF && + foo + ------- + xyzzy + ------- + bar + ------- + zyxxy + ------- + baz + EOF + echo "xyzzy" >note_a && + echo "zyxxy" >note_b && + git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" --separator "-------" && + git notes show >actual && + test_cmp expect-combine_m_and_F actual + +' + test_expect_success 'remove note with "git notes remove"' ' git notes remove HEAD^ && git notes remove && @@ -521,6 +542,85 @@ test_expect_success 'listing non-existing notes fails' ' test_must_be_empty actual ' +test_expect_success 'append: specify an empty separator' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator with line break' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------$LF" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator without line break' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------" -m "notes-2" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append: specify separator with multiple messages' ' + test_when_finished git notes remove HEAD && + cat >expect <<-\EOF && + notes-1 + ------- + notes-2 + ------- + notes-3 + EOF + + git notes add -m "notes-1" && + git notes append --separator="-------" -m "notes-2" -m "notes-3" && + git notes show >actual && + test_cmp expect actual +' + +test_expect_success 'append note with combination of -m and -F and --separator' ' + test_when_finished git notes remove HEAD && + cat >expect-combine_m_and_F <<-\EOF && + m-notes-1 + ------- + f-notes-1 + ------- + m-notes-2 + ------- + f-notes-2 + ------- + m-notes-3 + EOF + + echo "f-notes-1" >note_a && + echo "f-notes-2" >note_b && + git notes append -m "m-notes-1" -F note_a -m "m-notes-2" -F note_b -m "m-notes-3" --separator "-------" && + git notes show >actual && + test_cmp expect-combine_m_and_F actual +' + test_expect_success 'append to existing note with "git notes append"' ' cat >expect <<-EOF && Initial set of notes -- 2.39.2.459.gd5a6c747