зеркало из https://github.com/microsoft/git.git
Merge branch 'mh/notes-allow-reading-treeish'
Some "git notes" operations, e.g. "git log --notes=<note>", should be able to read notes from any tree-ish that is shaped like a notes tree, but the notes infrastructure required that the argument must be a ref under refs/notes/. Loosen it to require a valid ref only when the operation would update the notes (in which case we must have a place to store the updated notes tree, iow, a ref). * mh/notes-allow-reading-treeish: notes: allow treeish expressions as notes ref
This commit is contained in:
Коммит
b4e8e0ed2d
|
@ -43,7 +43,7 @@ people using 80-column terminals.
|
|||
commit may be copied to the output.
|
||||
|
||||
ifndef::git-rev-list[]
|
||||
--notes[=<ref>]::
|
||||
--notes[=<treeish>]::
|
||||
Show the notes (see linkgit:git-notes[1]) that annotate the
|
||||
commit, when showing the commit log message. This is the default
|
||||
for `git log`, `git show` and `git whatchanged` commands when
|
||||
|
@ -54,8 +54,8 @@ By default, the notes shown are from the notes refs listed in the
|
|||
'core.notesRef' and 'notes.displayRef' variables (or corresponding
|
||||
environment overrides). See linkgit:git-config[1] for more details.
|
||||
+
|
||||
With an optional '<ref>' argument, show this notes ref instead of the
|
||||
default notes ref(s). The ref specifies the full refname when it begins
|
||||
With an optional '<treeish>' argument, use the treeish to find the notes
|
||||
to display. The treeish can specify the full refname when it begins
|
||||
with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
|
||||
`refs/notes/` is prefixed to form a full name of the ref.
|
||||
+
|
||||
|
@ -71,7 +71,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
|
|||
"--notes --notes=foo --no-notes --notes=bar" will only show notes
|
||||
from "refs/notes/bar".
|
||||
|
||||
--show-notes[=<ref>]::
|
||||
--show-notes[=<treeish>]::
|
||||
--[no-]standard-notes::
|
||||
These options are deprecated. Use the above --notes/--no-notes
|
||||
options instead.
|
||||
|
|
|
@ -286,7 +286,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
|
|||
if (!c)
|
||||
return 0;
|
||||
} else {
|
||||
init_notes(NULL, NULL, NULL, 0);
|
||||
init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE);
|
||||
t = &default_notes_tree;
|
||||
}
|
||||
|
||||
|
@ -329,15 +329,18 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -360,7 +363,7 @@ static int list(int argc, const char **argv, const char *prefix)
|
|||
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]);
|
||||
|
@ -420,7 +423,7 @@ static int add(int argc, const char **argv, const char *prefix)
|
|||
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) {
|
||||
|
@ -511,7 +514,7 @@ static int copy(int argc, const char **argv, const char *prefix)
|
|||
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) {
|
||||
|
@ -589,7 +592,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
|
|||
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);
|
||||
|
@ -652,7 +655,7 @@ static int show(int argc, const char **argv, const char *prefix)
|
|||
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,7 +812,7 @@ static int merge(int argc, const char **argv, const char *prefix)
|
|||
expand_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)) {
|
||||
|
@ -901,7 +904,7 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
|
|||
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);
|
||||
|
@ -943,7 +946,7 @@ static int prune(int argc, const char **argv, const char *prefix)
|
|||
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) );
|
||||
|
|
|
@ -32,14 +32,14 @@ void notes_cache_init(struct notes_cache *c, const char *name,
|
|||
const char *validity)
|
||||
{
|
||||
struct strbuf ref = STRBUF_INIT;
|
||||
int flags = 0;
|
||||
int flags = NOTES_INIT_WRITABLE;
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
c->validity = xstrdup(validity);
|
||||
|
||||
strbuf_addf(&ref, "refs/notes/%s", name);
|
||||
if (!notes_cache_match_validity(ref.buf, validity))
|
||||
flags = NOTES_INIT_EMPTY;
|
||||
flags |= NOTES_INIT_EMPTY;
|
||||
init_notes(&c->tree, ref.buf, combine_notes_overwrite, flags);
|
||||
strbuf_release(&ref);
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ int notes_cache_write(struct notes_cache *c)
|
|||
unsigned char tree_sha1[20];
|
||||
unsigned char commit_sha1[20];
|
||||
|
||||
if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref)
|
||||
if (!c || !c->tree.initialized || !c->tree.update_ref ||
|
||||
!*c->tree.update_ref)
|
||||
return -1;
|
||||
if (!c->tree.dirty)
|
||||
return 0;
|
||||
|
@ -59,8 +60,8 @@ int notes_cache_write(struct notes_cache *c)
|
|||
if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL,
|
||||
commit_sha1, NULL, NULL) < 0)
|
||||
return -1;
|
||||
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
|
||||
0, UPDATE_REFS_QUIET_ON_ERR) < 0)
|
||||
if (update_ref("update notes cache", c->tree.update_ref, commit_sha1,
|
||||
NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -37,7 +37,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
|
|||
|
||||
if (!t)
|
||||
t = &default_notes_tree;
|
||||
if (!t->initialized || !t->ref || !*t->ref)
|
||||
if (!t->initialized || !t->update_ref || !*t->update_ref)
|
||||
die(_("Cannot commit uninitialized/unreferenced notes tree"));
|
||||
if (!t->dirty)
|
||||
return; /* don't have to commit an unchanged tree */
|
||||
|
@ -48,7 +48,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
|
|||
|
||||
create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
|
||||
strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
|
||||
update_ref(buf.buf, t->ref, commit_sha1, NULL, 0,
|
||||
update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0,
|
||||
UPDATE_REFS_DIE_ON_ERR);
|
||||
|
||||
strbuf_release(&buf);
|
||||
|
@ -148,7 +148,7 @@ struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
|
|||
free(c);
|
||||
return NULL;
|
||||
}
|
||||
c->trees = load_notes_trees(c->refs);
|
||||
c->trees = load_notes_trees(c->refs, NOTES_INIT_WRITABLE);
|
||||
string_list_clear(c->refs, 0);
|
||||
free(c->refs);
|
||||
return c;
|
||||
|
|
11
notes.c
11
notes.c
|
@ -1011,13 +1011,16 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
|
|||
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));
|
||||
|
@ -1027,7 +1030,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
|
|||
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;
|
||||
|
@ -1035,7 +1038,7 @@ struct notes_tree **load_notes_trees(struct string_list *refs)
|
|||
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;
|
||||
|
@ -1071,7 +1074,7 @@ void init_display_notes(struct display_notes_opt *opt)
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
10
notes.h
10
notes.h
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -276,7 +284,7 @@ void format_display_notes(const unsigned char *object_sha1,
|
|||
* 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'.
|
||||
|
|
|
@ -83,6 +83,16 @@ test_expect_success 'edit existing notes' '
|
|||
test_must_fail git notes show HEAD^
|
||||
'
|
||||
|
||||
test_expect_success 'show notes from treeish' '
|
||||
test "b3" = "$(git notes --ref commits^{tree} show)" &&
|
||||
test "b4" = "$(git notes --ref commits@{1} show)"
|
||||
'
|
||||
|
||||
test_expect_success 'cannot edit notes from non-ref' '
|
||||
test_must_fail git notes --ref commits^{tree} edit &&
|
||||
test_must_fail git notes --ref commits@{1} edit
|
||||
'
|
||||
|
||||
test_expect_success 'cannot "git notes add -m" where notes already exists' '
|
||||
test_must_fail git notes add -m "b2" &&
|
||||
test_path_is_missing .git/NOTES_EDITMSG &&
|
||||
|
|
Загрузка…
Ссылка в новой задаче