summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: b079fee)
raw | patch | inline | side by side (parent: b079fee)
author | Thomas Rast <trast@student.ethz.ch> | |
Fri, 12 Mar 2010 17:04:31 +0000 (18:04 +0100) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Sat, 13 Mar 2010 05:55:39 +0000 (21:55 -0800) |
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>
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>
Documentation/git-notes.txt | patch | blob | history | |
builtin-notes.c | patch | blob | history | |
notes.c | patch | blob | history | |
notes.h | patch | blob | history | |
t/t3301-notes.sh | patch | blob | history |
index 7abd0fbd2373b737fbdbdac3f4cc1616a6c7fbbf..6ab3f982b9e1d946c8fdd8bb63bf9b7d327dbe62 100644 (file)
[verse]
'git notes' [list [<object>]]
'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' copy [-f] <from-object> <to-object>
+'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
'git notes' edit [<object>]
'git notes' show [<object>]
objects has none. (use -f to overwrite existing notes to the
second object). This subcommand is equivalent to:
`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
++
+In `\--stdin` mode, take lines in the format
++
+----------
+<from-object> SP <to-object> [ SP <rest> ] LF
+----------
++
+on standard input, and copy the notes from each <from-object> to its
+corresponding <to-object>. (The optional `<rest>` is ignored so that
+the command can read the input given to the `post-rewrite` hook.)
append::
Append to the notes of an existing object (defaults to HEAD).
diff --git a/builtin-notes.c b/builtin-notes.c
index 123ecad830007bbf6df3e69442ce04abace7ad8e..daeb14e1d908cf22a3a6c21c5e4fb763f487ca4f 100644 (file)
--- a/builtin-notes.c
+++ b/builtin-notes.c
return 0;
}
+int notes_copy_from_stdin(int force)
+{
+ struct strbuf buf = STRBUF_INIT;
+ struct notes_tree *t;
+ int ret = 0;
+
+ init_notes(NULL, NULL, NULL, 0);
+ t = &default_notes_tree;
+
+ while (strbuf_getline(&buf, stdin, '\n') != EOF) {
+ unsigned char from_obj[20], to_obj[20];
+ struct strbuf **split;
+ int err;
+
+ split = strbuf_split(&buf, ' ');
+ if (!split[0] || !split[1])
+ die("Malformed input line: '%s'.", buf.buf);
+ strbuf_rtrim(split[0]);
+ strbuf_rtrim(split[1]);
+ if (get_sha1(split[0]->buf, from_obj))
+ die("Failed to resolve '%s' as a valid ref.", split[0]->buf);
+ if (get_sha1(split[1]->buf, to_obj))
+ die("Failed to resolve '%s' as a valid ref.", split[1]->buf);
+
+ err = copy_note(t, from_obj, to_obj, force, combine_notes_overwrite);
+
+ if (err) {
+ error("Failed to copy notes from '%s' to '%s'",
+ split[0]->buf, split[1]->buf);
+ ret = 1;
+ }
+
+ strbuf_list_free(split);
+ }
+
+ commit_notes(t, "Notes added by 'git notes copy'");
+ free_notes(t);
+ return ret;
+}
+
int cmd_notes(int argc, const char **argv, const char *prefix)
{
struct notes_tree *t;
char logmsg[100];
int list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,
- remove = 0, prune = 0, force = 0;
+ remove = 0, prune = 0, force = 0, from_stdin = 0;
int given_object = 0, i = 1, retval = 0;
struct msg_arg msg = { 0, 0, STRBUF_INIT };
struct option options[] = {
OPT_CALLBACK('C', "reuse-message", &msg, "OBJECT",
"reuse specified note object", parse_reuse_arg),
OPT_BOOLEAN('f', "force", &force, "replace existing notes"),
+ OPT_BOOLEAN(0, "stdin", &from_stdin, "read objects from stdin"),
OPT_END()
};
usage_with_options(git_notes_usage, options);
}
+ if (!copy && from_stdin) {
+ error("cannot use --stdin with %s subcommand.", argv[0]);
+ usage_with_options(git_notes_usage, options);
+ }
+
if (copy) {
const char *from_ref;
+ if (from_stdin) {
+ if (argc > 1) {
+ error("too many parameters");
+ usage_with_options(git_notes_usage, options);
+ } else {
+ return notes_copy_from_stdin(force);
+ }
+ }
if (argc < 3) {
error("too few parameters");
usage_with_options(git_notes_usage, options);
index 225a16608a516f6a4f9563727874174dbe03287b..2feeb7bb06ce5073d6813e447f13f1205e2d87c4 100644 (file)
--- a/notes.c
+++ b/notes.c
format_note(display_notes_trees[i], object_sha1, sb,
output_encoding, flags);
}
+
+int copy_note(struct notes_tree *t,
+ const unsigned char *from_obj, const unsigned char *to_obj,
+ int force, combine_notes_fn combine_fn)
+{
+ const unsigned char *note = get_note(t, from_obj);
+ const unsigned char *existing_note = get_note(t, to_obj);
+
+ if (!force && existing_note)
+ return 1;
+
+ if (note)
+ add_note(t, to_obj, note, combine_fn);
+ else if (existing_note)
+ add_note(t, to_obj, null_sha1, combine_fn);
+
+ return 0;
+}
index 2cc07409dbcfe36c71d25ae26dc20eff9bf89b6f..b7fafb448b6b8e50878548e1b5f6fa2bfe18e6a2 100644 (file)
--- a/notes.h
+++ b/notes.h
const unsigned char *get_note(struct notes_tree *t,
const unsigned char *object_sha1);
+/*
+ * Copy a note from one object to another in the given notes_tree.
+ *
+ * Fails if the to_obj already has a note unless 'force' is true.
+ */
+int copy_note(struct notes_tree *t,
+ const unsigned char *from_obj, const unsigned char *to_obj,
+ int force, combine_notes_fn combine_fn);
+
/*
* Flags controlling behaviour of for_each_note()
*
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index cb7166f6ecc77056d6a5a1626cb97c22b99db5f9..60ad6a1675cac0ba64bb8bf88ea40386f89ae3ff 100755 (executable)
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
test_must_fail git notes copy HEAD^ HEAD
'
+cat > expect << EOF
+commit e5d4fb5698d564ab8c73551538ecaf2b0c666185
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:25:13 2005 -0700
+
+ 13th
+
+Notes (other):
+ yet another note
+$whitespace
+ yet another note
+
+commit 7038787dfe22a14c3867ce816dbba39845359719
+Author: A U Thor <author@example.com>
+Date: Thu Apr 7 15:24:13 2005 -0700
+
+ 12th
+
+Notes (other):
+ other note
+$whitespace
+ yet another note
+EOF
+
+test_expect_success 'git notes copy --stdin' '
+ (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
+ echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
+ git notes copy --stdin &&
+ git log -2 > output &&
+ test_cmp expect output &&
+ test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" &&
+ test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)"
+'
+
test_done