From 894a9d333e9e2015cad00d95250b7c5d3acea8b6 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Fri, 12 Mar 2010 18:04:26 +0100 Subject: Support showing notes from more than one notes tree With this patch, you can set notes.displayRef to a glob that points at your favourite notes refs, e.g., [notes] displayRef = refs/notes/* Then git-log and friends will show notes from all trees. Thanks to Junio C Hamano for lots of feedback, which greatly influenced the design of the entire series and this commit in particular. Signed-off-by: Thomas Rast Acked-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-notes.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'Documentation/git-notes.txt') diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index 14f73b988e..7abd0fbd23 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -27,12 +27,13 @@ A typical use of notes is to extend a commit message without having to change the commit itself. Such commit notes can be shown by `git log` along with the original commit message. To discern these notes from the message stored in the commit object, the notes are indented like the -message, after an unindented line saying "Notes:". +message, after an unindented line saying "Notes ():" (or +"Notes:" for the default setting). -To disable notes, you have to set the config variable core.notesRef to -the empty string. Alternatively, you can set it to a different ref, -something like "refs/notes/bugzilla". This setting can be overridden -by the environment variable "GIT_NOTES_REF". +This command always manipulates the notes specified in "core.notesRef" +(see linkgit:git-config[1]), which can be overridden by GIT_NOTES_REF. +To change which notes are shown by 'git-log', see the +"notes.displayRef" configuration. SUBCOMMANDS -- cgit v1.3 From 160baa0d9cbdfcdb6251aa5ede77c59c0d53edfd Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Fri, 12 Mar 2010 18:04:31 +0100 Subject: notes: implement 'git notes copy --stdin' This implements a mass-copy command that takes a sequence of lines in the format SP [ SP ] LF on stdin, and copies each 's notes to the . The 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 Acked-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-notes.txt | 12 +++++++++- builtin-notes.c | 56 ++++++++++++++++++++++++++++++++++++++++++++- notes.c | 18 +++++++++++++++ notes.h | 9 ++++++++ t/t3301-notes.sh | 34 +++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) (limited to 'Documentation/git-notes.txt') diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index 7abd0fbd23..6ab3f982b9 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git notes' [list []] 'git notes' add [-f] [-F | -m | (-c | -C) ] [] -'git notes' copy [-f] +'git notes' copy [-f] ( --stdin | ) 'git notes' append [-F | -m | (-c | -C) ] [] 'git notes' edit [] 'git notes' show [] @@ -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 ) ` ++ +In `\--stdin` mode, take lines in the format ++ +---------- + SP [ SP ] LF +---------- ++ +on standard input, and copy the notes from each to its +corresponding . (The optional `` 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 123ecad830..daeb14e1d9 100644 --- a/builtin-notes.c +++ b/builtin-notes.c @@ -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); diff --git a/notes.c b/notes.c index 225a16608a..2feeb7bb06 100644 --- a/notes.c +++ b/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; +} diff --git a/notes.h b/notes.h index 2cc07409db..b7fafb448b 100644 --- a/notes.h +++ b/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() * diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index cb7166f6ec..60ad6a1675 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -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 +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 +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 -- cgit v1.3 From 6956f858f6237d426fa422949033e3c558104802 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Fri, 12 Mar 2010 18:04:32 +0100 Subject: notes: implement helpers needed for note copying during rewrite Implement helper functions to load the rewriting config, and to actually copy the notes. Also document the config. Secondly, also implement an undocumented --for-rewrite= option to 'git notes copy' which is used like --stdin, but also puts the configuration for into effect. It will be needed to support the copying in git-rebase. Signed-off-by: Thomas Rast Acked-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/config.txt | 30 +++++++ Documentation/git-notes.txt | 4 + Documentation/githooks.txt | 4 + builtin-notes.c | 139 +++++++++++++++++++++++++++++-- builtin.h | 17 ++++ cache.h | 2 + t/t3301-notes.sh | 195 ++++++++++++++++++++++++++++++++++++++++++++ t/test-lib.sh | 2 + 8 files changed, 385 insertions(+), 8 deletions(-) (limited to 'Documentation/git-notes.txt') diff --git a/Documentation/config.txt b/Documentation/config.txt index 503942a2e4..2e02f1b075 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1305,6 +1305,36 @@ The effective value of "core.notesRef" (possibly overridden by GIT_NOTES_REF) is also implicitly added to the list of refs to be displayed. +notes.rewrite.:: + When rewriting commits with (currently `amend` or + `rebase`) and this variable is set to `true`, git + automatically copies your notes from the original to the + rewritten commit. Defaults to `true`, but see + "notes.rewriteRef" below. ++ +This setting can be overridden with the `GIT_NOTES_REWRITE_REF` +environment variable, which must be a colon separated list of refs or +globs. + +notes.rewriteMode:: + When copying notes during a rewrite (see the + "notes.rewrite." option), determines what to do if + the target commit already has a note. Must be one of + `overwrite`, `concatenate`, or `ignore`. Defaults to + `concatenate`. ++ +This setting can be overridden with the `GIT_NOTES_REWRITE_MODE` +environment variable. + +notes.rewriteRef:: + When copying notes during a rewrite, specifies the (fully + qualified) ref whose notes should be copied. The ref may be a + glob, in which case notes in all matching refs will be copied. + You may also specify this configuration several times. ++ +Does not have a default value; you must configure this variable to +enable note rewriting. + pack.window:: The size of the window used by linkgit:git-pack-objects[1] when no window size is given on the command line. Defaults to 10. diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index 6ab3f982b9..b12d1cf539 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -35,6 +35,10 @@ This command always manipulates the notes specified in "core.notesRef" To change which notes are shown by 'git-log', see the "notes.displayRef" configuration. +See the description of "notes.rewrite." in +linkgit:git-config[1] for a way of carrying your notes across commands +that rewrite commits. + SUBCOMMANDS ----------- diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index a741769742..7183aa9abb 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -335,6 +335,10 @@ The 'extra-info' is again command-dependent. If it is empty, the preceding SP is also omitted. Currently, no commands pass any 'extra-info'. +The hook always runs after the automatic note copying (see +"notes.rewrite." in linkgit:git-config.txt) has happened, and +thus has access to these notes. + The following command-specific comments apply: rebase:: diff --git a/builtin-notes.c b/builtin-notes.c index daeb14e1d9..026cfd32a8 100644 --- a/builtin-notes.c +++ b/builtin-notes.c @@ -16,6 +16,7 @@ #include "exec_cmd.h" #include "run-command.h" #include "parse-options.h" +#include "string-list.h" static const char * const git_notes_usage[] = { "git notes [list []]", @@ -278,14 +279,121 @@ int commit_notes(struct notes_tree *t, const char *msg) return 0; } -int notes_copy_from_stdin(int force) + +combine_notes_fn *parse_combine_notes_fn(const char *v) +{ + if (!strcasecmp(v, "overwrite")) + return combine_notes_overwrite; + else if (!strcasecmp(v, "ignore")) + return combine_notes_ignore; + else if (!strcasecmp(v, "concatenate")) + return combine_notes_concatenate; + else + return NULL; +} + +static int notes_rewrite_config(const char *k, const char *v, void *cb) +{ + struct notes_rewrite_cfg *c = cb; + if (!prefixcmp(k, "notes.rewrite.") && !strcmp(k+14, c->cmd)) { + c->enabled = git_config_bool(k, v); + return 0; + } else if (!c->mode_from_env && !strcmp(k, "notes.rewritemode")) { + if (!v) + config_error_nonbool(k); + c->combine = parse_combine_notes_fn(v); + if (!c->combine) { + error("Bad notes.rewriteMode value: '%s'", v); + return 1; + } + return 0; + } else if (!c->refs_from_env && !strcmp(k, "notes.rewriteref")) { + /* note that a refs/ prefix is implied in the + * underlying for_each_glob_ref */ + if (!prefixcmp(v, "refs/notes/")) + string_list_add_refs_by_glob(c->refs, v); + else + warning("Refusing to rewrite notes in %s" + " (outside of refs/notes/)", v); + return 0; + } + + return 0; +} + + +struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd) +{ + struct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg)); + const char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT); + const char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT); + c->cmd = cmd; + c->enabled = 1; + c->combine = combine_notes_concatenate; + c->refs = xcalloc(1, sizeof(struct string_list)); + c->refs->strdup_strings = 1; + c->refs_from_env = 0; + c->mode_from_env = 0; + if (rewrite_mode_env) { + c->mode_from_env = 1; + c->combine = parse_combine_notes_fn(rewrite_mode_env); + if (!c->combine) + error("Bad " GIT_NOTES_REWRITE_MODE_ENVIRONMENT + " value: '%s'", rewrite_mode_env); + } + if (rewrite_refs_env) { + c->refs_from_env = 1; + string_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env); + } + git_config(notes_rewrite_config, c); + if (!c->enabled || !c->refs->nr) { + string_list_clear(c->refs, 0); + free(c->refs); + free(c); + return NULL; + } + c->trees = load_notes_trees(c->refs); + string_list_clear(c->refs, 0); + free(c->refs); + return c; +} + +int copy_note_for_rewrite(struct notes_rewrite_cfg *c, + const unsigned char *from_obj, const unsigned char *to_obj) +{ + int ret = 0; + int i; + for (i = 0; c->trees[i]; i++) + ret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret; + return ret; +} + +void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c) +{ + int i; + for (i = 0; c->trees[i]; i++) { + commit_notes(c->trees[i], "Notes added by 'git notes copy'"); + free_notes(c->trees[i]); + } + free(c->trees); + free(c); +} + +int notes_copy_from_stdin(int force, const char *rewrite_cmd) { struct strbuf buf = STRBUF_INIT; + struct notes_rewrite_cfg *c = NULL; struct notes_tree *t; int ret = 0; - init_notes(NULL, NULL, NULL, 0); - t = &default_notes_tree; + if (rewrite_cmd) { + c = init_copy_notes_for_rewrite(rewrite_cmd); + if (!c) + return 0; + } else { + 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]; @@ -302,7 +410,11 @@ int notes_copy_from_stdin(int force) 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 (rewrite_cmd) + err = copy_note_for_rewrite(c, from_obj, to_obj); + else + err = copy_note(t, from_obj, to_obj, force, + combine_notes_overwrite); if (err) { error("Failed to copy notes from '%s' to '%s'", @@ -313,8 +425,12 @@ int notes_copy_from_stdin(int force) strbuf_list_free(split); } - commit_notes(t, "Notes added by 'git notes copy'"); - free_notes(t); + if (!rewrite_cmd) { + commit_notes(t, "Notes added by 'git notes copy'"); + free_notes(t); + } else { + finish_copy_notes_for_rewrite(c); + } return ret; } @@ -330,6 +446,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix) 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 }; + const char *rewrite_cmd = NULL; struct option options[] = { OPT_GROUP("Notes options"), OPT_CALLBACK('m', "message", &msg, "MSG", @@ -342,6 +459,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix) "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_STRING(0, "for-rewrite", &rewrite_cmd, "command", + "load rewriting config for (implies --stdin)"), OPT_END() }; @@ -390,6 +509,10 @@ int cmd_notes(int argc, const char **argv, const char *prefix) usage_with_options(git_notes_usage, options); } + if (!copy && rewrite_cmd) { + error("cannot use --for-rewrite with %s subcommand.", argv[0]); + 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); @@ -397,12 +520,12 @@ int cmd_notes(int argc, const char **argv, const char *prefix) if (copy) { const char *from_ref; - if (from_stdin) { + if (from_stdin || rewrite_cmd) { if (argc > 1) { error("too many parameters"); usage_with_options(git_notes_usage, options); } else { - return notes_copy_from_stdin(force); + return notes_copy_from_stdin(force, rewrite_cmd); } } if (argc < 3) { diff --git a/builtin.h b/builtin.h index cdf98477a6..464588b299 100644 --- a/builtin.h +++ b/builtin.h @@ -20,6 +20,23 @@ extern int commit_tree(const char *msg, unsigned char *tree, struct commit_list *parents, unsigned char *ret, const char *author); extern int commit_notes(struct notes_tree *t, const char *msg); + +struct notes_rewrite_cfg { + struct notes_tree **trees; + const char *cmd; + int enabled; + combine_notes_fn *combine; + struct string_list *refs; + int refs_from_env; + int mode_from_env; +}; + +combine_notes_fn *parse_combine_notes_fn(const char *v); +struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd); +int copy_note_for_rewrite(struct notes_rewrite_cfg *c, + const unsigned char *from_obj, const unsigned char *to_obj); +void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c); + extern int check_pager_config(const char *cmd); extern int cmd_add(int argc, const char **argv, const char *prefix); diff --git a/cache.h b/cache.h index fab53d66e4..a04f37f14b 100644 --- a/cache.h +++ b/cache.h @@ -386,6 +386,8 @@ static inline enum object_type object_type(unsigned int mode) #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF" #define GIT_NOTES_DEFAULT_REF "refs/notes/commits" #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF" +#define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF" +#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE" extern int is_bare_repository_cfg; extern int is_bare_repository(void); diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh index 60ad6a1675..aeec90a8e9 100755 --- a/t/t3301-notes.sh +++ b/t/t3301-notes.sh @@ -810,4 +810,199 @@ test_expect_success 'git notes copy --stdin' ' test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)" ' +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d +Author: A U Thor +Date: Thu Apr 7 15:26:13 2005 -0700 + + 14th +EOF + +test_expect_success 'git notes copy --for-rewrite (unconfigured)' ' + test_commit 14th && + test_commit 15th && + (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \ + echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) | + git notes copy --for-rewrite=foo && + git log -2 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + yet another note +$whitespace + yet another note + +commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d +Author: A U Thor +Date: Thu Apr 7 15:26:13 2005 -0700 + + 14th + +Notes (other): + other note +$whitespace + yet another note +EOF + +test_expect_success 'git notes copy --for-rewrite (enabled)' ' + git config notes.rewriteMode overwrite && + git config notes.rewriteRef "refs/notes/*" && + (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \ + echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) | + git notes copy --for-rewrite=foo && + git log -2 > output && + test_cmp expect output +' + +test_expect_success 'git notes copy --for-rewrite (disabled)' ' + git config notes.rewrite.bar false && + echo $(git rev-parse HEAD~3) $(git rev-parse HEAD) | + git notes copy --for-rewrite=bar && + git log -2 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + a fresh note +EOF + +test_expect_success 'git notes copy --for-rewrite (overwrite)' ' + git notes add -f -m"a fresh note" HEAD^ && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +test_expect_success 'git notes copy --for-rewrite (ignore)' ' + git config notes.rewriteMode ignore && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + a fresh note + another fresh note +EOF + +test_expect_success 'git notes copy --for-rewrite (append)' ' + git notes add -f -m"another fresh note" HEAD^ && + git config notes.rewriteMode concatenate && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + a fresh note + another fresh note + append 1 + append 2 +EOF + +test_expect_success 'git notes copy --for-rewrite (append two to one)' ' + git notes add -f -m"append 1" HEAD^ && + git notes add -f -m"append 2" HEAD^^ && + (echo $(git rev-parse HEAD^) $(git rev-parse HEAD); + echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) | + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +test_expect_success 'git notes copy --for-rewrite (append empty)' ' + git notes remove HEAD^ && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + replacement note 1 +EOF + +test_expect_success 'GIT_NOTES_REWRITE_MODE works' ' + git notes add -f -m"replacement note 1" HEAD^ && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +cat > expect << EOF +commit 37a0d4cba38afef96ba54a3ea567e6dac575700b +Author: A U Thor +Date: Thu Apr 7 15:27:13 2005 -0700 + + 15th + +Notes (other): + replacement note 2 +EOF + +test_expect_success 'GIT_NOTES_REWRITE_REF works' ' + git config notes.rewriteMode overwrite && + git notes add -f -m"replacement note 2" HEAD^ && + git config --unset-all notes.rewriteRef && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \ + git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' + +test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' ' + git config notes.rewriteRef refs/notes/other && + git notes add -f -m"replacement note 3" HEAD^ && + echo $(git rev-parse HEAD^) $(git rev-parse HEAD) | + GIT_NOTES_REWRITE_REF= git notes copy --for-rewrite=foo && + git log -1 > output && + test_cmp expect output +' test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 90115863bc..806b83292f 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -56,6 +56,8 @@ unset SHA1_FILE_DIRECTORIES unset SHA1_FILE_DIRECTORY unset GIT_NOTES_REF unset GIT_NOTES_DISPLAY_REF +unset GIT_NOTES_REWRITE_REF +unset GIT_NOTES_REWRITE_MODE GIT_MERGE_VERBOSITY=5 export GIT_MERGE_VERBOSITY export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME -- cgit v1.3 From dcf783a26110ab99f2052e378ee76c3542a4b9e9 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Fri, 12 Mar 2010 18:04:35 +0100 Subject: notes: add shorthand --ref to override GIT_NOTES_REF Adds a shorthand option that overrides the GIT_NOTES_REF variable, and hence determines the notes tree that will be manipulated. It also DWIMs a refs/notes/ prefix. Signed-off-by: Thomas Rast Acked-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-notes.txt | 5 +++++ builtin-notes.c | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'Documentation/git-notes.txt') diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index b12d1cf539..dbfa1e88e6 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -116,6 +116,11 @@ OPTIONS Like '-C', but with '-c' the editor is invoked, so that the user can further edit the note message. +--ref :: + Manipulate the notes tree in . This overrides both + GIT_NOTES_REF and the "core.notesRef" configuration. The ref + is taken to be in `refs/notes/` if it is not qualified. + Author ------ Written by Johannes Schindelin and diff --git a/builtin-notes.c b/builtin-notes.c index 026cfd32a8..2e45be9de7 100644 --- a/builtin-notes.c +++ b/builtin-notes.c @@ -447,6 +447,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix) int given_object = 0, i = 1, retval = 0; struct msg_arg msg = { 0, 0, STRBUF_INIT }; const char *rewrite_cmd = NULL; + const char *override_notes_ref = NULL; struct option options[] = { OPT_GROUP("Notes options"), OPT_CALLBACK('m', "message", &msg, "MSG", @@ -459,6 +460,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix) "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_STRING(0, "ref", &override_notes_ref, "notes_ref", + "use notes from "), OPT_STRING(0, "for-rewrite", &rewrite_cmd, "command", "load rewriting config for (implies --stdin)"), OPT_END() @@ -468,6 +471,19 @@ int cmd_notes(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_notes_usage, 0); + if (override_notes_ref) { + struct strbuf sb = STRBUF_INIT; + if (!prefixcmp(override_notes_ref, "refs/notes/")) + /* we're happy */; + else if (!prefixcmp(override_notes_ref, "notes/")) + strbuf_addstr(&sb, "refs/"); + else + strbuf_addstr(&sb, "refs/notes/"); + strbuf_addstr(&sb, override_notes_ref); + setenv("GIT_NOTES_REF", sb.buf, 1); + strbuf_release(&sb); + } + if (argc && !strcmp(argv[0], "list")) list = 1; else if (argc && !strcmp(argv[0], "add")) -- cgit v1.3 From 66d681998411e8e5034080d5267a5e0f6cdc0c17 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Fri, 12 Mar 2010 18:04:37 +0100 Subject: git-notes(1): add a section about the meaning of history To the displaying code, the only interesting thing about a notes ref is that it has a tree of the required format. However, notes actually have a history since they are recorded as successive commits. Make a note about the existence of this history in the manpage, but keep some doors open if we want to change the details. Signed-off-by: Thomas Rast Acked-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/git-notes.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'Documentation/git-notes.txt') diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt index dbfa1e88e6..e2701cff1a 100644 --- a/Documentation/git-notes.txt +++ b/Documentation/git-notes.txt @@ -121,6 +121,20 @@ OPTIONS GIT_NOTES_REF and the "core.notesRef" configuration. The ref is taken to be in `refs/notes/` if it is not qualified. + +NOTES +----- + +Every notes change creates a new commit at the specified notes ref. +You can therefore inspect the history of the notes by invoking, e.g., +`git log -p notes/commits`. + +Currently the commit message only records which operation triggered +the update, and the commit authorship is determined according to the +usual rules (see linkgit:git-commit[1]). These details may change in +the future. + + Author ------ Written by Johannes Schindelin and -- cgit v1.3