Skip to content

Commit 13a14f2

Browse files
committed
notes.c: introduce '--separator=<paragraph-break>' option
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 specifying '-m', '-F', '-C', '-c' options. So this commit introduce a new '--separator' option for 'git notes add' and 'git notes append', for example when executing: $ git notes add -m foo -m bar --separator="-" $ git notes show HEAD | cat foo - bar a newline is added to the value given to --separator if it does not end with one already. So when executing: $ git notes add -m foo -m bar --separator="-" and $ export LF=" " $ git notes add -m foo -m bar --separator="-$LF" Both the two exections produce the same result. Signed-off-by: Teng Long <dyroneteng@gmail.com>
1 parent 11470f0 commit 13a14f2

3 files changed

Lines changed: 240 additions & 31 deletions

File tree

Documentation/git-notes.txt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git notes' [list [<object>]]
12-
'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
12+
'git notes' add [-f] [--allow-empty] [--separator=<paragraph-break>] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
1313
'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
14-
'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
14+
'git notes' append [--allow-empty] [--separator=<paragraph-break>] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
1515
'git notes' edit [--allow-empty] [<object>]
1616
'git notes' show [<object>]
1717
'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
@@ -65,7 +65,9 @@ add::
6565
However, if you're using `add` interactively (using an editor
6666
to supply the notes contents), then - instead of aborting -
6767
the existing notes will be opened in the editor (like the `edit`
68-
subcommand).
68+
subcommand). If you specify multiple `-m` and `-F`, a blank
69+
line will be inserted between the messages. Use the `--separator`
70+
option to insert other delimiters.
6971

