Skip to content

Commit 160baa0

Browse files
trastgitster
authored andcommitted
notes: implement 'git notes copy --stdin'
This implements a mass-copy command that takes a sequence of lines in the format <from-sha1> SP <to-sha1> [ SP <rest> ] LF on stdin, and copies each <from-sha1>'s notes to the <to-sha1>. The <rest> is ignored. The intent, of course, is that this can read the same input that the 'post-rewrite' hook gets. The copy_note() function is exposed for everyone's and in particular the next commit's use. Signed-off-by: Thomas Rast <[email protected]> Acked-by: Johan Herland <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b079fee commit 160baa0

File tree

5 files changed

+127
-2
lines changed

5 files changed

+127
-2
lines changed

Documentation/git-notes.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
[verse]
1111
'git notes' [list [<object>]]
1212
'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
13-
'git notes' copy [-f] <from-object> <to-object>
13+
'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
1414
'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
1515
'git notes' edit [<object>]
1616
'git notes' show [<object>]
@@ -56,6 +56,16 @@ copy::
5656
objects has none. (use -f to overwrite existing notes to the
5757
second object). This subcommand is equivalent to:
5858
`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
59+
+
60+
In `\--stdin` mode, take lines in the format
61+
+
62+
----------
63+
<from-object> SP <to-object> [ SP <rest> ] LF
64+
----------
65+
+
66+
on standard input, and copy the notes from each <from-object> to its
67+
corresponding <to-object>. (The optional `<rest>` is ignored so that
68+
the command can read the input given to the `post-rewrite` hook.)
5969

6070
append::
6171
Append to the notes of an existing object (defaults to HEAD).

builtin-notes.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,46 @@ int commit_notes(struct notes_tree *t, const char *msg)
278278
return 0;
279279
}
280280

281+
int notes_copy_from_stdin(int force)
282+
{
283+
struct strbuf buf = STRBUF_INIT;
284+
struct notes_tree *t;
285+
int ret = 0;
286+
287+
init_notes(NULL, NULL, NULL, 0);
288+
t = &default_notes_tree;
289+
290+
while (strbuf_getline(&buf, stdin, '\n') != EOF) {
291+
unsigned char from_obj[20], to_obj[20];
292+
struct strbuf **split;
293+
int err;
294+
295+
split = strbuf_split(&buf, ' ');
296+
if (!split[0] || !split[1])
297+
die("Malformed input line: '%s'.", buf.buf);
298+
strbuf_rtrim(split[0]);
299+
strbuf_rtrim(split[1]);
300+
if (get_sha1(split[0]->buf, from_obj))
301+
die("Failed to resolve '%s' as a valid ref.", split[0]->buf);
302+
if (get_sha1(split[1]->buf, to_obj))
303+
die("Failed to resolve '%s' as a valid ref.", split[1]->buf);
304+
305+
err = copy_note(t, from_obj, to_obj, force, combine_notes_overwrite);
306+
307+
if (err) {
308+
error("Failed to copy notes from '%s' to '%s'",
309+
split[0]->buf, split[1]->buf);
310+
ret = 1;
311+
}
312+
313+
strbuf_list_free(split);
314+
}
315+
316+
commit_notes(t, "Notes added by 'git notes copy'");
317+
free_notes(t);
318+
return ret;
319+
}
320+
281321
int cmd_notes(int argc, const char **argv, const char *prefix)
282322
{
283323
struct notes_tree *t;
@@ -287,7 +327,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
287327
char logmsg[100];
288328

289329
int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
290-
remove = 0, prune = 0, force = 0;
330+
remove = 0, prune = 0, force = 0, from_stdin = 0;
291331
int given_object = 0, i = 1, retval = 0;
292332
struct msg_arg msg = { 0, 0, STRBUF_INIT };
293333
struct option options[] = {
@@ -301,6 +341,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
301341
OPT_CALLBACK('C', "reuse-message", &msg, "OBJECT",
302342
"reuse specified note object", parse_reuse_arg),
303343
OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
344+
OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
304345
OPT_END()
305346
};
306347

@@ -349,8 +390,21 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
349390
usage_with_options(git_notes_usage, options);
350391
}
351392

393+
if (!copy && from_stdin) {
394+
error("cannot use --stdin with %s subcommand.", argv[0]);
395+
usage_with_options(git_notes_usage, options);
396+
}
397+
352398
if (copy) {
353399
const char *from_ref;
400+
if (from_stdin) {
401+
if (argc > 1) {
402+
error("too many parameters");
403+
usage_with_options(git_notes_usage, options);
404+
} else {
405+
return notes_copy_from_stdin(force);
406+
}
407+
}
354408
if (argc < 3) {
355409
error("too few parameters");
356410
usage_with_options(git_notes_usage, options);

notes.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1185,3 +1185,21 @@ void format_display_notes(const unsigned char *object_sha1,
11851185
format_note(display_notes_trees[i], object_sha1, sb,
11861186
output_encoding, flags);
11871187
}
1188+
1189+
int copy_note(struct notes_tree *t,
1190+
const unsigned char *from_obj, const unsigned char *to_obj,
1191+
int force, combine_notes_fn combine_fn)
1192+
{
1193+
const unsigned char *note = get_note(t, from_obj);
1194+
const unsigned char *existing_note = get_note(t, to_obj);
1195+
1196+
if (!force && existing_note)
1197+
return 1;
1198+
1199+
if (note)
1200+
add_note(t, to_obj, note, combine_fn);
1201+
else if (existing_note)
1202+
add_note(t, to_obj, null_sha1, combine_fn);
1203+
1204+
return 0;
1205+
}

notes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,15 @@ void remove_note(struct notes_tree *t, const unsigned char *object_sha1);
9999
const unsigned char *get_note(struct notes_tree *t,
100100
const unsigned char *object_sha1);
101101

102+
/*
103+
* Copy a note from one object to another in the given notes_tree.
104+
*
105+
* Fails if the to_obj already has a note unless 'force' is true.
106+
*/
107+
int copy_note(struct notes_tree *t,
108+
const unsigned char *from_obj, const unsigned char *to_obj,
109+
int force, combine_notes_fn combine_fn);
110+
102111
/*
103112
* Flags controlling behaviour of for_each_note()
104113
*

t/t3301-notes.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,4 +776,38 @@ test_expect_success 'cannot copy note from object without notes' '
776776
test_must_fail git notes copy HEAD^ HEAD
777777
'
778778

779+
cat > expect << EOF
780+
commit e5d4fb5698d564ab8c73551538ecaf2b0c666185
781+
Author: A U Thor <[email protected]>
782+
Date: Thu Apr 7 15:25:13 2005 -0700
783+
784+
13th
785+
786+
Notes (other):
787+
yet another note
788+
$whitespace
789+
yet another note
790+
791+
commit 7038787dfe22a14c3867ce816dbba39845359719
792+
Author: A U Thor <[email protected]>
793+
Date: Thu Apr 7 15:24:13 2005 -0700
794+
795+
12th
796+
797+
Notes (other):
798+
other note
799+
$whitespace
800+
yet another note
801+
EOF
802+
803+
test_expect_success 'git notes copy --stdin' '
804+
(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
805+
echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
806+
git notes copy --stdin &&
807+
git log -2 > output &&
808+
test_cmp expect output &&
809+
test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" &&
810+
test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)"
811+
'
812+
779813
test_done

0 commit comments

Comments
 (0)