{"thread":{"id":"22999","subject":"[PATCH v7 01/13] test-lib: unset GIT_NOTES_REF to stop it from influencing tests","startedAt":"2010-03-12T17:04:24Z","lastAt":"2010-06-21T20:53:52Z","messageCount":18,"participants":["Thomas Rast","Ævar Arnfjörð Bjarmason","Junio C Hamano","Ramsay Jones"],"isPatch":true,"patchVersion":7,"patchTotal":13},"messages":[{"id":"136668","messageId":"cover.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"201003111103.22671.johan@herland.net","subject":"[PATCH v7 00/13] tr/display-notes","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:24Z","receivedAt":"2010-03-12T17:04:24Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Here's a hopefully last replacement for the series.  I implemented\nJohan's requests for changes and collected his acks; the only\nbehavioral change is that format_display_notes() no longer calls\ninit_display_notes() implicitly.\n\nThomas Rast (13):\n  test-lib: unset GIT_NOTES_REF to stop it from influencing tests\n  Support showing notes from more than one notes tree\n  Documentation: document post-rewrite hook\n  commit --amend: invoke post-rewrite hook\n  rebase: invoke post-rewrite hook\n  rebase -i: invoke post-rewrite hook\n  notes: implement 'git notes copy --stdin'\n  notes: implement helpers needed for note copying during rewrite\n  rebase: support automatic notes copying\n  commit --amend: copy notes to the new commit\n  notes: add shorthand --ref to override GIT_NOTES_REF\n  notes: track whether notes_trees were changed at all\n  git-notes(1): add a section about the meaning of history\n\n Documentation/config.txt         |   53 +++++-\n Documentation/git-notes.txt      |   46 ++++-\n Documentation/githooks.txt       |   38 ++++\n Documentation/pretty-options.txt |   11 +-\n builtin.h                        |   18 ++\n builtin/commit.c                 |   45 +++++\n builtin/log.c                    |    5 +\n builtin/notes.c                  |  197 ++++++++++++++++++++-\n cache.h                          |    3 +\n git-am.sh                        |   13 ++\n git-rebase--interactive.sh       |   52 +++++-\n git-rebase.sh                    |    6 +\n notes.c                          |  191 +++++++++++++++++++-\n notes.h                          |   66 +++++++\n pretty.c                         |    6 +-\n refs.c                           |    4 +-\n refs.h                           |    5 +\n revision.c                       |   21 ++\n revision.h                       |    5 +\n t/t3301-notes.sh                 |  377 +++++++++++++++++++++++++++++++++++++-\n t/t3400-rebase.sh                |   17 ++\n t/t3404-rebase-interactive.sh    |   24 +++\n t/t5407-post-rewrite-hook.sh     |  183 ++++++++++++++++++\n t/t7501-commit.sh                |   12 ++\n t/test-lib.sh                    |    4 +\n 25 files changed, 1369 insertions(+), 33 deletions(-)\n create mode 100755 t/t5407-post-rewrite-hook.sh\n"},{"id":"136665","messageId":"75b9ed21559947cee7b1800e17ba3e3ac5a6dda9.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 01/13] test-lib: unset GIT_NOTES_REF to stop it from influencing tests","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:25Z","receivedAt":"2010-03-12T17:04:25Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Signed-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n t/test-lib.sh |    1 +\n 1 files changed, 1 insertions(+), 0 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex a0e396a..400bc6b 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -54,6 +54,7 @@ unset GIT_OBJECT_DIRECTORY\n unset GIT_CEILING_DIRECTORIES\n unset SHA1_FILE_DIRECTORIES\n unset SHA1_FILE_DIRECTORY\n+unset GIT_NOTES_REF\n GIT_MERGE_VERBOSITY=5\n export GIT_MERGE_VERBOSITY\n export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136666","messageId":"4e30f78f8789d1f8927989eba50dc08c1b68d9ae.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 02/13] Support showing notes from more than one notes tree","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:26Z","receivedAt":"2010-03-12T17:04:26Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"With this patch, you can set notes.displayRef to a glob that points at\nyour favourite notes refs, e.g.,\n\n[notes]\n\tdisplayRef = refs/notes/*\n\nThen git-log and friends will show notes from all trees.\n\nThanks to Junio C Hamano for lots of feedback, which greatly\ninfluenced the design of the entire series and this commit in\nparticular.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n* don't silently init from format_display_notes\n\n Documentation/config.txt         |   23 +++++-\n Documentation/git-notes.txt      |   11 ++-\n Documentation/pretty-options.txt |   11 ++-\n builtin/log.c                    |    5 +\n cache.h                          |    1 +\n notes.c                          |  170 ++++++++++++++++++++++++++++++++++++--\n notes.h                          |   56 +++++++++++++\n pretty.c                         |    6 +-\n refs.c                           |    4 +-\n refs.h                           |    5 +\n revision.c                       |   21 +++++\n revision.h                       |    5 +\n t/t3301-notes.sh                 |  148 +++++++++++++++++++++++++++++++--\n t/test-lib.sh                    |    1 +\n 14 files changed, 438 insertions(+), 29 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex d9ee519..0d0aa9c 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -519,10 +519,12 @@ check that makes sure that existing object files will not get overwritten.\n core.notesRef::\n \tWhen showing commit messages, also show notes which are stored in\n \tthe given ref.  This ref is expected to contain files named\n-\tafter the full SHA-1 of the commit they annotate.\n+\tafter the full SHA-1 of the commit they annotate.  The ref\n+\tmust be fully qualified.\n +\n If such a file exists in the given ref, the referenced blob is read, and\n-appended to the commit message, separated by a \"Notes:\" line.  If the\n+appended to the commit message, separated by a \"Notes (<refname>):\"\n+line (shortened to \"Notes:\" in the case of \"refs/notes/commits\").  If the\n given ref itself does not exist, it is not an error, but means that no\n notes should be printed.\n +\n@@ -1341,6 +1343,23 @@ mergetool.keepTemporaries::\n mergetool.prompt::\n \tPrompt before each invocation of the merge resolution program.\n \n+notes.displayRef::\n+\tThe (fully qualified) refname from which to show notes when\n+\tshowing commit messages.  The value of this variable can be set\n+\tto a glob, in which case notes from all matching refs will be\n+\tshown.  You may also specify this configuration variable\n+\tseveral times.  A warning will be issued for refs that do not\n+\texist, but a glob that does not match any refs is silently\n+\tignored.\n++\n+This setting can be overridden with the `GIT_NOTES_DISPLAY_REF`\n+environment variable, which must be a colon separated list of refs or\n+globs.\n++\n+The effective value of \"core.notesRef\" (possibly overridden by\n+GIT_NOTES_REF) is also implicitly added to the list of refs to be\n+displayed.\n+\n pack.window::\n \tThe size of the window used by linkgit:git-pack-objects[1] when no\n \twindow size is given on the command line. Defaults to 10.\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex bef2f39..95b4bca 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -27,12 +27,13 @@ A typical use of notes is to extend a commit message without having\n to change the commit itself. Such commit notes can be shown by `git log`\n along with the original commit message. To discern these notes from the\n message stored in the commit object, the notes are indented like the\n-message, after an unindented line saying \"Notes:\".\n+message, after an unindented line saying \"Notes (<refname>):\" (or\n+\"Notes:\" for the default setting).\n \n-To disable notes, you have to set the config variable core.notesRef to\n-the empty string.  Alternatively, you can set it to a different ref,\n-something like \"refs/notes/bugzilla\".  This setting can be overridden\n-by the environment variable \"GIT_NOTES_REF\".\n+This command always manipulates the notes specified in \"core.notesRef\"\n+(see linkgit:git-config[1]), which can be overridden by GIT_NOTES_REF.\n+To change which notes are shown by 'git-log', see the\n+\"notes.displayRef\" configuration.\n \n \n SUBCOMMANDS\ndiff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt\nindex aa96cae..af6d2b9 100644\n--- a/Documentation/pretty-options.txt\n+++ b/Documentation/pretty-options.txt\n@@ -30,9 +30,18 @@ people using 80-column terminals.\n \tdefaults to UTF-8.\n \n --no-notes::\n---show-notes::\n+--show-notes[=<ref>]::\n \tShow the notes (see linkgit:git-notes[1]) that annotate the\n \tcommit, when showing the commit log message.  This is the default\n \tfor `git log`, `git show` and `git whatchanged` commands when\n \tthere is no `--pretty`, `--format` nor `--oneline` option is\n \tgiven on the command line.\n++\n+With an optional argument, add this ref to the list of notes.  The ref\n+is taken to be in `refs/notes/` if it is not qualified.\n+\n+--[no-]standard-notes::\n+\tEnable or disable populating the notes ref list from the\n+\t'core.notesRef' and 'notes.displayRef' variables (or\n+\tcorresponding environment overrides).  Enabled by default.\n+\tSee linkgit:git-config[1].\ndiff --git a/builtin/log.c b/builtin/log.c\nindex b70d0f7..9feb031 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -77,6 +77,8 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,\n \n \tif (!rev->show_notes_given && !rev->pretty_given)\n \t\trev->show_notes = 1;\n+\tif (rev->show_notes)\n+\t\tinit_display_notes(&rev->notes_opt);\n \n \tif (rev->diffopt.pickaxe || rev->diffopt.filter)\n \t\trev->always_show_header = 0;\n@@ -1100,6 +1102,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tif (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)\n \t\tDIFF_OPT_SET(&rev.diffopt, BINARY);\n \n+\tif (rev.show_notes)\n+\t\tinit_display_notes(&rev.notes_opt);\n+\n \tif (!use_stdout)\n \t\toutput_directory = set_outdir(prefix, output_directory);\n \ndiff --git a/cache.h b/cache.h\nindex ded3090..b25d180 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -387,6 +387,7 @@ static inline enum object_type object_type(unsigned int mode)\n #define ATTRIBUTE_MACRO_PREFIX \"[attr]\"\n #define GIT_NOTES_REF_ENVIRONMENT \"GIT_NOTES_REF\"\n #define GIT_NOTES_DEFAULT_REF \"refs/notes/commits\"\n+#define GIT_NOTES_DISPLAY_REF_ENVIRONMENT \"GIT_NOTES_DISPLAY_REF\"\n \n /*\n  * Repository-local GIT_* environment variables\ndiff --git a/notes.c b/notes.c\nindex a4f9926..216ad24 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -5,6 +5,8 @@\n #include \"utf8.h\"\n #include \"strbuf.h\"\n #include \"tree-walk.h\"\n+#include \"string-list.h\"\n+#include \"refs.h\"\n \n /*\n  * Use a non-balancing simple 16-tree structure with struct int_node as\n@@ -68,6 +70,9 @@ struct non_note {\n \n struct notes_tree default_notes_tree;\n \n+static struct string_list display_notes_refs;\n+static struct notes_tree **display_notes_trees;\n+\n static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,\n \t\tstruct int_node *node, unsigned int n);\n \n@@ -828,6 +833,83 @@ int combine_notes_ignore(unsigned char *cur_sha1,\n \treturn 0;\n }\n \n+static int string_list_add_one_ref(const char *path, const unsigned char *sha1,\n+\t\t\t\t   int flag, void *cb)\n+{\n+\tstruct string_list *refs = cb;\n+\tif (!unsorted_string_list_has_string(refs, path))\n+\t\tstring_list_append(path, refs);\n+\treturn 0;\n+}\n+\n+void string_list_add_refs_by_glob(struct string_list *list, const char *glob)\n+{\n+\tif (has_glob_specials(glob)) {\n+\t\tfor_each_glob_ref(string_list_add_one_ref, glob, list);\n+\t} else {\n+\t\tunsigned char sha1[20];\n+\t\tif (get_sha1(glob, sha1))\n+\t\t\twarning(\"notes ref %s is invalid\", glob);\n+\t\tif (!unsorted_string_list_has_string(list, glob))\n+\t\t\tstring_list_append(glob, list);\n+\t}\n+}\n+\n+void string_list_add_refs_from_colon_sep(struct string_list *list,\n+\t\t\t\t\t const char *globs)\n+{\n+\tstruct strbuf globbuf = STRBUF_INIT;\n+\tstruct strbuf **split;\n+\tint i;\n+\n+\tstrbuf_addstr(&globbuf, globs);\n+\tsplit = strbuf_split(&globbuf, ':');\n+\n+\tfor (i = 0; split[i]; i++) {\n+\t\tif (!split[i]->len)\n+\t\t\tcontinue;\n+\t\tif (split[i]->buf[split[i]->len-1] == ':')\n+\t\t\tstrbuf_setlen(split[i], split[i]->len-1);\n+\t\tstring_list_add_refs_by_glob(list, split[i]->buf);\n+\t}\n+\n+\tstrbuf_list_free(split);\n+\tstrbuf_release(&globbuf);\n+}\n+\n+static int string_list_add_refs_from_list(struct string_list_item *item,\n+\t\t\t\t\t  void *cb)\n+{\n+\tstruct string_list *list = cb;\n+\tstring_list_add_refs_by_glob(list, item->string);\n+\treturn 0;\n+}\n+\n+static int notes_display_config(const char *k, const char *v, void *cb)\n+{\n+\tint *load_refs = cb;\n+\n+\tif (*load_refs && !strcmp(k, \"notes.displayref\")) {\n+\t\tif (!v)\n+\t\t\tconfig_error_nonbool(k);\n+\t\tstring_list_add_refs_by_glob(&display_notes_refs, v);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static const char *default_notes_ref(void)\n+{\n+\tconst char *notes_ref = NULL;\n+\tif (!notes_ref)\n+\t\tnotes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);\n+\tif (!notes_ref)\n+\t\tnotes_ref = notes_ref_name; /* value of core.notesRef config */\n+\tif (!notes_ref)\n+\t\tnotes_ref = GIT_NOTES_DEFAULT_REF;\n+\treturn notes_ref;\n+}\n+\n void init_notes(struct notes_tree *t, const char *notes_ref,\n \t\tcombine_notes_fn combine_notes, int flags)\n {\n@@ -840,11 +922,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,\n \tassert(!t->initialized);\n \n \tif (!notes_ref)\n-\t\tnotes_ref = getenv(GIT_NOTES_REF_ENVIRONMENT);\n-\tif (!notes_ref)\n-\t\tnotes_ref = notes_ref_name; /* value of core.notesRef config */\n-\tif (!notes_ref)\n-\t\tnotes_ref = GIT_NOTES_DEFAULT_REF;\n+\t\tnotes_ref = default_notes_ref();\n \n \tif (!combine_notes)\n \t\tcombine_notes = combine_notes_concatenate;\n@@ -868,6 +946,64 @@ void init_notes(struct notes_tree *t, const char *notes_ref,\n \tload_subtree(t, &root_tree, t->root, 0);\n }\n \n+struct load_notes_cb_data\n+{\n+\tint counter;\n+\tstruct notes_tree **trees;\n+};\n+\n+static int load_one_display_note_ref(struct string_list_item *item,\n+\t\t\t\t     void *cb_data)\n+{\n+\tstruct load_notes_cb_data *c = cb_data;\n+\tstruct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));\n+\tinit_notes(t, item->string, combine_notes_ignore, 0);\n+\tc->trees[c->counter++] = t;\n+\treturn 0;\n+}\n+\n+struct notes_tree **load_notes_trees(struct string_list *refs)\n+{\n+\tstruct notes_tree **trees;\n+\tstruct load_notes_cb_data cb_data;\n+\ttrees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));\n+\tcb_data.counter = 0;\n+\tcb_data.trees = trees;\n+\tfor_each_string_list(load_one_display_note_ref, refs, &cb_data);\n+\ttrees[cb_data.counter] = NULL;\n+\treturn trees;\n+}\n+\n+void init_display_notes(struct display_notes_opt *opt)\n+{\n+\tchar *display_ref_env;\n+\tint load_config_refs = 0;\n+\tdisplay_notes_refs.strdup_strings = 1;\n+\n+\tassert(!display_notes_trees);\n+\n+\tif (!opt || !opt->suppress_default_notes) {\n+\t\tstring_list_append(default_notes_ref(), &display_notes_refs);\n+\t\tdisplay_ref_env = getenv(GIT_NOTES_DISPLAY_REF_ENVIRONMENT);\n+\t\tif (display_ref_env) {\n+\t\t\tstring_list_add_refs_from_colon_sep(&display_notes_refs,\n+\t\t\t\t\t\t\t    display_ref_env);\n+\t\t\tload_config_refs = 0;\n+\t\t} else\n+\t\t\tload_config_refs = 1;\n+\t}\n+\n+\tgit_config(notes_display_config, &load_config_refs);\n+\n+\tif (opt && opt->extra_notes_refs)\n+\t\tfor_each_string_list(string_list_add_refs_from_list,\n+\t\t\t\t     opt->extra_notes_refs,\n+\t\t\t\t     &display_notes_refs);\n+\n+\tdisplay_notes_trees = load_notes_trees(&display_notes_refs);\n+\tstring_list_clear(&display_notes_refs, 0);\n+}\n+\n void add_note(struct notes_tree *t, const unsigned char *object_sha1,\n \t\tconst unsigned char *note_sha1, combine_notes_fn combine_notes)\n {\n@@ -1016,8 +1152,18 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,\n \tif (msglen && msg[msglen - 1] == '\\n')\n \t\tmsglen--;\n \n-\tif (flags & NOTES_SHOW_HEADER)\n-\t\tstrbuf_addstr(sb, \"\\nNotes:\\n\");\n+\tif (flags & NOTES_SHOW_HEADER) {\n+\t\tconst char *ref = t->ref;\n+\t\tif (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) {\n+\t\t\tstrbuf_addstr(sb, \"\\nNotes:\\n\");\n+\t\t} else {\n+\t\t\tif (!prefixcmp(ref, \"refs/\"))\n+\t\t\t\tref += 5;\n+\t\t\tif (!prefixcmp(ref, \"notes/\"))\n+\t\t\t\tref += 6;\n+\t\t\tstrbuf_addf(sb, \"\\nNotes (%s):\\n\", ref);\n+\t\t}\n+\t}\n \n \tfor (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) {\n \t\tlinelen = strchrnul(msg_p, '\\n') - msg_p;\n@@ -1030,3 +1176,13 @@ void format_note(struct notes_tree *t, const unsigned char *object_sha1,\n \n \tfree(msg);\n }\n+\n+void format_display_notes(const unsigned char *object_sha1,\n+\t\t\t  struct strbuf *sb, const char *output_encoding, int flags)\n+{\n+\tint i;\n+\tassert(display_notes_trees);\n+\tfor (i = 0; display_notes_trees[i]; i++)\n+\t\tformat_note(display_notes_trees[i], object_sha1, sb,\n+\t\t\t    output_encoding, flags);\n+}\ndiff --git a/notes.h b/notes.h\nindex bad03cc..69e995d 100644\n--- a/notes.h\n+++ b/notes.h\n@@ -198,4 +198,60 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,\n void format_note(struct notes_tree *t, const unsigned char *object_sha1,\n \t\tstruct strbuf *sb, const char *output_encoding, int flags);\n \n+\n+struct string_list;\n+\n+struct display_notes_opt\n+{\n+\tint suppress_default_notes : 1;\n+\tstruct string_list *extra_notes_refs;\n+};\n+\n+/*\n+ * Load the notes machinery for displaying several notes trees.\n+ *\n+ * If 'opt' is not NULL, then it specifies additional settings for the\n+ * displaying:\n+ *\n+ * - suppress_default_notes indicates that the notes from\n+ *   core.notesRef and notes.displayRef should not be loaded.\n+ *\n+ * - extra_notes_refs may contain a list of globs (in the same style\n+ *   as notes.displayRef) where notes should be loaded from.\n+ */\n+void init_display_notes(struct display_notes_opt *opt);\n+\n+/*\n+ * Append notes for the given 'object_sha1' from all trees set up by\n+ * init_display_notes() to 'sb'.  The 'flags' are a bitwise\n+ * combination of\n+ *\n+ * - NOTES_SHOW_HEADER: add a 'Notes (refname):' header\n+ *\n+ * - NOTES_INDENT: indent the notes by 4 places\n+ *\n+ * You *must* call init_display_notes() before using this function.\n+ */\n+void format_display_notes(const unsigned char *object_sha1,\n+\t\t\t  struct strbuf *sb, const char *output_encoding, int flags);\n+\n+/*\n+ * Load the notes tree from each ref listed in 'refs'.  The output is\n+ * an array of notes_tree*, terminated by a NULL.\n+ */\n+struct notes_tree **load_notes_trees(struct string_list *refs);\n+\n+/*\n+ * Add all refs that match 'glob' to the 'list'.\n+ */\n+void string_list_add_refs_by_glob(struct string_list *list, const char *glob);\n+\n+/*\n+ * Add all refs from a colon-separated glob list 'globs' to the end of\n+ * 'list'.  Empty components are ignored.  This helper is used to\n+ * parse GIT_NOTES_DISPLAY_REF style environment variables.\n+ */\n+void string_list_add_refs_from_colon_sep(struct string_list *list,\n+\t\t\t\t\t const char *globs);\n+\n #endif\ndiff --git a/pretty.c b/pretty.c\nindex f999485..6ba3da8 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -775,7 +775,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,\n \t\t}\n \t\treturn 0;\t/* unknown %g placeholder */\n \tcase 'N':\n-\t\tformat_note(NULL, commit->object.sha1, sb,\n+\t\tformat_display_notes(commit->object.sha1, sb,\n \t\t\t    git_log_output_encoding ? git_log_output_encoding\n \t\t\t\t\t\t    : git_commit_encoding, 0);\n \t\treturn 1;\n@@ -1096,8 +1096,8 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,\n \t\tstrbuf_addch(sb, '\\n');\n \n \tif (context->show_notes)\n-\t\tformat_note(NULL, commit->object.sha1, sb, encoding,\n-\t\t\t    NOTES_SHOW_HEADER | NOTES_INDENT);\n+\t\tformat_display_notes(commit->object.sha1, sb, encoding,\n+\t\t\t\t     NOTES_SHOW_HEADER | NOTES_INDENT);\n \n \tfree(reencoded);\n }\ndiff --git a/refs.c b/refs.c\nindex f3fcbe0..5a860c4 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -695,7 +695,6 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n {\n \tstruct strbuf real_pattern = STRBUF_INIT;\n \tstruct ref_filter filter;\n-\tconst char *has_glob_specials;\n \tint ret;\n \n \tif (!prefix && prefixcmp(pattern, \"refs/\"))\n@@ -704,8 +703,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,\n \t\tstrbuf_addstr(&real_pattern, prefix);\n \tstrbuf_addstr(&real_pattern, pattern);\n \n-\thas_glob_specials = strpbrk(pattern, \"?*[\");\n-\tif (!has_glob_specials) {\n+\tif (!has_glob_specials(pattern)) {\n \t\t/* Append implied '/' '*' if not present. */\n \t\tif (real_pattern.buf[real_pattern.len - 1] != '/')\n \t\t\tstrbuf_addch(&real_pattern, '/');\ndiff --git a/refs.h b/refs.h\nindex f7648b9..4a18b08 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -28,6 +28,11 @@ struct ref_lock {\n extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *);\n extern int for_each_glob_ref_in(each_ref_fn, const char *pattern, const char* prefix, void *);\n \n+static inline const char *has_glob_specials(const char *pattern)\n+{\n+\treturn strpbrk(pattern, \"?*[\");\n+}\n+\n /* can be used to learn about broken ref and symref */\n extern int for_each_rawref(each_ref_fn, void *);\n \ndiff --git a/revision.c b/revision.c\nindex 29721ec..d6e842e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -12,6 +12,7 @@\n #include \"patch-ids.h\"\n #include \"decorate.h\"\n #include \"log-tree.h\"\n+#include \"string-list.h\"\n \n volatile show_early_output_fn_t show_early_output;\n \n@@ -1191,9 +1192,29 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg\n \t} else if (!strcmp(arg, \"--show-notes\")) {\n \t\trevs->show_notes = 1;\n \t\trevs->show_notes_given = 1;\n+\t} else if (!prefixcmp(arg, \"--show-notes=\")) {\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\t\trevs->show_notes = 1;\n+\t\trevs->show_notes_given = 1;\n+\t\tif (!revs->notes_opt.extra_notes_refs)\n+\t\t\trevs->notes_opt.extra_notes_refs = xcalloc(1, sizeof(struct string_list));\n+\t\tif (!prefixcmp(arg+13, \"refs/\"))\n+\t\t\t/* happy */;\n+\t\telse if (!prefixcmp(arg+13, \"notes/\"))\n+\t\t\tstrbuf_addstr(&buf, \"refs/\");\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, \"refs/notes/\");\n+\t\tstrbuf_addstr(&buf, arg+13);\n+\t\tstring_list_append(strbuf_detach(&buf, NULL),\n+\t\t\t\t   revs->notes_opt.extra_notes_refs);\n \t} else if (!strcmp(arg, \"--no-notes\")) {\n \t\trevs->show_notes = 0;\n \t\trevs->show_notes_given = 1;\n+\t} else if (!strcmp(arg, \"--standard-notes\")) {\n+\t\trevs->show_notes_given = 1;\n+\t\trevs->notes_opt.suppress_default_notes = 0;\n+\t} else if (!strcmp(arg, \"--no-standard-notes\")) {\n+\t\trevs->notes_opt.suppress_default_notes = 1;\n \t} else if (!strcmp(arg, \"--oneline\")) {\n \t\trevs->verbose_header = 1;\n \t\tget_commit_format(\"oneline\", revs);\ndiff --git a/revision.h b/revision.h\nindex a14deef..580f6ec 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -3,6 +3,7 @@\n \n #include \"parse-options.h\"\n #include \"grep.h\"\n+#include \"notes.h\"\n \n #define SEEN\t\t(1u<<0)\n #define UNINTERESTING   (1u<<1)\n@@ -20,6 +21,7 @@\n \n struct rev_info;\n struct log_info;\n+struct string_list;\n \n struct rev_info {\n \t/* Starting list */\n@@ -126,6 +128,9 @@ struct rev_info {\n \tstruct reflog_walk_info *reflog_info;\n \tstruct decoration children;\n \tstruct decoration merge_simplification;\n+\n+\t/* notes-specific options: which refs to show */\n+\tstruct display_notes_opt notes_opt;\n };\n \n #define REV_TREE_SAME\t\t0\ndiff --git a/t/t3301-notes.sh b/t/t3301-notes.sh\nindex 37b9687..f6cdb33 100755\n--- a/t/t3301-notes.sh\n+++ b/t/t3301-notes.sh\n@@ -416,7 +416,7 @@ Date:   Thu Apr 7 15:18:13 2005 -0700\n \n     6th\n \n-Notes:\n+Notes (other):\n     other note\n EOF\n \n@@ -449,7 +449,139 @@ test_expect_success 'Do not show note when core.notesRef is overridden' '\n \ttest_cmp expect-not-other output\n '\n \n+cat > expect-both << EOF\n+commit 387a89921c73d7ed72cd94d179c1c7048ca47756\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:18:13 2005 -0700\n+\n+    6th\n+\n+Notes:\n+    order test\n+\n+Notes (other):\n+    other note\n+\n+commit bd1753200303d0a0344be813e504253b3d98e74d\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:17:13 2005 -0700\n+\n+    5th\n+\n+Notes:\n+    replacement for deleted note\n+EOF\n+\n+test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '\n+\tGIT_NOTES_REF=refs/notes/commits git notes add \\\n+\t\t-m\"replacement for deleted note\" HEAD^ &&\n+\tGIT_NOTES_REF=refs/notes/commits git notes add -m\"order test\" &&\n+\tgit config --unset core.notesRef &&\n+\tgit config notes.displayRef \"refs/notes/*\" &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+test_expect_success 'core.notesRef is implicitly in notes.displayRef' '\n+\tgit config core.notesRef refs/notes/commits &&\n+\tgit config notes.displayRef refs/notes/other &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+test_expect_success 'notes.displayRef can be given more than once' '\n+\tgit config --unset core.notesRef &&\n+\tgit config notes.displayRef refs/notes/commits &&\n+\tgit config --add notes.displayRef refs/notes/other &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+cat > expect-both-reversed << EOF\n+commit 387a89921c73d7ed72cd94d179c1c7048ca47756\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:18:13 2005 -0700\n+\n+    6th\n+\n+Notes (other):\n+    other note\n+\n+Notes:\n+    order test\n+EOF\n+\n+test_expect_success 'notes.displayRef respects order' '\n+\tgit config core.notesRef refs/notes/other &&\n+\tgit config --unset-all notes.displayRef &&\n+\tgit config notes.displayRef refs/notes/commits &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect-both-reversed output\n+'\n+\n+test_expect_success 'GIT_NOTES_DISPLAY_REF works' '\n+\tgit config --unset-all core.notesRef &&\n+\tgit config --unset-all notes.displayRef &&\n+\tGIT_NOTES_DISPLAY_REF=refs/notes/commits:refs/notes/other \\\n+\t\tgit log -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+cat > expect-none << EOF\n+commit 387a89921c73d7ed72cd94d179c1c7048ca47756\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:18:13 2005 -0700\n+\n+    6th\n+\n+commit bd1753200303d0a0344be813e504253b3d98e74d\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:17:13 2005 -0700\n+\n+    5th\n+EOF\n+\n+test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '\n+\tgit config notes.displayRef \"refs/notes/*\" &&\n+\tGIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 > output &&\n+\ttest_cmp expect-none output\n+'\n+\n+test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' '\n+\tGIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+cat > expect-commits << EOF\n+commit 387a89921c73d7ed72cd94d179c1c7048ca47756\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:18:13 2005 -0700\n+\n+    6th\n+\n+Notes:\n+    order test\n+EOF\n+\n+test_expect_success '--no-standard-notes' '\n+\tgit log --no-standard-notes --show-notes=commits -1 > output &&\n+\ttest_cmp expect-commits output\n+'\n+\n+test_expect_success '--standard-notes' '\n+\tgit log --no-standard-notes --show-notes=commits \\\n+\t\t--standard-notes -2 > output &&\n+\ttest_cmp expect-both output\n+'\n+\n+test_expect_success '--show-notes=ref accumulates' '\n+\tgit log --show-notes=other --show-notes=commits \\\n+\t\t --no-standard-notes -1 > output &&\n+\ttest_cmp expect-both-reversed output\n+'\n+\n test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '\n+\tgit config core.notesRef refs/notes/other &&\n \techo \"Note on a tree\" > expect\n \tgit notes add -m \"Note on a tree\" HEAD: &&\n \tgit notes show HEAD: > actual &&\n@@ -473,7 +605,7 @@ Date:   Thu Apr 7 15:19:13 2005 -0700\n \n     7th\n \n-Notes:\n+Notes (other):\n     other note\n EOF\n \n@@ -504,7 +636,7 @@ Date:   Thu Apr 7 15:21:13 2005 -0700\n \n     9th\n \n-Notes:\n+Notes (other):\n     yet another note\n EOF\n \n@@ -534,7 +666,7 @@ Date:   Thu Apr 7 15:21:13 2005 -0700\n \n     9th\n \n-Notes:\n+Notes (other):\n     yet another note\n $whitespace\n     yet another note\n@@ -553,7 +685,7 @@ Date:   Thu Apr 7 15:22:13 2005 -0700\n \n     10th\n \n-Notes:\n+Notes (other):\n     other note\n EOF\n \n@@ -570,7 +702,7 @@ Date:   Thu Apr 7 15:22:13 2005 -0700\n \n     10th\n \n-Notes:\n+Notes (other):\n     other note\n $whitespace\n     yet another note\n@@ -589,7 +721,7 @@ Date:   Thu Apr 7 15:23:13 2005 -0700\n \n     11th\n \n-Notes:\n+Notes (other):\n     other note\n $whitespace\n     yet another note\n@@ -620,7 +752,7 @@ Date:   Thu Apr 7 15:23:13 2005 -0700\n \n     11th\n \n-Notes:\n+Notes (other):\n     yet another note\n $whitespace\n     yet another note\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 400bc6b..3d026b4 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -55,6 +55,7 @@ unset GIT_CEILING_DIRECTORIES\n unset SHA1_FILE_DIRECTORIES\n unset SHA1_FILE_DIRECTORY\n unset GIT_NOTES_REF\n+unset GIT_NOTES_DISPLAY_REF\n GIT_MERGE_VERBOSITY=5\n export GIT_MERGE_VERBOSITY\n export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136678","messageId":"2cbffdbdfb20a0c570fb2b7030a106c1c78768a5.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 03/13] Documentation: document post-rewrite hook","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:27Z","receivedAt":"2010-03-12T17:04:27Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"This defines the behaviour of the post-rewrite hook support, which\nwill be implemented in the following patches.\n\nWe deliberately do not document how often the hook will be invoked per\nrewriting command, but the interface is designed to keep that at\n\"once\".  This would currently not matter too much, since both rebase\nand filter-branch are shellscripts and spawn many processes anyway.\nHowever, when a fast sequencer in C is implemented, it will be\nbeneficial to only have to run the hook once.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n Documentation/githooks.txt |   34 ++++++++++++++++++++++++++++++++++\n 1 files changed, 34 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex 87e2c03..a741769 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -317,6 +317,40 @@ This hook is invoked by 'git gc --auto'. It takes no parameter, and\n exiting with non-zero status from this script causes the 'git gc --auto'\n to abort.\n \n+post-rewrite\n+~~~~~~~~~~~~\n+\n+This hook is invoked by commands that rewrite commits (`git commit\n+--amend`, 'git-rebase'; currently 'git-filter-branch' does 'not' call\n+it!).  Its first argument denotes the command it was invoked by:\n+currently one of `amend` or `rebase`.  Further command-dependent\n+arguments may be passed in the future.\n+\n+The hook receives a list of the rewritten commits on stdin, in the\n+format\n+\n+  <old-sha1> SP <new-sha1> [ SP <extra-info> ] LF\n+\n+The 'extra-info' is again command-dependent.  If it is empty, the\n+preceding SP is also omitted.  Currently, no commands pass any\n+'extra-info'.\n+\n+The following command-specific comments apply:\n+\n+rebase::\n+\tFor the 'squash' and 'fixup' operation, all commits that were\n+\tsquashed are listed as being rewritten to the squashed commit.\n+\tThis means that there will be several lines sharing the same\n+\t'new-sha1'.\n++\n+The commits are guaranteed to be listed in the order that they were\n+processed by rebase.\n+\n+There is no default 'post-rewrite' hook, but see the\n+`post-receive-copy-notes` script in `contrib/hooks` for an example\n+that copies your git-notes to the rewritten commits.\n+\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136673","messageId":"608dc1b14c648d26063b7a0a71382ab0c44b8b39.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 04/13] commit --amend: invoke post-rewrite hook","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:28Z","receivedAt":"2010-03-12T17:04:28Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"The rough structure of run_rewrite_hook() comes from\nrun_receive_hook() in receive-pack.\n\nWe introduce a --no-post-rewrite option and use it to avoid the hook\nwhen called from git-rebase -i 'edit'.  The next patch will add full\nsupport in git-rebase, and we only want to invoke the hook once.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n builtin/commit.c             |   39 +++++++++++++++++++++++++++++++\n git-rebase--interactive.sh   |    2 +-\n t/t5407-post-rewrite-hook.sh |   52 ++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 92 insertions(+), 1 deletions(-)\n create mode 100755 t/t5407-post-rewrite-hook.sh\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex f4c7344..0367412 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -66,6 +66,7 @@\n static char *author_name, *author_email, *author_date;\n static int all, edit_flag, also, interactive, only, amend, signoff;\n static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n+static int no_post_rewrite;\n static char *untracked_files_arg, *force_date;\n /*\n  * The default commit message cleanup mode will remove the lines\n@@ -137,6 +138,7 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)\n \tOPT_BOOLEAN('z', \"null\", &null_termination,\n \t\t    \"terminate entries with NUL\"),\n \tOPT_BOOLEAN(0, \"amend\", &amend, \"amend previous commit\"),\n+\tOPT_BOOLEAN(0, \"no-post-rewrite\", &no_post_rewrite, \"bypass post-rewrite hook\"),\n \t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, \"mode\", \"show untracked files, optional modes: all, normal, no. (Default: all)\", PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n \tOPT_BOOLEAN(0, \"allow-empty\", &allow_empty, \"ok to record an empty change\"),\n \t/* end commit contents options */\n@@ -1160,6 +1162,40 @@ static int git_commit_config(const char *k, const char *v, void *cb)\n \treturn git_status_config(k, v, s);\n }\n \n+static const char post_rewrite_hook[] = \"hooks/post-rewrite\";\n+\n+static int run_rewrite_hook(const unsigned char *oldsha1,\n+\t\t\t    const unsigned char *newsha1)\n+{\n+\t/* oldsha1 SP newsha1 LF NUL */\n+\tstatic char buf[2*40 + 3];\n+\tstruct child_process proc;\n+\tconst char *argv[3];\n+\tint code;\n+\tsize_t n;\n+\n+\tif (access(git_path(post_rewrite_hook), X_OK) < 0)\n+\t\treturn 0;\n+\n+\targv[0] = git_path(post_rewrite_hook);\n+\targv[1] = \"amend\";\n+\targv[2] = NULL;\n+\n+\tmemset(&proc, 0, sizeof(proc));\n+\tproc.argv = argv;\n+\tproc.in = -1;\n+\tproc.stdout_to_stderr = 1;\n+\n+\tcode = start_command(&proc);\n+\tif (code)\n+\t\treturn code;\n+\tn = snprintf(buf, sizeof(buf), \"%s %s\\n\",\n+\t\t     sha1_to_hex(oldsha1), sha1_to_hex(newsha1));\n+\twrite_in_full(proc.in, buf, n);\n+\tclose(proc.in);\n+\treturn finish_command(&proc);\n+}\n+\n int cmd_commit(int argc, const char **argv, const char *prefix)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n@@ -1303,6 +1339,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \n \trerere(0);\n \trun_hook(get_index_file(), \"post-commit\", NULL);\n+\tif (amend && !no_post_rewrite) {\n+\t\trun_rewrite_hook(head_sha1, commit_sha1);\n+\t}\n \tif (!quiet)\n \t\tprint_summary(prefix, commit_sha1);\n \ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 92d19f5..c38efc4 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -436,7 +436,7 @@ do_next () {\n \t\tmark_action_done\n \t\tpick_one $sha1 ||\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n-\t\tgit commit --amend\n+\t\tgit commit --amend --no-post-rewrite\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nnew file mode 100755\nindex 0000000..1020af9\n--- /dev/null\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2010 Thomas Rast\n+#\n+\n+test_description='Test the post-rewrite hook.'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_commit A foo A &&\n+\ttest_commit B foo B &&\n+\ttest_commit C foo C &&\n+\ttest_commit D foo D\n+'\n+\n+mkdir .git/hooks\n+\n+cat >.git/hooks/post-rewrite <<EOF\n+#!/bin/sh\n+echo \\$@ > \"$TRASH_DIRECTORY\"/post-rewrite.args\n+cat > \"$TRASH_DIRECTORY\"/post-rewrite.data\n+EOF\n+chmod u+x .git/hooks/post-rewrite\n+\n+clear_hook_input () {\n+\trm -f post-rewrite.args post-rewrite.data\n+}\n+\n+verify_hook_input () {\n+\ttest_cmp \"$TRASH_DIRECTORY\"/post-rewrite.args expected.args &&\n+\ttest_cmp \"$TRASH_DIRECTORY\"/post-rewrite.data expected.data\n+}\n+\n+test_expect_success 'git commit --amend' '\n+\tclear_hook_input &&\n+\techo \"D new message\" > newmsg &&\n+\toldsha=$(git rev-parse HEAD^0) &&\n+\tgit commit -Fnewmsg --amend &&\n+\techo amend > expected.args &&\n+\techo $oldsha $(git rev-parse HEAD^0) > expected.data &&\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git commit --amend --no-post-rewrite' '\n+\tclear_hook_input &&\n+\techo \"D new message again\" > newmsg &&\n+\tgit commit --no-post-rewrite -Fnewmsg --amend &&\n+\ttest ! -f post-rewrite.args &&\n+\ttest ! -f post-rewrite.data\n+'\n+\n+test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136677","messageId":"a0baa1adb8937c7c0bffe2b9134027d8ddcd90cb.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 05/13] rebase: invoke post-rewrite hook","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:29Z","receivedAt":"2010-03-12T17:04:29Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"We have to deal with two separate code paths: a normal rebase, which\nactually goes through git-am; and rebase {-m|-s}.\n\nThe only small issue with both is that they need to remember the\noriginal sha1 across a possible conflict resolution.  rebase -m\nalready puts this information in $dotest/current, and we just\nintroduce a similar file for git-am.\n\nNote that in git-am, the hook really only runs when coming from\ngit-rebase: the code path that sets the $dotest/original-commit file\nis guarded by a test for $dotest/rebasing.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n git-am.sh                    |   10 ++++++++++\n git-rebase.sh                |    5 +++++\n t/t5407-post-rewrite-hook.sh |   30 ++++++++++++++++++++++++++++++\n 3 files changed, 45 insertions(+), 0 deletions(-)\n\ndiff --git a/git-am.sh b/git-am.sh\nindex 50a292a..9b73e0b 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -593,6 +593,7 @@ do\n \t\t\techo \"Patch is empty.  Was it split wrong?\"\n \t\t\tstop_here $this\n \t\t}\n+\t\trm -f \"$dotest/original-commit\"\n \t\tif test -f \"$dotest/rebasing\" &&\n \t\t\tcommit=$(sed -e 's/^From \\([0-9a-f]*\\) .*/\\1/' \\\n \t\t\t\t-e q \"$dotest/$msgnum\") &&\n@@ -600,6 +601,7 @@ do\n \t\tthen\n \t\t\tgit cat-file commit \"$commit\" |\n \t\t\tsed -e '1,/^$/d' >\"$dotest/msg-clean\"\n+\t\t\techo \"$commit\" > \"$dotest/original-commit\"\n \t\telse\n \t\t\t{\n \t\t\t\tsed -n '/^Subject/ s/Subject: //p' \"$dotest/info\"\n@@ -783,6 +785,10 @@ do\n \tgit update-ref -m \"$GIT_REFLOG_ACTION: $FIRSTLINE\" HEAD $commit $parent ||\n \tstop_here $this\n \n+\tif test -f \"$dotest/original-commit\"; then\n+\t\techo \"$(cat \"$dotest/original-commit\") $commit\" >> \"$dotest/rewritten\"\n+\tfi\n+\n \tif test -x \"$GIT_DIR\"/hooks/post-applypatch\n \tthen\n \t\t\"$GIT_DIR\"/hooks/post-applypatch\n@@ -791,5 +797,9 @@ do\n \tgo_next\n done\n \n+if test -s \"$dotest\"/rewritten && test -x \"$GIT_DIR\"/hooks/post-rewrite; then\n+\t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$dotest\"/rewritten\n+fi\n+\n rm -fr \"$dotest\"\n git gc --auto\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex fb4fef7..52f8b9b 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -79,6 +79,7 @@ continue_merge () {\n \t\tthen\n \t\t\tprintf \"Committed: %0${prec}d \" $msgnum\n \t\tfi\n+\t\techo \"$cmt $(git rev-parse HEAD^0)\" >> \"$dotest/rewritten\"\n \telse\n \t\tif test -z \"$GIT_QUIET\"\n \t\tthen\n@@ -151,6 +152,10 @@ move_to_original_branch () {\n \n finish_rb_merge () {\n \tmove_to_original_branch\n+\tif test -x \"$GIT_DIR\"/hooks/post-rewrite &&\n+\t\ttest -s \"$dotest\"/rewritten; then\n+\t\t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$dotest\"/rewritten\n+\tfi\n \trm -r \"$dotest\"\n \tsay All done.\n }\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 1020af9..1ecaa4b 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -49,4 +49,34 @@ test_expect_success 'git commit --amend --no-post-rewrite' '\n \ttest ! -f post-rewrite.data\n '\n \n+test_expect_success 'git rebase' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_must_fail git rebase --onto A B &&\n+\techo C > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse C) $(git rev-parse HEAD^)\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git rebase --skip' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_must_fail git rebase --onto A B &&\n+\ttest_must_fail git rebase --skip &&\n+\techo D > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136676","messageId":"1c3480afdf81da22af59e50b37e1190f77c3130f.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 06/13] rebase -i: invoke post-rewrite hook","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:30Z","receivedAt":"2010-03-12T17:04:30Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Aside from the same issue that rebase also has (remembering the\noriginal commit across a conflict resolution), rebase -i brings an\nextra twist: We need to defer writing the rewritten list in the case\nof {squash,fixup} because their rewritten result should be the last\ncommit in the squashed group.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n git-rebase--interactive.sh   |   46 +++++++++++++++++++-\n t/t5407-post-rewrite-hook.sh |  101 ++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 146 insertions(+), 1 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c38efc4..f18a118 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -96,6 +96,13 @@ AUTHOR_SCRIPT=\"$DOTEST\"/author-script\n # command is processed, this file is deleted.\n AMEND=\"$DOTEST\"/amend\n \n+# For the post-rewrite hook, we make a list of rewritten commits and\n+# their new sha1s.  The rewritten-pending list keeps the sha1s of\n+# commits that have been processed, but not committed yet,\n+# e.g. because they are waiting for a 'squash' command.\n+REWRITTEN_LIST=\"$DOTEST\"/rewritten-list\n+REWRITTEN_PENDING=\"$DOTEST\"/rewritten-pending\n+\n PRESERVE_MERGES=\n STRATEGY=\n ONTO=\n@@ -198,6 +205,7 @@ make_patch () {\n }\n \n die_with_patch () {\n+\techo \"$1\" > \"$DOTEST\"/stopped-sha\n \tmake_patch \"$1\"\n \tgit rerere\n \tdie \"$2\"\n@@ -339,6 +347,7 @@ pick_one_preserving_merges () {\n \t\t\t\tprintf \"%s\\n\" \"$msg\" > \"$GIT_DIR\"/MERGE_MSG\n \t\t\t\tdie_with_patch $sha1 \"Error redoing merge $sha1\"\n \t\t\tfi\n+\t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$REWRITTEN_LIST\"\n \t\t\t;;\n \t\t*)\n \t\t\toutput git cherry-pick \"$@\" ||\n@@ -416,6 +425,26 @@ die_failed_squash() {\n \tdie_with_patch $1 \"\"\n }\n \n+flush_rewritten_pending() {\n+\ttest -s \"$REWRITTEN_PENDING\" || return\n+\tnewsha1=\"$(git rev-parse HEAD^0)\"\n+\tsed \"s/$/ $newsha1/\" < \"$REWRITTEN_PENDING\" >> \"$REWRITTEN_LIST\"\n+\trm -f \"$REWRITTEN_PENDING\"\n+}\n+\n+record_in_rewritten() {\n+\toldsha1=\"$(git rev-parse $1)\"\n+\techo \"$oldsha1\" >> \"$REWRITTEN_PENDING\"\n+\n+\tcase \"$(peek_next_command)\" in\n+\t    squash|s|fixup|f)\n+\t\t;;\n+\t    *)\n+\t\tflush_rewritten_pending\n+\t\t;;\n+\tesac\n+}\n+\n do_next () {\n \trm -f \"$MSG\" \"$AUTHOR_SCRIPT\" \"$AMEND\" || exit\n \tread command sha1 rest < \"$TODO\"\n@@ -429,6 +458,7 @@ do_next () {\n \t\tmark_action_done\n \t\tpick_one $sha1 ||\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n@@ -437,6 +467,7 @@ do_next () {\n \t\tpick_one $sha1 ||\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\tgit commit --amend --no-post-rewrite\n+\t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n@@ -444,6 +475,7 @@ do_next () {\n \t\tmark_action_done\n \t\tpick_one $sha1 ||\n \t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\techo \"$1\" > \"$DOTEST\"/stopped-sha\n \t\tmake_patch $sha1\n \t\tgit rev-parse --verify HEAD > \"$AMEND\"\n \t\twarn \"Stopped at $sha1... $rest\"\n@@ -500,6 +532,7 @@ do_next () {\n \t\t\trm -f \"$SQUASH_MSG\" \"$FIXUP_MSG\"\n \t\t\t;;\n \t\tesac\n+\t\trecord_in_rewritten $sha1\n \t\t;;\n \t*)\n \t\twarn \"Unknown command: $command $sha1 $rest\"\n@@ -528,6 +561,11 @@ do_next () {\n \t\ttest ! -f \"$DOTEST\"/verbose ||\n \t\t\tgit diff-tree --stat $(cat \"$DOTEST\"/head)..HEAD\n \t} &&\n+\tif test -x \"$GIT_DIR\"/hooks/post-rewrite &&\n+\t\ttest -s \"$REWRITTEN_LIST\"; then\n+\t\t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$REWRITTEN_LIST\"\n+\t\ttrue # we don't care if this hook failed\n+\tfi &&\n \trm -rf \"$DOTEST\" &&\n \tgit gc --auto &&\n \twarn \"Successfully rebased and updated $HEADNAME.\"\n@@ -562,7 +600,12 @@ skip_unnecessary_picks () {\n \t\tesac\n \t\techo \"$command${sha1:+ }$sha1${rest:+ }$rest\" >&$fd\n \tdone <\"$TODO\" >\"$TODO.new\" 3>>\"$DONE\" &&\n-\tmv -f \"$TODO\".new \"$TODO\" ||\n+\tmv -f \"$TODO\".new \"$TODO\" &&\n+\tcase \"$(peek_next_command)\" in\n+\tsquash|s|fixup|f)\n+\t\trecord_in_rewritten \"$ONTO\"\n+\t\t;;\n+\tesac ||\n \tdie \"Could not skip unnecessary pick commands\"\n }\n \n@@ -676,6 +719,7 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\ttest -n \"$amend\" && git reset --soft $amend\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\t\t}\n+\t\t\trecord_in_rewritten \"$(cat \"$DOTEST\"/stopped-sha)\"\n \t\tfi\n \n \t\trequire_clean_work_tree\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 1ecaa4b..f0f91f1 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -79,4 +79,105 @@ EOF\n \tverify_hook_input\n '\n \n+test_expect_success 'git rebase -m' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_must_fail git rebase -m --onto A B &&\n+\techo C > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse C) $(git rev-parse HEAD^)\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git rebase -m --skip' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_must_fail git rebase --onto A B &&\n+\ttest_must_fail git rebase --skip &&\n+\techo D > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+set_fake_editor\n+\n+# Helper to work around the lack of one-shot exporting for\n+# test_must_fail (as it is a shell function)\n+test_fail_interactive_rebase () {\n+\t(\n+\t\tFAKE_LINES=\"$1\" &&\n+\t\tshift &&\n+\t\texport FAKE_LINES &&\n+\t\ttest_must_fail git rebase -i \"$@\"\n+\t)\n+}\n+\n+test_expect_success 'git rebase -i (unchanged)' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_fail_interactive_rebase \"1 2\" --onto A B &&\n+\techo C > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse C) $(git rev-parse HEAD^)\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git rebase -i (skip)' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_fail_interactive_rebase \"2\" --onto A B &&\n+\techo D > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git rebase -i (squash)' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\ttest_fail_interactive_rebase \"1 squash 2\" --onto A B &&\n+\techo C > foo &&\n+\tgit add foo &&\n+\tgit rebase --continue &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse C) $(git rev-parse HEAD)\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n+test_expect_success 'git rebase -i (fixup without conflict)' '\n+\tgit reset --hard D &&\n+\tclear_hook_input &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase -i B &&\n+\techo rebase >expected.args &&\n+\tcat >expected.data <<EOF &&\n+$(git rev-parse C) $(git rev-parse HEAD)\n+$(git rev-parse D) $(git rev-parse HEAD)\n+EOF\n+\tverify_hook_input\n+'\n+\n test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136675","messageId":"e0fbd6edc13d94a097e8e7e3649b9e669f9b4ee3.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 07/13] notes: implement 'git notes copy --stdin'","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:31Z","receivedAt":"2010-03-12T17:04:31Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"This implements a mass-copy command that takes a sequence of lines in\nthe format\n\n  <from-sha1> SP <to-sha1> [ SP <rest> ] LF\n\non stdin, and copies each <from-sha1>'s notes to the <to-sha1>.  The\n<rest> is ignored.  The intent, of course, is that this can read the\nsame input that the 'post-rewrite' hook gets.\n\nThe copy_note() function is exposed for everyone's and in particular\nthe next commit's use.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n Documentation/git-notes.txt |   12 ++++++++-\n builtin/notes.c             |   56 ++++++++++++++++++++++++++++++++++++++++++-\n notes.c                     |   18 +++++++++++++\n notes.h                     |    9 +++++++\n t/t3301-notes.sh            |   34 ++++++++++++++++++++++++++\n 5 files changed, 127 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 95b4bca..064758b 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n [verse]\n 'git notes' [list [<object>]]\n 'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]\n-'git notes' copy [-f] <from-object> <to-object>\n+'git notes' copy [-f] ( --stdin | <from-object> <to-object> )\n 'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]\n 'git notes' edit [<object>]\n 'git notes' show [<object>]\n@@ -56,6 +56,16 @@ copy::\n \tobject has none (use -f to overwrite existing notes to the\n \tsecond object). This subcommand is equivalent to:\n \t`git notes add [-f] -C $(git notes list <from-object>) <to-object>`\n++\n+In `\\--stdin` mode, take lines in the format\n++\n+----------\n+<from-object> SP <to-object> [ SP <rest> ] LF\n+----------\n++\n+on standard input, and copy the notes from each <from-object> to its\n+corresponding <to-object>.  (The optional `<rest>` is ignored so that\n+the command can read the input given to the `post-rewrite` hook.)\n \n append::\n \tAppend to the notes of an existing object (defaults to HEAD).\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex feb710a..576a989 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -269,6 +269,46 @@ int commit_notes(struct notes_tree *t, const char *msg)\n \treturn 0;\n }\n \n+int notes_copy_from_stdin(int force)\n+{\n+\tstruct strbuf buf = STRBUF_INIT;\n+\tstruct notes_tree *t;\n+\tint ret = 0;\n+\n+\tinit_notes(NULL, NULL, NULL, 0);\n+\tt = &default_notes_tree;\n+\n+\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\t\tunsigned char from_obj[20], to_obj[20];\n+\t\tstruct strbuf **split;\n+\t\tint err;\n+\n+\t\tsplit = strbuf_split(&buf, ' ');\n+\t\tif (!split[0] || !split[1])\n+\t\t\tdie(\"Malformed input line: '%s'.\", buf.buf);\n+\t\tstrbuf_rtrim(split[0]);\n+\t\tstrbuf_rtrim(split[1]);\n+\t\tif (get_sha1(split[0]->buf, from_obj))\n+\t\t\tdie(\"Failed to resolve '%s' as a valid ref.\", split[0]->buf);\n+\t\tif (get_sha1(split[1]->buf, to_obj))\n+\t\t\tdie(\"Failed to resolve '%s' as a valid ref.\", split[1]->buf);\n+\n+\t\terr = copy_note(t, from_obj, to_obj, force, combine_notes_overwrite);\n+\n+\t\tif (err) {\n+\t\t\terror(\"Failed to copy notes from '%s' to '%s'\",\n+\t\t\t      split[0]->buf, split[1]->buf);\n+\t\t\tret = 1;\n+\t\t}\n+\n+\t\tstrbuf_list_free(split);\n+\t}\n+\n+\tcommit_notes(t, \"Notes added by 'git notes copy'\");\n+\tfree_notes(t);\n+\treturn ret;\n+}\n+\n int cmd_notes(int argc, const char **argv, const char *prefix)\n {\n \tstruct notes_tree *t;\n@@ -278,7 +318,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \tchar logmsg[100];\n \n \tint list = 0, add = 0, copy = 0, append = 0, edit = 0, show = 0,\n-\t    remove = 0, prune = 0, force = 0;\n+\t    remove = 0, prune = 0, force = 0, from_stdin = 0;\n \tint given_object = 0, i = 1, retval = 0;\n \tstruct msg_arg msg = { 0, 0, STRBUF_INIT };\n \tstruct option options[] = {\n@@ -297,6 +337,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t\t\tparse_reuse_arg},\n \t\tOPT_GROUP(\"Other options\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"replace existing notes\"),\n+\t\tOPT_BOOLEAN(0, \"stdin\", &from_stdin, \"read objects from stdin\"),\n \t\tOPT_END()\n \t};\n \n@@ -345,8 +386,21 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_notes_usage, options);\n \t}\n \n+\tif (!copy && from_stdin) {\n+\t\terror(\"cannot use --stdin with %s subcommand.\", argv[0]);\n+\t\tusage_with_options(git_notes_usage, options);\n+\t}\n+\n \tif (copy) {\n \t\tconst char *from_ref;\n+\t\tif (from_stdin) {\n+\t\t\tif (argc > 1) {\n+\t\t\t\terror(\"too many parameters\");\n+\t\t\t\tusage_with_options(git_notes_usage, options);\n+\t\t\t} else {\n+\t\t\t\treturn notes_copy_from_stdin(force);\n+\t\t\t}\n+\t\t}\n \t\tif (argc < 3) {\n \t\t\terror(\"too few parameters\");\n \t\t\tusage_with_options(git_notes_usage, options);\ndiff --git a/notes.c b/notes.c\nindex 216ad24..66912a3 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -1186,3 +1186,21 @@ void format_display_notes(const unsigned char *object_sha1,\n \t\tformat_note(display_notes_trees[i], object_sha1, sb,\n \t\t\t    output_encoding, flags);\n }\n+\n+int copy_note(struct notes_tree *t,\n+\t      const unsigned char *from_obj, const unsigned char *to_obj,\n+\t      int force, combine_notes_fn combine_fn)\n+{\n+\tconst unsigned char *note = get_note(t, from_obj);\n+\tconst unsigned char *existing_note = get_note(t, to_obj);\n+\n+\tif (!force && existing_note)\n+\t\treturn 1;\n+\n+\tif (note)\n+\t\tadd_note(t, to_obj, note, combine_fn);\n+\telse if (existing_note)\n+\t\tadd_note(t, to_obj, null_sha1, combine_fn);\n+\n+\treturn 0;\n+}\ndiff --git a/notes.h b/notes.h\nindex 69e995d..6166927 100644\n--- a/notes.h\n+++ b/notes.h\n@@ -100,6 +100,15 @@ void add_note(struct notes_tree *t, const unsigned char *object_sha1,\n \t\tconst unsigned char *object_sha1);\n \n /*\n+ * Copy a note from one object to another in the given notes_tree.\n+ *\n+ * Fails if the to_obj already has a note unless 'force' is true.\n+ */\n+int copy_note(struct notes_tree *t,\n+\t      const unsigned char *from_obj, const unsigned char *to_obj,\n+\t      int force, combine_notes_fn combine_fn);\n+\n+/*\n  * Flags controlling behaviour of for_each_note()\n  *\n  * Default behaviour of for_each_note() is to traverse every single note object\ndiff --git a/t/t3301-notes.sh b/t/t3301-notes.sh\nindex f6cdb33..29ef0c6 100755\n--- a/t/t3301-notes.sh\n+++ b/t/t3301-notes.sh\n@@ -777,4 +777,38 @@ test_expect_success 'cannot copy note from object without notes' '\n \ttest_must_fail git notes copy HEAD^ HEAD\n '\n \n+cat > expect << EOF\n+commit e5d4fb5698d564ab8c73551538ecaf2b0c666185\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:25:13 2005 -0700\n+\n+    13th\n+\n+Notes (other):\n+    yet another note\n+$whitespace\n+    yet another note\n+\n+commit 7038787dfe22a14c3867ce816dbba39845359719\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:24:13 2005 -0700\n+\n+    12th\n+\n+Notes (other):\n+    other note\n+$whitespace\n+    yet another note\n+EOF\n+\n+test_expect_success 'git notes copy --stdin' '\n+\t(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \\\n+\techo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |\n+\tgit notes copy --stdin &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect output &&\n+\ttest \"$(git notes list HEAD)\" = \"$(git notes list HEAD~2)\" &&\n+\ttest \"$(git notes list HEAD^)\" = \"$(git notes list HEAD~3)\"\n+'\n+\n test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136672","messageId":"4282af8beef234299ede82beae5eb22f99bb8505.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 08/13] notes: implement helpers needed for note copying during rewrite","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:32Z","receivedAt":"2010-03-12T17:04:32Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Implement helper functions to load the rewriting config, and to\nactually copy the notes.  Also document the config.\n\nSecondly, also implement an undocumented --for-rewrite=<cmd> option to\n'git notes copy' which is used like --stdin, but also puts the\nconfiguration for <cmd> into effect.  It will be needed to support the\ncopying in git-rebase.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n Documentation/config.txt    |   30 +++++++\n Documentation/git-notes.txt |    4 +\n Documentation/githooks.txt  |    4 +\n builtin.h                   |   18 ++++\n builtin/notes.c             |  139 +++++++++++++++++++++++++++++--\n cache.h                     |    2 +\n t/t3301-notes.sh            |  195 +++++++++++++++++++++++++++++++++++++++++++\n t/test-lib.sh               |    2 +\n 8 files changed, 386 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 0d0aa9c..25da59e 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1360,6 +1360,36 @@ The effective value of \"core.notesRef\" (possibly overridden by\n GIT_NOTES_REF) is also implicitly added to the list of refs to be\n displayed.\n \n+notes.rewrite.<command>::\n+\tWhen rewriting commits with <command> (currently `amend` or\n+\t`rebase`) and this variable is set to `true`, git\n+\tautomatically copies your notes from the original to the\n+\trewritten commit.  Defaults to `true`, but see\n+\t\"notes.rewriteRef\" below.\n++\n+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`\n+environment variable, which must be a colon separated list of refs or\n+globs.\n+\n+notes.rewriteMode::\n+\tWhen copying notes during a rewrite (see the\n+\t\"notes.rewrite.<command>\" option), determines what to do if\n+\tthe target commit already has a note.  Must be one of\n+\t`overwrite`, `concatenate`, or `ignore`.  Defaults to\n+\t`concatenate`.\n++\n+This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`\n+environment variable.\n+\n+notes.rewriteRef::\n+\tWhen copying notes during a rewrite, specifies the (fully\n+\tqualified) ref whose notes should be copied.  The ref may be a\n+\tglob, in which case notes in all matching refs will be copied.\n+\tYou may also specify this configuration several times.\n++\n+Does not have a default value; you must configure this variable to\n+enable note rewriting.\n+\n pack.window::\n \tThe size of the window used by linkgit:git-pack-objects[1] when no\n \twindow size is given on the command line. Defaults to 10.\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 064758b..77311bd 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -35,6 +35,10 @@ This command always manipulates the notes specified in \"core.notesRef\"\n To change which notes are shown by 'git-log', see the\n \"notes.displayRef\" configuration.\n \n+See the description of \"notes.rewrite.<command>\" in\n+linkgit:git-config[1] for a way of carrying your notes across commands\n+that rewrite commits.\n+\n \n SUBCOMMANDS\n -----------\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex a741769..7183aa9 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -335,6 +335,10 @@ The 'extra-info' is again command-dependent.  If it is empty, the\n preceding SP is also omitted.  Currently, no commands pass any\n 'extra-info'.\n \n+The hook always runs after the automatic note copying (see\n+\"notes.rewrite.<command>\" in linkgit:git-config.txt) has happened, and\n+thus has access to these notes.\n+\n The following command-specific comments apply:\n \n rebase::\ndiff --git a/builtin.h b/builtin.h\nindex cdf9847..8aebe61 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -20,6 +20,24 @@ extern int commit_tree(const char *msg, unsigned char *tree,\n \t\tstruct commit_list *parents, unsigned char *ret,\n \t\tconst char *author);\n extern int commit_notes(struct notes_tree *t, const char *msg);\n+\n+struct notes_rewrite_cfg\n+{\n+\tstruct notes_tree **trees;\n+\tconst char *cmd;\n+\tint enabled;\n+\tcombine_notes_fn *combine;\n+\tstruct string_list *refs;\n+\tint refs_from_env;\n+\tint mode_from_env;\n+};\n+\n+combine_notes_fn *parse_combine_notes_fn(const char *v);\n+struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);\n+int copy_note_for_rewrite(struct notes_rewrite_cfg *c,\n+\t\t\t  const unsigned char *from_obj, const unsigned char *to_obj);\n+void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);\n+\n extern int check_pager_config(const char *cmd);\n \n extern int cmd_add(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 576a989..6c2297a 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -16,6 +16,7 @@\n #include \"exec_cmd.h\"\n #include \"run-command.h\"\n #include \"parse-options.h\"\n+#include \"string-list.h\"\n \n static const char * const git_notes_usage[] = {\n \t\"git notes [list [<object>]]\",\n@@ -269,14 +270,121 @@ int commit_notes(struct notes_tree *t, const char *msg)\n \treturn 0;\n }\n \n-int notes_copy_from_stdin(int force)\n+\n+combine_notes_fn *parse_combine_notes_fn(const char *v)\n+{\n+\tif (!strcasecmp(v, \"overwrite\"))\n+\t\treturn combine_notes_overwrite;\n+\telse if (!strcasecmp(v, \"ignore\"))\n+\t\treturn combine_notes_ignore;\n+\telse if (!strcasecmp(v, \"concatenate\"))\n+\t\treturn combine_notes_concatenate;\n+\telse\n+\t\treturn NULL;\n+}\n+\n+static int notes_rewrite_config(const char *k, const char *v, void *cb)\n+{\n+\tstruct notes_rewrite_cfg *c = cb;\n+\tif (!prefixcmp(k, \"notes.rewrite.\") && !strcmp(k+14, c->cmd)) {\n+\t\tc->enabled = git_config_bool(k, v);\n+\t\treturn 0;\n+\t} else if (!c->mode_from_env && !strcmp(k, \"notes.rewritemode\")) {\n+\t\tif (!v)\n+\t\t\tconfig_error_nonbool(k);\n+\t\tc->combine = parse_combine_notes_fn(v);\n+\t\tif (!c->combine) {\n+\t\t\terror(\"Bad notes.rewriteMode value: '%s'\", v);\n+\t\t\treturn 1;\n+\t\t}\n+\t\treturn 0;\n+\t} else if (!c->refs_from_env && !strcmp(k, \"notes.rewriteref\")) {\n+\t\t/* note that a refs/ prefix is implied in the\n+\t\t * underlying for_each_glob_ref */\n+\t\tif (!prefixcmp(v, \"refs/notes/\"))\n+\t\t\tstring_list_add_refs_by_glob(c->refs, v);\n+\t\telse\n+\t\t\twarning(\"Refusing to rewrite notes in %s\"\n+\t\t\t\t\" (outside of refs/notes/)\", v);\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)\n+{\n+\tstruct notes_rewrite_cfg *c = xmalloc(sizeof(struct notes_rewrite_cfg));\n+\tconst char *rewrite_mode_env = getenv(GIT_NOTES_REWRITE_MODE_ENVIRONMENT);\n+\tconst char *rewrite_refs_env = getenv(GIT_NOTES_REWRITE_REF_ENVIRONMENT);\n+\tc->cmd = cmd;\n+\tc->enabled = 1;\n+\tc->combine = combine_notes_concatenate;\n+\tc->refs = xcalloc(1, sizeof(struct string_list));\n+\tc->refs->strdup_strings = 1;\n+\tc->refs_from_env = 0;\n+\tc->mode_from_env = 0;\n+\tif (rewrite_mode_env) {\n+\t\tc->mode_from_env = 1;\n+\t\tc->combine = parse_combine_notes_fn(rewrite_mode_env);\n+\t\tif (!c->combine)\n+\t\t\terror(\"Bad \" GIT_NOTES_REWRITE_MODE_ENVIRONMENT\n+\t\t\t      \" value: '%s'\", rewrite_mode_env);\n+\t}\n+\tif (rewrite_refs_env) {\n+\t\tc->refs_from_env = 1;\n+\t\tstring_list_add_refs_from_colon_sep(c->refs, rewrite_refs_env);\n+\t}\n+\tgit_config(notes_rewrite_config, c);\n+\tif (!c->enabled || !c->refs->nr) {\n+\t\tstring_list_clear(c->refs, 0);\n+\t\tfree(c->refs);\n+\t\tfree(c);\n+\t\treturn NULL;\n+\t}\n+\tc->trees = load_notes_trees(c->refs);\n+\tstring_list_clear(c->refs, 0);\n+\tfree(c->refs);\n+\treturn c;\n+}\n+\n+int copy_note_for_rewrite(struct notes_rewrite_cfg *c,\n+\t\t\t  const unsigned char *from_obj, const unsigned char *to_obj)\n+{\n+\tint ret = 0;\n+\tint i;\n+\tfor (i = 0; c->trees[i]; i++)\n+\t\tret = copy_note(c->trees[i], from_obj, to_obj, 1, c->combine) || ret;\n+\treturn ret;\n+}\n+\n+void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c)\n+{\n+\tint i;\n+\tfor (i = 0; c->trees[i]; i++) {\n+\t\tcommit_notes(c->trees[i], \"Notes added by 'git notes copy'\");\n+\t\tfree_notes(c->trees[i]);\n+\t}\n+\tfree(c->trees);\n+\tfree(c);\n+}\n+\n+int notes_copy_from_stdin(int force, const char *rewrite_cmd)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n+\tstruct notes_rewrite_cfg *c = NULL;\n \tstruct notes_tree *t;\n \tint ret = 0;\n \n-\tinit_notes(NULL, NULL, NULL, 0);\n-\tt = &default_notes_tree;\n+\tif (rewrite_cmd) {\n+\t\tc = init_copy_notes_for_rewrite(rewrite_cmd);\n+\t\tif (!c)\n+\t\t\treturn 0;\n+\t} else {\n+\t\tinit_notes(NULL, NULL, NULL, 0);\n+\t\tt = &default_notes_tree;\n+\t}\n \n \twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n \t\tunsigned char from_obj[20], to_obj[20];\n@@ -293,7 +401,11 @@ int notes_copy_from_stdin(int force)\n \t\tif (get_sha1(split[1]->buf, to_obj))\n \t\t\tdie(\"Failed to resolve '%s' as a valid ref.\", split[1]->buf);\n \n-\t\terr = copy_note(t, from_obj, to_obj, force, combine_notes_overwrite);\n+\t\tif (rewrite_cmd)\n+\t\t\terr = copy_note_for_rewrite(c, from_obj, to_obj);\n+\t\telse\n+\t\t\terr = copy_note(t, from_obj, to_obj, force,\n+\t\t\t\t\tcombine_notes_overwrite);\n \n \t\tif (err) {\n \t\t\terror(\"Failed to copy notes from '%s' to '%s'\",\n@@ -304,8 +416,12 @@ int notes_copy_from_stdin(int force)\n \t\tstrbuf_list_free(split);\n \t}\n \n-\tcommit_notes(t, \"Notes added by 'git notes copy'\");\n-\tfree_notes(t);\n+\tif (!rewrite_cmd) {\n+\t\tcommit_notes(t, \"Notes added by 'git notes copy'\");\n+\t\tfree_notes(t);\n+\t} else {\n+\t\tfinish_copy_notes_for_rewrite(c);\n+\t}\n \treturn ret;\n }\n \n@@ -321,6 +437,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t    remove = 0, prune = 0, force = 0, from_stdin = 0;\n \tint given_object = 0, i = 1, retval = 0;\n \tstruct msg_arg msg = { 0, 0, STRBUF_INIT };\n+\tconst char *rewrite_cmd = NULL;\n \tstruct option options[] = {\n \t\tOPT_GROUP(\"Notes contents options\"),\n \t\t{ OPTION_CALLBACK, 'm', \"message\", &msg, \"MSG\",\n@@ -338,6 +455,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t\tOPT_GROUP(\"Other options\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"replace existing notes\"),\n \t\tOPT_BOOLEAN(0, \"stdin\", &from_stdin, \"read objects from stdin\"),\n+\t\tOPT_STRING(0, \"for-rewrite\", &rewrite_cmd, \"command\",\n+\t\t\t   \"load rewriting config for <command> (implies --stdin)\"),\n \t\tOPT_END()\n \t};\n \n@@ -386,6 +505,10 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(git_notes_usage, options);\n \t}\n \n+\tif (!copy && rewrite_cmd) {\n+\t\terror(\"cannot use --for-rewrite with %s subcommand.\", argv[0]);\n+\t\tusage_with_options(git_notes_usage, options);\n+\t}\n \tif (!copy && from_stdin) {\n \t\terror(\"cannot use --stdin with %s subcommand.\", argv[0]);\n \t\tusage_with_options(git_notes_usage, options);\n@@ -393,12 +516,12 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \n \tif (copy) {\n \t\tconst char *from_ref;\n-\t\tif (from_stdin) {\n+\t\tif (from_stdin || rewrite_cmd) {\n \t\t\tif (argc > 1) {\n \t\t\t\terror(\"too many parameters\");\n \t\t\t\tusage_with_options(git_notes_usage, options);\n \t\t\t} else {\n-\t\t\t\treturn notes_copy_from_stdin(force);\n+\t\t\t\treturn notes_copy_from_stdin(force, rewrite_cmd);\n \t\t\t}\n \t\t}\n \t\tif (argc < 3) {\ndiff --git a/cache.h b/cache.h\nindex b25d180..32c18b1 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -388,6 +388,8 @@ static inline enum object_type object_type(unsigned int mode)\n #define GIT_NOTES_REF_ENVIRONMENT \"GIT_NOTES_REF\"\n #define GIT_NOTES_DEFAULT_REF \"refs/notes/commits\"\n #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT \"GIT_NOTES_DISPLAY_REF\"\n+#define GIT_NOTES_REWRITE_REF_ENVIRONMENT \"GIT_NOTES_REWRITE_REF\"\n+#define GIT_NOTES_REWRITE_MODE_ENVIRONMENT \"GIT_NOTES_REWRITE_MODE\"\n \n /*\n  * Repository-local GIT_* environment variables\ndiff --git a/t/t3301-notes.sh b/t/t3301-notes.sh\nindex 29ef0c6..a4a0b1d 100755\n--- a/t/t3301-notes.sh\n+++ b/t/t3301-notes.sh\n@@ -811,4 +811,199 @@ test_expect_success 'git notes copy --stdin' '\n \ttest \"$(git notes list HEAD^)\" = \"$(git notes list HEAD~3)\"\n '\n \n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:26:13 2005 -0700\n+\n+    14th\n+EOF\n+\n+test_expect_success 'git notes copy --for-rewrite (unconfigured)' '\n+\ttest_commit 14th &&\n+\ttest_commit 15th &&\n+\t(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \\\n+\techo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    yet another note\n+$whitespace\n+    yet another note\n+\n+commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:26:13 2005 -0700\n+\n+    14th\n+\n+Notes (other):\n+    other note\n+$whitespace\n+    yet another note\n+EOF\n+\n+test_expect_success 'git notes copy --for-rewrite (enabled)' '\n+\tgit config notes.rewriteMode overwrite &&\n+\tgit config notes.rewriteRef \"refs/notes/*\" &&\n+\t(echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \\\n+\techo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect output\n+'\n+\n+test_expect_success 'git notes copy --for-rewrite (disabled)' '\n+\tgit config notes.rewrite.bar false &&\n+\techo $(git rev-parse HEAD~3) $(git rev-parse HEAD) |\n+\tgit notes copy --for-rewrite=bar &&\n+\tgit log -2 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    a fresh note\n+EOF\n+\n+test_expect_success 'git notes copy --for-rewrite (overwrite)' '\n+\tgit notes add -f -m\"a fresh note\" HEAD^ &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+test_expect_success 'git notes copy --for-rewrite (ignore)' '\n+\tgit config notes.rewriteMode ignore &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    a fresh note\n+    another fresh note\n+EOF\n+\n+test_expect_success 'git notes copy --for-rewrite (append)' '\n+\tgit notes add -f -m\"another fresh note\" HEAD^ &&\n+\tgit config notes.rewriteMode concatenate &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    a fresh note\n+    another fresh note\n+    append 1\n+    append 2\n+EOF\n+\n+test_expect_success 'git notes copy --for-rewrite (append two to one)' '\n+\tgit notes add -f -m\"append 1\" HEAD^ &&\n+\tgit notes add -f -m\"append 2\" HEAD^^ &&\n+\t(echo $(git rev-parse HEAD^) $(git rev-parse HEAD);\n+\techo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+test_expect_success 'git notes copy --for-rewrite (append empty)' '\n+\tgit notes remove HEAD^ &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    replacement note 1\n+EOF\n+\n+test_expect_success 'GIT_NOTES_REWRITE_MODE works' '\n+\tgit notes add -f -m\"replacement note 1\" HEAD^ &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tGIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+cat > expect << EOF\n+commit 37a0d4cba38afef96ba54a3ea567e6dac575700b\n+Author: A U Thor <author@example.com>\n+Date:   Thu Apr 7 15:27:13 2005 -0700\n+\n+    15th\n+\n+Notes (other):\n+    replacement note 2\n+EOF\n+\n+test_expect_success 'GIT_NOTES_REWRITE_REF works' '\n+\tgit config notes.rewriteMode overwrite &&\n+\tgit notes add -f -m\"replacement note 2\" HEAD^ &&\n+\tgit config --unset-all notes.rewriteRef &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tGIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \\\n+\t\tgit notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n+\n+test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '\n+\tgit config notes.rewriteRef refs/notes/other &&\n+\tgit notes add -f -m\"replacement note 3\" HEAD^ &&\n+\techo $(git rev-parse HEAD^) $(git rev-parse HEAD) |\n+\tGIT_NOTES_REWRITE_REF= git notes copy --for-rewrite=foo &&\n+\tgit log -1 > output &&\n+\ttest_cmp expect output\n+'\n test_done\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 3d026b4..c582964 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -56,6 +56,8 @@ unset SHA1_FILE_DIRECTORIES\n unset SHA1_FILE_DIRECTORY\n unset GIT_NOTES_REF\n unset GIT_NOTES_DISPLAY_REF\n+unset GIT_NOTES_REWRITE_REF\n+unset GIT_NOTES_REWRITE_MODE\n GIT_MERGE_VERBOSITY=5\n export GIT_MERGE_VERBOSITY\n export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136671","messageId":"f69e4f9e1a5e9bca056573e24b97e37f251330e8.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 09/13] rebase: support automatic notes copying","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:33Z","receivedAt":"2010-03-12T17:04:33Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Luckily, all the support already happens to be there.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n git-am.sh                     |    5 ++++-\n git-rebase--interactive.sh    |    4 ++++\n git-rebase.sh                 |    1 +\n t/t3400-rebase.sh             |   17 +++++++++++++++++\n t/t3404-rebase-interactive.sh |   24 ++++++++++++++++++++++++\n 5 files changed, 50 insertions(+), 1 deletions(-)\n\ndiff --git a/git-am.sh b/git-am.sh\nindex 9b73e0b..1056075 100755\n--- a/git-am.sh\n+++ b/git-am.sh\n@@ -797,8 +797,11 @@ do\n \tgo_next\n done\n \n-if test -s \"$dotest\"/rewritten && test -x \"$GIT_DIR\"/hooks/post-rewrite; then\n+if test -s \"$dotest\"/rewritten; then\n+    git notes copy --for-rewrite=rebase < \"$dotest\"/rewritten\n+    if test -x \"$GIT_DIR\"/hooks/post-rewrite; then\n \t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$dotest\"/rewritten\n+    fi\n fi\n \n rm -fr \"$dotest\"\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex f18a118..a57f043 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -561,6 +561,10 @@ do_next () {\n \t\ttest ! -f \"$DOTEST\"/verbose ||\n \t\t\tgit diff-tree --stat $(cat \"$DOTEST\"/head)..HEAD\n \t} &&\n+\t{\n+\t\tgit notes copy --for-rewrite=rebase < \"$REWRITTEN_LIST\" ||\n+\t\ttrue # we don't care if this copying failed\n+\t} &&\n \tif test -x \"$GIT_DIR\"/hooks/post-rewrite &&\n \t\ttest -s \"$REWRITTEN_LIST\"; then\n \t\t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$REWRITTEN_LIST\"\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 52f8b9b..e0eb956 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -152,6 +152,7 @@ move_to_original_branch () {\n \n finish_rb_merge () {\n \tmove_to_original_branch\n+\tgit notes copy --for-rewrite=rebase < \"$dotest\"/rewritten\n \tif test -x \"$GIT_DIR\"/hooks/post-rewrite &&\n \t\ttest -s \"$dotest\"/rewritten; then\n \t\t\"$GIT_DIR\"/hooks/post-rewrite rebase < \"$dotest\"/rewritten\ndiff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh\nindex 4314ad2..dbf7dfb 100755\n--- a/t/t3400-rebase.sh\n+++ b/t/t3400-rebase.sh\n@@ -151,4 +151,21 @@ test_expect_success 'Rebase a commit that sprinkles CRs in' '\n \tgit diff --exit-code file-with-cr:CR HEAD:CR\n '\n \n+test_expect_success 'rebase can copy notes' '\n+\tgit config notes.rewrite.rebase true &&\n+\tgit config notes.rewriteRef \"refs/notes/*\" &&\n+\ttest_commit n1 &&\n+\ttest_commit n2 &&\n+\ttest_commit n3 &&\n+\tgit notes add -m\"a note\" n3 &&\n+\tgit rebase --onto n1 n2 &&\n+\ttest \"a note\" = \"$(git notes show HEAD)\"\n+'\n+\n+test_expect_success 'rebase -m can copy notes' '\n+\tgit reset --hard n3 &&\n+\tgit rebase -m --onto n1 n2 &&\n+\ttest \"a note\" = \"$(git notes show HEAD)\"\n+'\n+\n test_done\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 4e35137..19668c2 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -553,4 +553,28 @@ test_expect_success 'reword' '\n \tgit show HEAD~2 | grep \"C changed\"\n '\n \n+test_expect_success 'rebase -i can copy notes' '\n+\tgit config notes.rewrite.rebase true &&\n+\tgit config notes.rewriteRef \"refs/notes/*\" &&\n+\ttest_commit n1 &&\n+\ttest_commit n2 &&\n+\ttest_commit n3 &&\n+\tgit notes add -m\"a note\" n3 &&\n+\tgit rebase --onto n1 n2 &&\n+\ttest \"a note\" = \"$(git notes show HEAD)\"\n+'\n+\n+cat >expect <<EOF\n+an earlier note\n+a note\n+EOF\n+\n+test_expect_success 'rebase -i can copy notes over a fixup' '\n+\tgit reset --hard n3 &&\n+\tgit notes add -m\"an earlier note\" n2 &&\n+\tGIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES=\"1 fixup 2\" git rebase -i n1 &&\n+\tgit notes show > output &&\n+\ttest_cmp expect output\n+'\n+\n test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136674","messageId":"b335e1b2939a465d9d85d9e29e4ef0bef562ca40.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 10/13] commit --amend: copy notes to the new commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:34Z","receivedAt":"2010-03-12T17:04:34Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teaches 'git commit --amend' to copy notes.  The catch is that this\nmust also be guarded by --no-post-rewrite, which we use to prevent\n--amend from copying notes during a rebase -i 'edit'/'reword'.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\n\n builtin/commit.c  |    6 ++++++\n t/t7501-commit.sh |   12 ++++++++++++\n 2 files changed, 18 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 0367412..8dd104e 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1340,6 +1340,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \trerere(0);\n \trun_hook(get_index_file(), \"post-commit\", NULL);\n \tif (amend && !no_post_rewrite) {\n+\t\tstruct notes_rewrite_cfg *cfg;\n+\t\tcfg = init_copy_notes_for_rewrite(\"amend\");\n+\t\tif (cfg) {\n+\t\t\tcopy_note_for_rewrite(cfg, head_sha1, commit_sha1);\n+\t\t\tfinish_copy_notes_for_rewrite(cfg);\n+\t\t}\n \t\trun_rewrite_hook(head_sha1, commit_sha1);\n \t}\n \tif (!quiet)\ndiff --git a/t/t7501-commit.sh b/t/t7501-commit.sh\nindex 7940901..8297cb4 100755\n--- a/t/t7501-commit.sh\n+++ b/t/t7501-commit.sh\n@@ -425,4 +425,16 @@ test_expect_success 'amend using the message from a commit named with tag' '\n \n '\n \n+test_expect_success 'amend can copy notes' '\n+\n+\tgit config notes.rewrite.amend true &&\n+\tgit config notes.rewriteRef \"refs/notes/*\" &&\n+\ttest_commit foo &&\n+\tgit notes add -m\"a note\" &&\n+\ttest_tick &&\n+\tgit commit --amend -m\"new foo\" &&\n+\ttest \"$(git notes show)\" = \"a note\"\n+\n+'\n+\n test_done\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136667","messageId":"64e07051ff37ccc8528064c0dccc75eeeddf4701.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 11/13] notes: add shorthand --ref to override GIT_NOTES_REF","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:35Z","receivedAt":"2010-03-12T17:04:35Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Adds a shorthand option that overrides the GIT_NOTES_REF variable, and\nhence determines the notes tree that will be manipulated.  It also\nDWIMs a refs/notes/ prefix.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n Documentation/git-notes.txt |    5 +++++\n builtin/notes.c             |   16 ++++++++++++++++\n 2 files changed, 21 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 77311bd..02a2baf 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -116,6 +116,11 @@ OPTIONS\n \tLike '-C', but with '-c' the editor is invoked, so that\n \tthe user can further edit the note message.\n \n+--ref <ref>::\n+\tManipulate the notes tree in <ref>.  This overrides both\n+\tGIT_NOTES_REF and the \"core.notesRef\" configuration.  The ref\n+\tis taken to be in `refs/notes/` if it is not qualified.\n+\n Author\n ------\n Written by Johannes Schindelin <johannes.schindelin@gmx.de> and\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 6c2297a..cb30ad0 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -438,6 +438,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \tint given_object = 0, i = 1, retval = 0;\n \tstruct msg_arg msg = { 0, 0, STRBUF_INIT };\n \tconst char *rewrite_cmd = NULL;\n+\tconst char *override_notes_ref = NULL;\n \tstruct option options[] = {\n \t\tOPT_GROUP(\"Notes contents options\"),\n \t\t{ OPTION_CALLBACK, 'm', \"message\", &msg, \"MSG\",\n@@ -455,6 +456,8 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \t\tOPT_GROUP(\"Other options\"),\n \t\tOPT_BOOLEAN('f', \"force\", &force, \"replace existing notes\"),\n \t\tOPT_BOOLEAN(0, \"stdin\", &from_stdin, \"read objects from stdin\"),\n+\t\tOPT_STRING(0, \"ref\", &override_notes_ref, \"notes_ref\",\n+\t\t\t   \"use notes from <notes_ref>\"),\n \t\tOPT_STRING(0, \"for-rewrite\", &rewrite_cmd, \"command\",\n \t\t\t   \"load rewriting config for <command> (implies --stdin)\"),\n \t\tOPT_END()\n@@ -464,6 +467,19 @@ int cmd_notes(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, git_notes_usage, 0);\n \n+\tif (override_notes_ref) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tif (!prefixcmp(override_notes_ref, \"refs/notes/\"))\n+\t\t\t/* we're happy */;\n+\t\telse if (!prefixcmp(override_notes_ref, \"notes/\"))\n+\t\t\tstrbuf_addstr(&sb, \"refs/\");\n+\t\telse\n+\t\t\tstrbuf_addstr(&sb, \"refs/notes/\");\n+\t\tstrbuf_addstr(&sb, override_notes_ref);\n+\t\tsetenv(\"GIT_NOTES_REF\", sb.buf, 1);\n+\t\tstrbuf_release(&sb);\n+\t}\n+\n \tif (argc && !strcmp(argv[0], \"list\"))\n \t\tlist = 1;\n \telse if (argc && !strcmp(argv[0], \"add\"))\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136670","messageId":"1264c49974f992c4f7bc0a5fa72e01a8d1e6d18e.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 12/13] notes: track whether notes_trees were changed at all","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:36Z","receivedAt":"2010-03-12T17:04:36Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, the notes copying is a bit wasteful since it always creates\nnew trees, even if no notes were copied at all.\n\nTeach add_note() and remove_note() to flag the affected notes tree as\nchanged ('dirty').  Then teach builtin/notes.c to use this knowledge\nand avoid committing trees that weren't changed.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n builtin/notes.c |    2 ++\n notes.c         |    3 +++\n notes.h         |    1 +\n 3 files changed, 6 insertions(+), 0 deletions(-)\n\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex cb30ad0..4543d11 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -240,6 +240,8 @@ int commit_notes(struct notes_tree *t, const char *msg)\n \t\tt = &default_notes_tree;\n \tif (!t->initialized || !t->ref || !*t->ref)\n \t\tdie(\"Cannot commit uninitialized/unreferenced notes tree\");\n+\tif (!t->dirty)\n+\t\treturn 0; /* don't have to commit an unchanged tree */\n \n \t/* Prepare commit message and reflog message */\n \tstrbuf_addstr(&buf, \"notes: \"); /* commit message starts at index 7 */\ndiff --git a/notes.c b/notes.c\nindex 66912a3..e72ba02 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -933,6 +933,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,\n \tt->ref = notes_ref ? xstrdup(notes_ref) : NULL;\n \tt->combine_notes = combine_notes;\n \tt->initialized = 1;\n+\tt->dirty = 0;\n \n \tif (flags & NOTES_INIT_EMPTY || !notes_ref ||\n \t    read_ref(notes_ref, object_sha1))\n@@ -1012,6 +1013,7 @@ void add_note(struct notes_tree *t, const unsigned char *object_sha1,\n \tif (!t)\n \t\tt = &default_notes_tree;\n \tassert(t->initialized);\n+\tt->dirty = 1;\n \tif (!combine_notes)\n \t\tcombine_notes = t->combine_notes;\n \tl = (struct leaf_node *) xmalloc(sizeof(struct leaf_node));\n@@ -1027,6 +1029,7 @@ void remove_note(struct notes_tree *t, const unsigned char *object_sha1)\n \tif (!t)\n \t\tt = &default_notes_tree;\n \tassert(t->initialized);\n+\tt->dirty = 1;\n \thashcpy(l.key_sha1, object_sha1);\n \thashclr(l.val_sha1);\n \treturn note_tree_remove(t, t->root, 0, &l);\ndiff --git a/notes.h b/notes.h\nindex 6166927..596e0a5 100644\n--- a/notes.h\n+++ b/notes.h\n@@ -40,6 +40,7 @@\n \tchar *ref;\n \tcombine_notes_fn *combine_notes;\n \tint initialized;\n+\tint dirty;\n } default_notes_tree;\n \n /*\n-- \n1.7.0.2.417.gbc354\n"},{"id":"136669","messageId":"3ca76d6ba7f58880e6260c9ad4893425d1189787.1268413246.git.trast@student.ethz.ch","threadId":"22999","inReplyTo":"cover.1268413246.git.trast@student.ethz.ch","subject":"[PATCH v7 13/13] git-notes(1): add a section about the meaning of history","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2010-03-12T17:04:37Z","receivedAt":"2010-03-12T17:04:37Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"To the displaying code, the only interesting thing about a notes ref\nis that it has a tree of the required format.  However, notes actually\nhave a history since they are recorded as successive commits.\n\nMake a note about the existence of this history in the manpage, but\nkeep some doors open if we want to change the details.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\nAcked-by: Johan Herland <johan@herland.net>\n---\n\n\n Documentation/git-notes.txt |   14 ++++++++++++++\n 1 files changed, 14 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 02a2baf..4e5113b 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -121,6 +121,20 @@ OPTIONS\n \tGIT_NOTES_REF and the \"core.notesRef\" configuration.  The ref\n \tis taken to be in `refs/notes/` if it is not qualified.\n \n+\n+NOTES\n+-----\n+\n+Every notes change creates a new commit at the specified notes ref.\n+You can therefore inspect the history of the notes by invoking, e.g.,\n+`git log -p notes/commits`.\n+\n+Currently the commit message only records which operation triggered\n+the update, and the commit authorship is determined according to the\n+usual rules (see linkgit:git-commit[1]).  These details may change in\n+the future.\n+\n+\n Author\n ------\n Written by Johannes Schindelin <johannes.schindelin@gmx.de> and\n-- \n1.7.0.2.417.gbc354\n"},{"id":"143707","messageId":"1276558805-26573-1-git-send-email-avarab@gmail.com","threadId":"22999","inReplyTo":"e0fbd6edc13d94a097e8e7e3649b9e669f9b4ee3.1268413246.git.trast@student.ethz.ch","subject":"[PATCH] notes: Initialize variable to appease Sun Studio","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-14T23:40:05Z","receivedAt":"2010-06-14T23:40:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Sun Studio 12 Update 1 thinks that *t could be uninitialized,\nostensibly because it doesn't take rewrite_cmd into account in its\nstatic analysis.\n\n    builtin/notes.c: In function `notes_copy_from_stdin':\n    builtin/notes.c:419: warning: 't' might be used uninitialized in this function\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/notes.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex ba8fd17..648033c 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -416,7 +416,7 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct notes_rewrite_cfg *c = NULL;\n-\tstruct notes_tree *t;\n+\tstruct notes_tree *t = NULL;\n \tint ret = 0;\n \n \tif (rewrite_cmd) {\n-- \n1.7.1.251.g92a7\n"},{"id":"143934","messageId":"7vvd9fwrmc.fsf@alter.siamese.dyndns.org","threadId":"22999","inReplyTo":"1276558805-26573-1-git-send-email-avarab@gmail.com","subject":"Re: [PATCH] notes: Initialize variable to appease Sun Studio","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-06-19T04:52:59Z","receivedAt":"2010-06-19T04:52:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Sun Studio 12 Update 1 thinks that *t could be uninitialized,\n> ostensibly because it doesn't take rewrite_cmd into account in its\n> static analysis.\n\nHmm, I am wondering if I should apply this or just tell you to fix your\ncompiler ;-)\n"},{"id":"143937","messageId":"AANLkTimmnlHmt6LTHFKUtJZ7taSF10p4Pkna4CCb1G_J@mail.gmail.com","threadId":"22999","inReplyTo":"7vvd9fwrmc.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] notes: Initialize variable to appease Sun Studio","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-06-19T11:58:59Z","receivedAt":"2010-06-19T11:58:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Sat, Jun 19, 2010 at 04:52, Junio C Hamano <gitster@pobox.com> wrote:\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> Sun Studio 12 Update 1 thinks that *t could be uninitialized,\n>> ostensibly because it doesn't take rewrite_cmd into account in its\n>> static analysis.\n>\n> Hmm, I am wondering if I should apply this or just tell you to fix your\n> compiler ;-)\n\nI just noticed it when testing on Solaris, I don't use it regularly.\n\nIIRC pretty much exactly the same changes were proposed for\ncompatibility with HP/UX a while back, and looking through the source\nit seems a lot of things initialize struct pointers to NULL. Although\nI haven't found any examples yet where they strictly didn't have to.\n"},{"id":"144048","messageId":"4C1FD160.6010700@ramsay1.demon.co.uk","threadId":"22999","inReplyTo":"AANLkTimmnlHmt6LTHFKUtJZ7taSF10p4Pkna4CCb1G_J@mail.gmail.com","subject":"Re: [PATCH] notes: Initialize variable to appease Sun Studio","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsay1.demon.co.uk","sentAt":"2010-06-21T20:53:52Z","receivedAt":"2010-06-21T20:53:52Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"Ævar Arnfjörð Bjarmason wrote:\n> On Sat, Jun 19, 2010 at 04:52, Junio C Hamano <gitster@pobox.com> wrote:\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>>> Sun Studio 12 Update 1 thinks that *t could be uninitialized,\n>>> ostensibly because it doesn't take rewrite_cmd into account in its\n>>> static analysis.\n>> Hmm, I am wondering if I should apply this or just tell you to fix your\n>> compiler ;-)\n> \n> I just noticed it when testing on Solaris, I don't use it regularly.\n\ngcc version 3.4.4 issues exactly the same warning (but gcc versions 4.1.2\nand 4.4.0 don't).\n\nHowever, gcc 3.4.4 also issues a warning for notes.c, thus:\n\n    notes.c: In function `write_each_non_note_until':\n    notes.c:719: warning: 'cmp' might be used uninitialized in this function\n\nThe obvious patch is below, ;-)\n\nATB,\nRamsay Jones\n\n-- >8 --\nFrom: Ramsay Jones <ramsay@ramsay1.demon.co.uk>\nDate: Mon, 21 Jun 2010 19:52:29 +0100\nSubject: [PATCH] notes: Initialise variable to appease gcc\n\ngcc version 3.4.4 thinks that the 'cmp' variable could be used\nwhile uninitialised and complains thus:\n\n    notes.c: In function `write_each_non_note_until':\n    notes.c:719: warning: 'cmp' might be used uninitialized in \\\n        this function\n\nNote that gcc versions 4.1.2 and 4.4.0 do not issue this warning.\n\nSigned-off-by: Ramsay Jones <ramsay@ramsay1.demon.co.uk>\n---\n notes.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/notes.c b/notes.c\nindex 6ee04e7..30d6ded 100644\n--- a/notes.c\n+++ b/notes.c\n@@ -716,7 +716,7 @@ static int write_each_non_note_until(const char *note_path,\n \t\tstruct write_each_note_data *d)\n {\n \tstruct non_note *n = d->next_non_note;\n-\tint cmp, ret;\n+\tint cmp = 0, ret;\n \twhile (n && (!note_path || (cmp = strcmp(n->path, note_path)) <= 0)) {\n \t\tif (note_path && cmp == 0)\n \t\t\t; /* do nothing, prefer note to non-note */\n-- \n1.7.1\n"}]}