Skip to content

Commit b4e8e0e

Browse files
committed
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
2 parents fc10eb5 + ee76f92 commit b4e8e0e

File tree

7 files changed

+55
-30
lines changed

7 files changed

+55
-30
lines changed

Documentation/pretty-options.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ people using 80-column terminals.
4343
commit may be copied to the output.
4444

4545
ifndef::git-rev-list[]
46-
--notes[=<ref>]::
46+
--notes[=<treeish>]::
4747
Show the notes (see linkgit:git-notes[1]) that annotate the
4848
commit, when showing the commit log message. This is the default
4949
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
5454
'core.notesRef' and 'notes.displayRef' variables (or corresponding
5555
environment overrides). See linkgit:git-config[1] for more details.
5656
+
57-
With an optional '<ref>' argument, show this notes ref instead of the
58-
default notes ref(s). The ref specifies the full refname when it begins
57+
With an optional '<treeish>' argument, use the treeish to find the notes
58+
to display. The treeish can specify the full refname when it begins
5959
with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
6060
`refs/notes/` is prefixed to form a full name of the ref.
6161
+
@@ -71,7 +71,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
7171
"--notes --notes=foo --no-notes --notes=bar" will only show notes
7272
from "refs/notes/bar".
7373

74-
--show-notes[=<ref>]::
74+
--show-notes[=<treeish>]::
7575
--[no-]standard-notes::
7676
These options are deprecated. Use the above --notes/--no-notes
7777
options instead.

builtin/notes.c

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
286286
if (!c)
287287
return 0;
288288
} else {
289-
init_notes(NULL, NULL, NULL, 0);
289+
init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE);
290290
t = &default_notes_tree;
291291
}
292292

@@ -329,15 +329,18 @@ static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
329329
return ret;
330330
}
331331

332-
static struct notes_tree *init_notes_check(const char *subcommand)
332+
static struct notes_tree *init_notes_check(const char *subcommand,
333+
int flags)
333334
{
334335
struct notes_tree *t;
335-
init_notes(NULL, NULL, NULL, 0);
336+
const char *ref;
337+
init_notes(NULL, NULL, NULL, flags);
336338
t = &default_notes_tree;
337339

338-
if (!starts_with(t->ref, "refs/notes/"))
340+
ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref;
341+
if (!starts_with(ref, "refs/notes/"))
339342
die("Refusing to %s notes in %s (outside of refs/notes/)",
340-
subcommand, t->ref);
343+
subcommand, ref);
341344
return t;
342345
}
343346

@@ -360,7 +363,7 @@ static int list(int argc, const char **argv, const char *prefix)
360363
usage_with_options(git_notes_list_usage, options);
361364
}
362365

363-
t = init_notes_check("list");
366+
t = init_notes_check("list", 0);
364367
if (argc) {
365368
if (get_sha1(argv[0], object))
366369
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)
420423
if (get_sha1(object_ref, object))
421424
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
422425

423-
t = init_notes_check("add");
426+
t = init_notes_check("add", NOTES_INIT_WRITABLE);
424427
note = get_note(t, object);
425428

