@matheusbsbs / matheus-bagliano / commits / 160baa0d9c
Fork 0

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 <trast@student.ethz.ch> Acked-by: Johan Herland <johan@herland.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Thomas Rast committed Mar 12, 2010 at 18:04 UTC 160baa0d9cbdfcdb6251aa5ede77c59c0d53edfd
5 files changed +127 -2
Documentation/git-notes.txt
+11 -1
@@ -10,7 +10,7 @@ SYNOPSIS
10 [verse]
11 'git notes' [list [<object>]]
12 '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> )
14 'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
15 'git notes' edit [<object>]
16 'git notes' show [<object>]
@@ -56,6 +56,16 @@ copy::
56 objects has none. (use -f to overwrite existing notes to the
57 second object). This subcommand is equivalent to:
58 `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.)
69
70 append::
71 Append to the notes of an existing object (defaults to HEAD).
builtin-notes.c
+55 -1
@@ -278,6 +278,46 @@ int commit_notes(struct notes_tree *t, const char *msg)
278 return 0;
279 }
280
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 +
321 int cmd_notes(int argc, const char **argv, const char *prefix)
322 {
323 struct notes_tree *t;
@@ -287,7 +327,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
327 char logmsg[100];
328
329 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;
331 int given_object = 0, i = 1, retval = 0;
332 struct msg_arg msg = { 0, 0, STRBUF_INIT };
333 struct option options[] = {
@@ -301,6 +341,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
341 OPT_CALLBACK('C', "reuse-message", &msg, "OBJECT",
342 "reuse specified note object", parse_reuse_arg),
343 OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
344 + OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
345 OPT_END()
346 };
347
@@ -349,8 +390,21 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
390 usage_with_options(git_notes_usage, options);
391 }
392
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 +
398 if (copy) {
399 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 + }
408 if (argc < 3) {
409 error("too few parameters");
410 usage_with_options(git_notes_usage, options);
notes.c
+18
@@ -1185,3 +1185,21 @@ void format_display_notes(const unsigned char *object_sha1,
1185 format_note(display_notes_trees[i], object_sha1, sb,
1186 output_encoding, flags);
1187 }
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
+9
@@ -99,6 +99,15 @@ void remove_note(struct notes_tree *t, const unsigned char *object_sha1);
99 const unsigned char *get_note(struct notes_tree *t,
100 const unsigned char *object_sha1);
101
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 +
111 /*
112 * Flags controlling behaviour of for_each_note()
113 *
t/t3301-notes.sh
+34
@@ -776,4 +776,38 @@ test_expect_success 'cannot copy note from object without notes' '
776 test_must_fail git notes copy HEAD^ HEAD
777 '
778
779 +cat > expect << EOF
780 +commit e5d4fb5698d564ab8c73551538ecaf2b0c666185
781 +Author: A U Thor <author@example.com>
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 <author@example.com>
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 +
813 test_done