99
1010#include "builtin.h"
1111#include "config.h"
12+ #include "alloc.h"
1213#include "editor.h"
1314#include "environment.h"
1415#include "gettext.h"
3031#include "worktree.h"
3132#include "write-or-die.h"
3233
34+ static const char * separator = "\n" ;
3335static const char * const git_notes_usage [] = {
3436 N_ ("git notes [--ref <notes-ref>] [list [<object>]]" ),
35- N_ ("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]" ),
37+ N_ ("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [- m <msg> | -F <file> | (-c | -C) <object>] [<object>]" ),
3638 N_ ("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>" ),
37- N_ ("git notes [--ref <notes-ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]" ),
39+ N_ ("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [- m <msg> | -F <file> | (-c | -C) <object>] [<object>]" ),
3840 N_ ("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]" ),
3941 N_ ("git notes [--ref <notes-ref>] show [<object>]" ),
4042 N_ ("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>" ),
@@ -102,11 +104,26 @@ static const char * const git_notes_get_ref_usage[] = {
102104static const char note_template [] =
103105 N_ ("Write/edit the notes for the following object:" );
104106
107+ enum notes_stripspace {
108+ UNSPECIFIED = -1 ,
109+ NO_STRIPSPACE = 0 ,
110+ STRIPSPACE = 1 ,
111+ };
112+
113+ struct note_msg {
114+ enum notes_stripspace stripspace ;
115+ struct strbuf buf ;
116+ };
117+
105118struct note_data {
106119 int given ;
107120 int use_editor ;
121+ int stripspace ;
108122 char * edit_path ;
109123 struct strbuf buf ;
124+ struct note_msg * * messages ;
125+ size_t msg_nr ;
126+ size_t msg_alloc ;
110127};
111128
112129static void free_note_data (struct note_data * d )
@@ -116,6 +133,12 @@ static void free_note_data(struct note_data *d)
116133 free (d -> edit_path );
117134 }
118135 strbuf_release (& d -> buf );
136+
137+ while (d -> msg_nr -- ) {
138+ strbuf_release (& d -> messages [d -> msg_nr ]-> buf );
139+ free (d -> messages [d -> msg_nr ]);
140+ }
141+ free (d -> messages );
119142}
120143
121144static int list_each_note (const struct object_id * object_oid ,
@@ -201,7 +224,8 @@ static void prepare_note_data(const struct object_id *object, struct note_data *
201224 if (launch_editor (d -> edit_path , & d -> buf , NULL )) {
202225 die (_ ("please supply the note contents using either -m or -F option" ));
203226 }
204- strbuf_stripspace (& d -> buf , comment_line_char );
227+ if (d -> stripspace )
228+ strbuf_stripspace (& d -> buf , comment_line_char );
205229 }
206230}
207231
@@ -217,66 +241,102 @@ static void write_note_data(struct note_data *d, struct object_id *oid)
217241 }
218242}
219243
244+ static void append_separator (struct strbuf * message )
245+ {
246+ size_t sep_len = 0 ;
247+
248+ if (!separator )
249+ return ;
250+ else if ((sep_len = strlen (separator )) && separator [sep_len - 1 ] == '\n' )
251+ strbuf_addstr (message , separator );
252+ else
253+ strbuf_addf (message , "%s%s" , separator , "\n" );
254+ }
255+
256+ static void concat_messages (struct note_data * d )
257+ {
258+ struct strbuf msg = STRBUF_INIT ;
259+ size_t i ;
260+
261+ for (i = 0 ; i < d -> msg_nr ; i ++ ) {
262+ if (d -> buf .len )
263+ append_separator (& d -> buf );
264+ strbuf_add (& msg , d -> messages [i ]-> buf .buf , d -> messages [i ]-> buf .len );
265+ strbuf_addbuf (& d -> buf , & msg );
266+ if ((d -> stripspace == UNSPECIFIED &&
267+ d -> messages [i ]-> stripspace == STRIPSPACE ) ||
268+ d -> stripspace == STRIPSPACE )
269+ strbuf_stripspace (& d -> buf , 0 );
270+ strbuf_reset (& msg );
271+ }
272+ strbuf_release (& msg );
273+ }
274+
220275static int parse_msg_arg (const struct option * opt , const char * arg , int unset )
221276{
222277 struct note_data * d = opt -> value ;
278+ struct note_msg * msg = xmalloc (sizeof (* msg ));
223279
224280 BUG_ON_OPT_NEG (unset );
225281
226- strbuf_grow (& d -> buf , strlen (arg ) + 2 );
227- if (d -> buf .len )
228- strbuf_addch (& d -> buf , '\n' );
229- strbuf_addstr (& d -> buf , arg );
230- strbuf_stripspace (& d -> buf , '\0' );
231-
232- d -> given = 1 ;
282+ strbuf_init (& msg -> buf , strlen (arg ));
283+ strbuf_addstr (& msg -> buf , arg );
284+ ALLOC_GROW_BY (d -> messages , d -> msg_nr , 1 , d -> msg_alloc );
285+ d -> messages [d -> msg_nr - 1 ] = msg ;
286+ msg -> stripspace = STRIPSPACE ;
233287 return 0 ;
234288}
235289
236290static int parse_file_arg (const struct option * opt , const char * arg , int unset )
237291{
238292 struct note_data * d = opt -> value ;
293+ struct note_msg * msg = xmalloc (sizeof (* msg ));
239294
240295 BUG_ON_OPT_NEG (unset );
241296
242- if (d -> buf .len )
243- strbuf_addch (& d -> buf , '\n' );
297+ strbuf_init (& msg -> buf , 0 );
244298 if (!strcmp (arg , "-" )) {
245- if (strbuf_read (& d -> buf , 0 , 1024 ) < 0 )
299+ if (strbuf_read (& msg -> buf , 0 , 1024 ) < 0 )
246300 die_errno (_ ("cannot read '%s'" ), arg );
247- } else if (strbuf_read_file (& d -> buf , arg , 1024 ) < 0 )
301+ } else if (strbuf_read_file (& msg -> buf , arg , 1024 ) < 0 )
248302 die_errno (_ ("could not open or read '%s'" ), arg );
249- strbuf_stripspace (& d -> buf , '\0' );
250303
251- d -> given = 1 ;
304+ ALLOC_GROW_BY (d -> messages , d -> msg_nr , 1 , d -> msg_alloc );
305+ d -> messages [d -> msg_nr - 1 ] = msg ;
306+ msg -> stripspace = STRIPSPACE ;
252307 return 0 ;
253308}
254309
255310static int parse_reuse_arg (const struct option * opt , const char * arg , int unset )
256311{
257312 struct note_data * d = opt -> value ;
258- char * buf ;
313+ struct note_msg * msg = xmalloc (sizeof (* msg ));
314+ char * value ;
259315 struct object_id object ;
260316 enum object_type type ;
261317 unsigned long len ;
262318
263319 BUG_ON_OPT_NEG (unset );
264320
265- if (d -> buf .len )
266- strbuf_addch (& d -> buf , '\n' );
267-
321+ strbuf_init (& msg -> buf , 0 );
268322 if (repo_get_oid (the_repository , arg , & object ))
269323 die (_ ("failed to resolve '%s' as a valid ref." ), arg );
270- if (!(buf = repo_read_object_file (the_repository , & object , & type , & len )))
324+ if (!(value = repo_read_object_file (the_repository , & object , & type , & len )))
271325 die (_ ("failed to read object '%s'." ), arg );
272326 if (type != OBJ_BLOB ) {
273- free (buf );
327+ strbuf_release (& msg -> buf );
328+ free (value );
329+ free (msg );
274330 die (_ ("cannot read note data from non-blob object '%s'." ), arg );
275331 }
276- strbuf_add (& d -> buf , buf , len );
277- free (buf );
278332
279- d -> given = 1 ;
333+ strbuf_add (& msg -> buf , value , len );
334+ free (value );
335+
336+ msg -> buf .len = len ;
337+ ALLOC_GROW_BY (d -> messages , d -> msg_nr , 1 , d -> msg_alloc );
338+ d -> messages [d -> msg_nr - 1 ] = msg ;
339+ msg -> stripspace = NO_STRIPSPACE ;
280340 return 0 ;
281341}
282342
@@ -288,6 +348,16 @@ static int parse_reedit_arg(const struct option *opt, const char *arg, int unset
288348 return parse_reuse_arg (opt , arg , unset );
289349}
290350
351+ static int parse_separator_arg (const struct option * opt , const char * arg ,
352+ int unset )
353+ {
354+ if (unset )
355+ * (const char * * )opt -> value = NULL ;
356+ else
357+ * (const char * * )opt -> value = arg ? arg : "\n" ;
358+ return 0 ;
359+ }
360+
291361static int notes_copy_from_stdin (int force , const char * rewrite_cmd )
292362{
293363 struct strbuf buf = STRBUF_INIT ;
@@ -410,7 +480,8 @@ static int add(int argc, const char **argv, const char *prefix)
410480 struct notes_tree * t ;
411481 struct object_id object , new_note ;
412482 const struct object_id * note ;
413- struct note_data d = { 0 , 0 , NULL , STRBUF_INIT };
483+ struct note_data d = { .buf = STRBUF_INIT , .stripspace = UNSPECIFIED };
484+
414485 struct option options [] = {
415486 OPT_CALLBACK_F ('m' , "message" , & d , N_ ("message" ),
416487 N_ ("note contents as a string" ), PARSE_OPT_NONEG ,
@@ -427,6 +498,12 @@ static int add(int argc, const char **argv, const char *prefix)
427498 OPT_BOOL (0 , "allow-empty" , & allow_empty ,
428499 N_ ("allow storing empty note" )),
429500 OPT__FORCE (& force , N_ ("replace existing notes" ), PARSE_OPT_NOCOMPLETE ),
501+ OPT_CALLBACK_F (0 , "separator" , & separator ,
502+ N_ ("<paragraph-break>" ),
503+ N_ ("insert <paragraph-break> between paragraphs" ),
504+ PARSE_OPT_OPTARG , parse_separator_arg ),
505+ OPT_BOOL (0 , "stripspace" , & d .stripspace ,
506+ N_ ("remove unnecessary whitespace" )),
430507 OPT_END ()
431508 };
432509
@@ -438,6 +515,10 @@ static int add(int argc, const char **argv, const char *prefix)
438515 usage_with_options (git_notes_add_usage , options );
439516 }
440517
518+ if (d .msg_nr )
519+ concat_messages (& d );
520+ d .given = !!d .buf .len ;
521+
441522 object_ref = argc > 1 ? argv [1 ] : "HEAD" ;
442523
443524 if (repo_get_oid (the_repository , object_ref , & object ))
@@ -576,7 +657,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
576657 const struct object_id * note ;
577658 char * logmsg ;
578659 const char * const * usage ;
579- struct note_data d = { 0 , 0 , NULL , STRBUF_INIT };
660+ struct note_data d = { . buf = STRBUF_INIT , . stripspace = UNSPECIFIED };
580661 struct option options [] = {
581662 OPT_CALLBACK_F ('m' , "message" , & d , N_ ("message" ),
582663 N_ ("note contents as a string" ), PARSE_OPT_NONEG ,
@@ -592,6 +673,12 @@ static int append_edit(int argc, const char **argv, const char *prefix)
592673 parse_reuse_arg ),
593674 OPT_BOOL (0 , "allow-empty" , & allow_empty ,
594675 N_ ("allow storing empty note" )),
676+ OPT_CALLBACK_F (0 , "separator" , & separator ,
677+ N_ ("<paragraph-break>" ),
678+ N_ ("insert <paragraph-break> between paragraphs" ),
679+ PARSE_OPT_OPTARG , parse_separator_arg ),
680+ OPT_BOOL (0 , "stripspace" , & d .stripspace ,
681+ N_ ("remove unnecessary whitespace" )),
595682 OPT_END ()
596683 };
597684 int edit = !strcmp (argv [0 ], "edit" );
@@ -605,6 +692,10 @@ static int append_edit(int argc, const char **argv, const char *prefix)
605692 usage_with_options (usage , options );
606693 }
607694
695+ if (d .msg_nr )
696+ concat_messages (& d );
697+ d .given = !!d .buf .len ;
698+
608699 if (d .given && edit )
609700 fprintf (stderr , _ ("The -m/-F/-c/-C options have been deprecated "
610701 "for the 'edit' subcommand.\n"
@@ -624,15 +715,17 @@ static int append_edit(int argc, const char **argv, const char *prefix)
624715 /* Append buf to previous note contents */
625716 unsigned long size ;
626717 enum object_type type ;
627- char * prev_buf = repo_read_object_file ( the_repository , note ,
628- & type , & size );
718+ struct strbuf buf = STRBUF_INIT ;
719+ char * prev_buf = repo_read_object_file ( the_repository , note , & type , & size );
629720
630- strbuf_grow (& d .buf , size + 1 );
631- if (d .buf .len && prev_buf && size )
632- strbuf_insertstr (& d .buf , 0 , "\n" );
633721 if (prev_buf && size )
634- strbuf_insert (& d .buf , 0 , prev_buf , size );
722+ strbuf_add (& buf , prev_buf , size );
723+ if (d .buf .len && prev_buf && size )
724+ append_separator (& buf );
725+ strbuf_insert (& d .buf , 0 , buf .buf , buf .len );
726+
635727 free (prev_buf );
728+ strbuf_release (& buf );
636729 }
637730
638731 if (d .buf .len || allow_empty ) {
0 commit comments