7072
copy::
7173
Copy the notes for the first object onto the second object (defaults to
@@ -85,8 +87,12 @@ corresponding <to-object>. (The optional `<rest>` is ignored so that
8587
the command can read the input given to the `post-rewrite` hook.)
8688

8789
append::
88-
Append to the notes of an existing object (defaults to HEAD).
89-
Creates a new notes object if needed.
90+
Append new message(s) given by `-m` or `-F` options to an
91+
existing note, or add them as a new note if one does not
92+
exist, for the object (defaults to HEAD). When appending to
93+
an existing note, a blank line is added before each new
94+
message as an inter-paragraph separator. The separator can
95+
be customized with the `--separator` option.
9096

9197
edit::
9298
Edit the notes for a given object (defaults to HEAD).
@@ -159,6 +165,11 @@ OPTIONS
159165
Allow an empty note object to be stored. The default behavior is
160166
to automatically remove empty notes.
161167

168+
--separator <paragraph-break>::
169+
Specify a string used as a custom inter-paragraph separator
170+
(a newline is added at the end as needed). Defaults to a
171+
blank line.
172+
162173
--ref <ref>::
163174
Manipulate the notes tree in <ref>. This overrides
164175
`GIT_NOTES_REF` and the "core.notesRef" configuration. The ref

builtin/notes.c

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@
2424
#include "notes-utils.h"
2525
#include "worktree.h"
2626

27+
static char *separator = NULL;
2728
static const char * const git_notes_usage[] = {
2829
N_("git notes [--ref <notes-ref>] [list [<object>]]"),
29-
N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
30+
N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
3031
N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
31-
N_("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
32+
N_("git notes [--ref <notes-ref>] append [--allow-empty] [--separator=<paragraph-break>] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
3233
N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
3334
N_("git notes [--ref <notes-ref>] show [<object>]"),
3435
N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
@@ -96,11 +97,19 @@ static const char * const git_notes_get_ref_usage[] = {
9697
static const char note_template[] =
9798
N_("Write/edit the notes for the following object:");
9899

100+
struct note_msg {
101+
int stripspace;
102+
struct strbuf buf;
103+
};
104+
99105
struct note_data {
100106
int given;
101107
int use_editor;
102108
char *edit_path;
103109
struct strbuf buf;
110+
struct note_msg **messages;
111+
size_t msg_nr;
112+
size_t msg_alloc;
104113
};
105114

106115
static void free_note_data(struct note_data *d)
@@ -110,6 +119,13 @@ static void free_note_data(struct note_data *d)
110119
free(d->edit_path);
111120
}
112121
strbuf_release(&d->buf);
122+
123+
while (d->msg_nr) {
124+
--d->msg_nr;
125+
strbuf_release(&d->messages[d->msg_nr]->buf);
126+
free(d->messages[d->msg_nr]);
127+
}
128+
free(d->messages);
113129
}
114130

115131
static int list_each_note(const struct object_id *object_oid,
@@ -209,71 +225,109 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
209225
}
210226
}
211227

228+
static void insert_separator(struct strbuf *message, size_t pos)
229+
{
230+
if (!separator)
231+
strbuf_insertstr(message, pos, "\n");
232+
else if (separator[strlen(separator) - 1] == '\n')
233+
strbuf_insertstr(message, pos, separator);
234+
else
235+
strbuf_insertf(message, pos, "%s%s", separator, "\n");
236+
}
237+
238+
/* Consume messages and append them into d->buf, then free them */
239+
static void concat_messages(struct note_data *d)
240+
{
241+
struct strbuf msg = STRBUF_INIT;
242+
243+
size_t i;
244+
for (i = 0; i < d->msg_nr ; i++) {
245+
if (d->buf.len)
246+
insert_separator(&d->buf, d->buf.len);
247+
strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
248+
strbuf_addbuf(&d->buf, &msg);
249+
if (d->messages[i]->stripspace)
250+
strbuf_stripspace(&d->buf, 0);
251+
strbuf_reset(&msg);
252+
strbuf_release(&d->messages[i]->buf);
253+
free(d->messages[i]);
254+
}
255+
strbuf_release(&msg);
256+
free(d->messages);
257+
}
258+
212259
static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
213260
{
214261
struct note_data *d = opt->value;
262+
struct note_msg *msg = xmalloc(sizeof(*msg));
215263

216264
BUG_ON_OPT_NEG(unset);
217265

218-
if (d->buf.len)
219-
strbuf_addch(&d->buf, '\n');
220-
strbuf_addstr(&d->buf, arg);
221-
strbuf_stripspace(&d->buf, 0);
222-
223-
d->given = 1;
266+
strbuf_init(&msg->buf, strlen(arg));
267+
strbuf_addstr(&msg->buf, arg);
268+
ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
269+
d->messages[d->msg_nr - 1] = msg;
270+
msg->stripspace = 1;
224271
return 0;
225272
}
226273

227274
static int parse_file_arg(const struct option *opt, const char *arg, int unset)
228275
{
229276
struct note_data *d = opt->value;
277+
struct note_msg *msg = xmalloc(sizeof(*msg));
230278

231279
BUG_ON_OPT_NEG(unset);
232280

233-
if (d->buf.len)
234-
strbuf_addch(&d->buf, '\n');
281+
strbuf_init(&msg->buf , 0);
235282
if (!strcmp(arg, "-")) {
236-
if (strbuf_read(&d->buf, 0, 1024) < 0)
283+
if (strbuf_read(&msg->buf, 0, 1024) < 0)
237284
die_errno(_("cannot read '%s'"), arg);
238-
} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
285+
} else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
239286
die_errno(_("could not open or read '%s'"), arg);
240-
strbuf_stripspace(&d->buf, 0);
241287

242-
d->given = 1;
288+
ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
289+
d->messages[d->msg_nr - 1] = msg;
290+
msg->stripspace = 1;
243291
return 0;
244292
}
245293

246294
static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
247295
{
248296
struct note_data *d = opt->value;
249-
char *buf;
297+
struct note_msg *msg = xmalloc(sizeof(*msg));
298+
char *value;
250299
struct object_id object;
251300
enum object_type type;
252301
unsigned long len;
253302

254303
BUG_ON_OPT_NEG(unset);
255304

256-
if (d->buf.len)
257-
strbuf_addch(&d->buf, '\n');
258-
305+
strbuf_init(&msg->buf, 0);
259306
if (get_oid(arg, &object))
260307
die(_("failed to resolve '%s' as a valid ref."), arg);
261-
if (!(buf = read_object_file(&object, &type, &len)))
308+
if (!(value = read_object_file(&object, &type, &len)))
262309
die(_("failed to read object '%s'."), arg);
263310
if (type != OBJ_BLOB) {
264-
free(buf);
311+
strbuf_release(&msg->buf);
312+
free(value);
313+
free(msg);
265314
die(_("cannot read note data from non-blob object '%s'."), arg);
266315
}
267-
strbuf_add(&d->buf, buf, len);
268-
free(buf);
269316

270-
d->given = 1;
317+
strbuf_add(&msg->buf, value, len);
318+
free(value);
319+
320+
msg->buf.len = len;
321+
ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
322+
d->messages[d->msg_nr - 1] = msg;
323+
msg->stripspace = 0;
271324
return 0;
272325
}
273326

274327
static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
275328
{
276329
struct note_data *d = opt->value;
330+
277331
BUG_ON_OPT_NEG(unset);
278332
d->use_editor = 1;
279333
return parse_reuse_arg(opt, arg, unset);
@@ -402,6 +456,7 @@ static int add(int argc, const char **argv, const char *prefix)
402456
struct object_id object, new_note;
403457
const struct object_id *note;
404458
struct note_data d = { .buf = STRBUF_INIT };
459+
405460
struct option options[] = {
406461
OPT_CALLBACK_F('m', "message", &d, N_("message"),
407462
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -418,6 +473,8 @@ static int add(int argc, const char **argv, const char *prefix)
418473
OPT_BOOL(0, "allow-empty", &allow_empty,
419474
N_("allow storing empty note")),
420475
OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
476+
OPT_STRING(0, "separator", &separator, N_("separator"),
477+
N_("insert <paragraph-break> between paragraphs")),
421478
OPT_END()
422479
};
423480

@@ -429,6 +486,10 @@ static int add(int argc, const char **argv, const char *prefix)
429486
usage_with_options(git_notes_add_usage, options);
430487
}
431488

489+
if (d.msg_nr)
490+
concat_messages(&d);
491+
d.given = !!d.buf.len;
492+
432493
object_ref = argc > 1 ? argv[1] : "HEAD";
433494

434495
if (get_oid(object_ref, &object))
@@ -568,6 +629,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
568629
char *logmsg;
569630
const char * const *usage;
570631
struct note_data d = { .buf = STRBUF_INIT };
632+
571633
struct option options[] = {
572634
OPT_CALLBACK_F('m', "message", &d, N_("message"),
573635
N_("note contents as a string"), PARSE_OPT_NONEG,
@@ -583,6 +645,8 @@ static int append_edit(int argc, const char **argv, const char *prefix)
583645
parse_reuse_arg),
584646
OPT_BOOL(0, "allow-empty", &allow_empty,
585647
N_("allow storing empty note")),
648+
OPT_STRING(0, "separator", &separator, N_("separator"),
649+
N_("insert <paragraph-break> between paragraphs")),
586650
OPT_END()
587651
};
588652
int edit = !strcmp(argv[0], "edit");
@@ -596,6 +660,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
596660
usage_with_options(usage, options);
597661
}
598662

663+
if (d.msg_nr)
664+
concat_messages(&d);
665+
d.given = !!d.buf.len;
666+
599667
if (d.given && edit)
600668
fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
601669
"for the 'edit' subcommand.\n"
@@ -615,13 +683,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
615683
/* Append buf to previous note contents */
616684
unsigned long size;
617685
enum object_type type;
686+
struct strbuf buf = STRBUF_INIT;
618687
char *prev_buf = read_object_file(note, &type, &size);
619688

620-
if (d.buf.len && prev_buf && size)
621-
strbuf_insertstr(&d.buf, 0, "\n");
622689
if (prev_buf && size)
623-
strbuf_insert(&d.buf, 0, prev_buf, size);
690+
strbuf_add(&buf, prev_buf, size);
691+
if (d.buf.len && prev_buf && size)
692+
insert_separator(&buf, buf.len);
693+
strbuf_insert(&d.buf, 0, buf.buf, buf.len);
694+
624695
free(prev_buf);
696+
strbuf_release(&buf);
625697
}
626698

627699
if (d.buf.len || allow_empty) {

0 commit comments

Comments
 (0)