From: Junio C Hamano Date: Wed, 3 Feb 2016 22:15:59 +0000 (-0800) Subject: Merge branch 'jk/notes-merge-from-anywhere' X-Git-Tag: v2.8.0-rc0~84 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1cb3ed308dcfaa6084b8aed075c772aeb9e57243?hp=-c Merge branch 'jk/notes-merge-from-anywhere' "git notes merge" used to limit the source of the merged notes tree to somewhere under refs/notes/ hierarchy, which was too limiting when inventing a workflow to exchange notes with remote repositories using remote-tracking notes trees (located in e.g. refs/remote-notes/ or somesuch). * jk/notes-merge-from-anywhere: notes: allow merging from arbitrary references --- 1cb3ed308dcfaa6084b8aed075c772aeb9e57243 diff --combined builtin/notes.c index 9d54934d6c,b16b8b56a0..ed6f2222f4 --- a/builtin/notes.c +++ b/builtin/notes.c @@@ -286,11 -286,11 +286,11 @@@ static int notes_copy_from_stdin(int fo if (!c) return 0; } else { - init_notes(NULL, NULL, NULL, 0); + init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE); t = &default_notes_tree; } - while (strbuf_getline(&buf, stdin, '\n') != EOF) { + while (strbuf_getline_lf(&buf, stdin) != EOF) { unsigned char from_obj[20], to_obj[20]; struct strbuf **split; int err; @@@ -329,18 -329,15 +329,18 @@@ return ret; } -static struct notes_tree *init_notes_check(const char *subcommand) +static struct notes_tree *init_notes_check(const char *subcommand, + int flags) { struct notes_tree *t; - init_notes(NULL, NULL, NULL, 0); + const char *ref; + init_notes(NULL, NULL, NULL, flags); t = &default_notes_tree; - if (!starts_with(t->ref, "refs/notes/")) + ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref; + if (!starts_with(ref, "refs/notes/")) die("Refusing to %s notes in %s (outside of refs/notes/)", - subcommand, t->ref); + subcommand, ref); return t; } @@@ -363,7 -360,7 +363,7 @@@ static int list(int argc, const char ** usage_with_options(git_notes_list_usage, options); } - t = init_notes_check("list"); + t = init_notes_check("list", 0); if (argc) { if (get_sha1(argv[0], object)) die(_("Failed to resolve '%s' as a valid ref."), argv[0]); @@@ -423,7 -420,7 +423,7 @@@ static int add(int argc, const char **a if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("add"); + t = init_notes_check("add", NOTES_INIT_WRITABLE); note = get_note(t, object); if (note) { @@@ -514,7 -511,7 +514,7 @@@ static int copy(int argc, const char ** if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("copy"); + t = init_notes_check("copy", NOTES_INIT_WRITABLE); note = get_note(t, object); if (note) { @@@ -592,7 -589,7 +592,7 @@@ static int append_edit(int argc, const if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check(argv[0]); + t = init_notes_check(argv[0], NOTES_INIT_WRITABLE); note = get_note(t, object); prepare_note_data(object, &d, edit ? note : NULL); @@@ -655,7 -652,7 +655,7 @@@ static int show(int argc, const char ** if (get_sha1(object_ref, object)) die(_("Failed to resolve '%s' as a valid ref."), object_ref); - t = init_notes_check("show"); + t = init_notes_check("show", 0); note = get_note(t, object); if (!note) @@@ -809,10 -806,10 +809,10 @@@ static int merge(int argc, const char * o.local_ref = default_notes_ref(); strbuf_addstr(&remote_ref, argv[0]); - expand_notes_ref(&remote_ref); + expand_loose_notes_ref(&remote_ref); o.remote_ref = remote_ref.buf; - t = init_notes_check("merge"); + t = init_notes_check("merge", NOTES_INIT_WRITABLE); if (strategy) { if (parse_notes_merge_strategy(strategy, &o.strategy)) { @@@ -904,7 -901,7 +904,7 @@@ static int remove_cmd(int argc, const c argc = parse_options(argc, argv, prefix, options, git_notes_remove_usage, 0); - t = init_notes_check("remove"); + t = init_notes_check("remove", NOTES_INIT_WRITABLE); if (!argc && !from_stdin) { retval = remove_one_note(t, "HEAD", flag); @@@ -946,7 -943,7 +946,7 @@@ static int prune(int argc, const char * usage_with_options(git_notes_prune_usage, options); } - t = init_notes_check("prune"); + t = init_notes_check("prune", NOTES_INIT_WRITABLE); prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) | (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) ); diff --combined notes.c index 358e2fdb74,086cc483e5..c1e5035590 --- a/notes.c +++ b/notes.c @@@ -1011,16 -1011,13 +1011,16 @@@ void init_notes(struct notes_tree *t, c t->first_non_note = NULL; t->prev_non_note = NULL; t->ref = xstrdup_or_null(notes_ref); + t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL; t->combine_notes = combine_notes; t->initialized = 1; t->dirty = 0; if (flags & NOTES_INIT_EMPTY || !notes_ref || - read_ref(notes_ref, object_sha1)) + get_sha1_treeish(notes_ref, object_sha1)) return; + if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_sha1)) + die("Cannot use notes ref %s", notes_ref); if (get_tree_entry(object_sha1, "", sha1, &mode)) die("Failed to read notes tree referenced by %s (%s)", notes_ref, sha1_to_hex(object_sha1)); @@@ -1030,7 -1027,7 +1030,7 @@@ load_subtree(t, &root_tree, t->root, 0); } -struct notes_tree **load_notes_trees(struct string_list *refs) +struct notes_tree **load_notes_trees(struct string_list *refs, int flags) { struct string_list_item *item; int counter = 0; @@@ -1038,7 -1035,7 +1038,7 @@@ trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *)); for_each_string_list_item(item, refs) { struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree)); - init_notes(t, item->string, combine_notes_ignore, 0); + init_notes(t, item->string, combine_notes_ignore, flags); trees[counter++] = t; } trees[counter] = NULL; @@@ -1074,7 -1071,7 +1074,7 @@@ void init_display_notes(struct display_ item->string); } - display_notes_trees = load_notes_trees(&display_notes_refs); + display_notes_trees = load_notes_trees(&display_notes_refs, 0); string_list_clear(&display_notes_refs, 0); } @@@ -1306,3 -1303,13 +1306,13 @@@ void expand_notes_ref(struct strbuf *sb else strbuf_insert(sb, 0, "refs/notes/", 11); } + + void expand_loose_notes_ref(struct strbuf *sb) + { + unsigned char object[20]; + + if (get_sha1(sb->buf, object)) { + /* fallback to expand_notes_ref */ + expand_notes_ref(sb); + } + } diff --combined notes.h index e5d67fd375,431f143788..5345642cfd --- a/notes.h +++ b/notes.h @@@ -44,7 -44,6 +44,7 @@@ extern struct notes_tree struct int_node *root; struct non_note *first_non_note, *prev_non_note; char *ref; + char *update_ref; combine_notes_fn combine_notes; int initialized; int dirty; @@@ -72,13 -71,6 +72,13 @@@ const char *default_notes_ref(void) */ #define NOTES_INIT_EMPTY 1 +/* + * By default, the notes tree is only readable, and the notes ref can be + * any treeish. The notes tree can however be made writable with this flag, + * in which case only strict ref names can be used. + */ +#define NOTES_INIT_WRITABLE 2 + /* * Initialize the given notes_tree with the notes tree structure at the given * ref. If given ref is NULL, the value of the $GIT_NOTES_REF environment @@@ -284,7 -276,7 +284,7 @@@ void format_display_notes(const unsigne * Load the notes tree from each ref listed in 'refs'. The output is * an array of notes_tree*, terminated by a NULL. */ -struct notes_tree **load_notes_trees(struct string_list *refs); +struct notes_tree **load_notes_trees(struct string_list *refs, int flags); /* * Add all refs that match 'glob' to the 'list'. @@@ -302,4 -294,11 +302,11 @@@ void string_list_add_refs_from_colon_se /* Expand inplace a note ref like "foo" or "notes/foo" into "refs/notes/foo" */ void expand_notes_ref(struct strbuf *sb); + /* + * Similar to expand_notes_ref, but will check whether the ref can be located + * via get_sha1 first, and only falls back to expand_notes_ref in the case + * where get_sha1 fails. + */ + void expand_loose_notes_ref(struct strbuf *sb); + #endif