426429
if (note) {
@@ -511,7 +514,7 @@ static int copy(int argc, const char **argv, const char *prefix)
511514
if (get_sha1(object_ref, object))
512515
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
513516

514-
t = init_notes_check("copy");
517+
t = init_notes_check("copy", NOTES_INIT_WRITABLE);
515518
note = get_note(t, object);
516519

517520
if (note) {
@@ -589,7 +592,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
589592
if (get_sha1(object_ref, object))
590593
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
591594

592-
t = init_notes_check(argv[0]);
595+
t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
593596
note = get_note(t, object);
594597

595598
prepare_note_data(object, &d, edit ? note : NULL);
@@ -652,7 +655,7 @@ static int show(int argc, const char **argv, const char *prefix)
652655
if (get_sha1(object_ref, object))
653656
die(_("Failed to resolve '%s' as a valid ref."), object_ref);
654657

655-
t = init_notes_check("show");
658+
t = init_notes_check("show", 0);
656659
note = get_note(t, object);
657660

658661
if (!note)
@@ -809,7 +812,7 @@ static int merge(int argc, const char **argv, const char *prefix)
809812
expand_notes_ref(&remote_ref);
810813
o.remote_ref = remote_ref.buf;
811814

812-
t = init_notes_check("merge");
815+
t = init_notes_check("merge", NOTES_INIT_WRITABLE);
813816

814817
if (strategy) {
815818
if (parse_notes_merge_strategy(strategy, &o.strategy)) {
@@ -901,7 +904,7 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
901904
argc = parse_options(argc, argv, prefix, options,
902905
git_notes_remove_usage, 0);
903906

904-
t = init_notes_check("remove");
907+
t = init_notes_check("remove", NOTES_INIT_WRITABLE);
905908

906909
if (!argc && !from_stdin) {
907910
retval = remove_one_note(t, "HEAD", flag);
@@ -943,7 +946,7 @@ static int prune(int argc, const char **argv, const char *prefix)
943946
usage_with_options(git_notes_prune_usage, options);
944947
}
945948

946-
t = init_notes_check("prune");
949+
t = init_notes_check("prune", NOTES_INIT_WRITABLE);
947950

948951
prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) |
949952
(show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) );

notes-cache.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ void notes_cache_init(struct notes_cache *c, const char *name,
3232
const char *validity)
3333
{
3434
struct strbuf ref = STRBUF_INIT;
35-
int flags = 0;
35+
int flags = NOTES_INIT_WRITABLE;
3636

3737
memset(c, 0, sizeof(*c));
3838
c->validity = xstrdup(validity);
3939

4040
strbuf_addf(&ref, "refs/notes/%s", name);
4141
if (!notes_cache_match_validity(ref.buf, validity))
42-
flags = NOTES_INIT_EMPTY;
42+
flags |= NOTES_INIT_EMPTY;
4343
init_notes(&c->tree, ref.buf, combine_notes_overwrite, flags);
4444
strbuf_release(&ref);
4545
}
@@ -49,7 +49,8 @@ int notes_cache_write(struct notes_cache *c)
4949
unsigned char tree_sha1[20];
5050
unsigned char commit_sha1[20];
5151

52-
if (!c || !c->tree.initialized || !c->tree.ref || !*c->tree.ref)
52+
if (!c || !c->tree.initialized || !c->tree.update_ref ||
53+
!*c->tree.update_ref)
5354
return -1;
5455
if (!c->tree.dirty)
5556
return 0;
@@ -59,8 +60,8 @@ int notes_cache_write(struct notes_cache *c)
5960
if (commit_tree(c->validity, strlen(c->validity), tree_sha1, NULL,
6061
commit_sha1, NULL, NULL) < 0)
6162
return -1;
62-
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
63-
0, UPDATE_REFS_QUIET_ON_ERR) < 0)
63+
if (update_ref("update notes cache", c->tree.update_ref, commit_sha1,
64+
NULL, 0, UPDATE_REFS_QUIET_ON_ERR) < 0)
6465
return -1;
6566

6667
return 0;

notes-utils.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
3737

3838
if (!t)
3939
t = &default_notes_tree;
40-
if (!t->initialized || !t->ref || !*t->ref)
40+
if (!t->initialized || !t->update_ref || !*t->update_ref)
4141
die(_("Cannot commit uninitialized/unreferenced notes tree"));
4242
if (!t->dirty)
4343
return; /* don't have to commit an unchanged tree */
@@ -48,7 +48,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
4848

4949
create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
5050
strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
51-
update_ref(buf.buf, t->ref, commit_sha1, NULL, 0,
51+
update_ref(buf.buf, t->update_ref, commit_sha1, NULL, 0,
5252
UPDATE_REFS_DIE_ON_ERR);
5353

5454
strbuf_release(&buf);
@@ -148,7 +148,7 @@ struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd)
148148
free(c);
149149
return NULL;
150150
}
151-
c->trees = load_notes_trees(c->refs);
151+
c->trees = load_notes_trees(c->refs, NOTES_INIT_WRITABLE);
152152
string_list_clear(c->refs, 0);
153153
free(c->refs);
154154
return c;

