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>
This commit is contained in:
parent
b079feed64
commit
160baa0d9c
@ -10,7 +10,7 @@ SYNOPSIS
|
||||
[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>]
|
||||
@ -56,6 +56,16 @@ copy::
|
||||
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).
|
||||
|
@ -278,6 +278,46 @@ int commit_notes(struct notes_tree *t, const char *msg)
|
||||
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;
|
||||
@ -287,7 +327,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
|
||||
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[] = {
|
||||
@ -301,6 +341,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
|
||||
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()
|
||||
};
|
||||
|
||||
@ -349,8 +390,21 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
|
||||
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);
|
||||
|
18
notes.c
18
notes.c
@ -1185,3 +1185,21 @@ void format_display_notes(const unsigned char *object_sha1,
|
||||
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;
|
||||
}
|
||||
|
9
notes.h
9
notes.h
@ -99,6 +99,15 @@ void remove_note(struct notes_tree *t, const unsigned char *object_sha1);
|
||||
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()
|
||||
*
|
||||
|
@ -776,4 +776,38 @@ test_expect_success 'cannot copy note from object without notes' '
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user