notes.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,13 +1011,16 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
10111011
t->first_non_note = NULL;
10121012
t->prev_non_note = NULL;
10131013
t->ref = xstrdup_or_null(notes_ref);
1014+
t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
10141015
t->combine_notes = combine_notes;
10151016
t->initialized = 1;
10161017
t->dirty = 0;
10171018

10181019
if (flags & NOTES_INIT_EMPTY || !notes_ref ||
1019-
read_ref(notes_ref, object_sha1))
1020+
get_sha1_treeish(notes_ref, object_sha1))
10201021
return;
1022+
if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, object_sha1))
1023+
die("Cannot use notes ref %s", notes_ref);
10211024
if (get_tree_entry(object_sha1, "", sha1, &mode))
10221025
die("Failed to read notes tree referenced by %s (%s)",
10231026
notes_ref, sha1_to_hex(object_sha1));
@@ -1027,15 +1030,15 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
10271030
load_subtree(t, &root_tree, t->root, 0);
10281031
}
10291032

1030-
struct notes_tree **load_notes_trees(struct string_list *refs)
1033+
struct notes_tree **load_notes_trees(struct string_list *refs, int flags)
10311034
{
10321035
struct string_list_item *item;
10331036
int counter = 0;
10341037
struct notes_tree **trees;
10351038
trees = xmalloc((refs->nr+1) * sizeof(struct notes_tree *));
10361039
for_each_string_list_item(item, refs) {
10371040
struct notes_tree *t = xcalloc(1, sizeof(struct notes_tree));
1038-
init_notes(t, item->string, combine_notes_ignore, 0);
1041+
init_notes(t, item->string, combine_notes_ignore, flags);
10391042
trees[counter++] = t;
10401043
}
10411044
trees[counter] = NULL;
@@ -1071,7 +1074,7 @@ void init_display_notes(struct display_notes_opt *opt)
10711074
item->string);
10721075
}
10731076

1074-
display_notes_trees = load_notes_trees(&display_notes_refs);
1077+
display_notes_trees = load_notes_trees(&display_notes_refs, 0);
10751078
string_list_clear(&display_notes_refs, 0);
10761079
}
10771080

notes.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ extern struct notes_tree {
4444
struct int_node *root;
4545
struct non_note *first_non_note, *prev_non_note;
4646
char *ref;
47+
char *update_ref;
4748
combine_notes_fn combine_notes;
4849
int initialized;
4950
int dirty;
@@ -71,6 +72,13 @@ const char *default_notes_ref(void);
7172
*/
7273
#define NOTES_INIT_EMPTY 1
7374

75+
/*
76+
* By default, the notes tree is only readable, and the notes ref can be
77+
* any treeish. The notes tree can however be made writable with this flag,
78+
* in which case only strict ref names can be used.
79+
*/
80+
#define NOTES_INIT_WRITABLE 2
81+
7482
/*
7583
* Initialize the given notes_tree with the notes tree structure at the given
7684
* 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,
276284
* Load the notes tree from each ref listed in 'refs'. The output is
277285
* an array of notes_tree*, terminated by a NULL.
278286
*/
279-
struct notes_tree **load_notes_trees(struct string_list *refs);
287+
struct notes_tree **load_notes_trees(struct string_list *refs, int flags);
280288

281289
/*
282290
* Add all refs that match 'glob' to the 'list'.

t/t3301-notes.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ test_expect_success 'edit existing notes' '
8383
test_must_fail git notes show HEAD^
8484
'
8585

86+
test_expect_success 'show notes from treeish' '
87+
test "b3" = "$(git notes --ref commits^{tree} show)" &&
88+
test "b4" = "$(git notes --ref commits@{1} show)"
89+
'
90+
91+
test_expect_success 'cannot edit notes from non-ref' '
92+
test_must_fail git notes --ref commits^{tree} edit &&
93+
test_must_fail git notes --ref commits@{1} edit
94+
'
95+
8696
test_expect_success 'cannot "git notes add -m" where notes already exists' '
8797
test_must_fail git notes add -m "b2" &&
8898
test_path_is_missing .git/NOTES_EDITMSG &&

0 commit comments

Comments
 (0)