I am writing a hook for validating url\'s which are entered in the notes section of the git log. I loop through each commit to get the note for that particular commit and do
To add to torek's answer (which illustrates why you need to push notes and commits, in order for the pre-receive
hook to work), here is an evolution.
The issue was:
Naturally,
refs/notes/commits
is itself a regular commit tree.
We can therefore "go back in time" and look at what the notes looked like before the most recent git notes edit. But there seems to be no "front end" interface for this. I tried, e.g.:
$ git log -1 --notes=refs/notes/commits^ 5e0137
but that just shows no note at all, which seems weird / broken, since
--notes=refs/notes/commits
works.
That will work with commits@{1}
, in git 2.8 (March 2016).
See commit ee76f92 (08 Oct 2015) by Mike Hommey (glandium).
(Merged by Junio C Hamano -- gitster -- in commit b4e8e0e, 20 Jan 2016)
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 underrefs/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, aref
).With this change, operations that use notes read-only can be fed any notes-shaped tree-ish can be used, e.g. git log --notes=notes@{1}.
(on tree-ish, see gitrevisions)
If you create two notes (b4
, then b3
):
MSG=b4 git notes add
MSG=b3 git notes add
Then you can see the most recent note (b3
) associated to the commits tree:
test "b3" = "$(git notes --ref commits^{tree} show)"
A suffix
^
followed by an object type name enclosed in brace pair means dereference the object at<rev>
recursively until an object of type<type>
is found.
<rev>^{tree}
describes the corresponding tree object.
And the previous note would indeed be b4
:
test "b4" = "$(git notes --ref commits@{1} show)"
With:
<refname>@\{<n>\}, e.g. commits@{1}
A ref followed by the suffix
@
with an ordinal specification enclosed in a brace pair (e.g.{1}
,{15}
) specifies the n-th prior value of that ref.
For examplecommits@{1}
is the immediate prior value ofcommits
.
You literally can't do this the way you showed. The problem boils down to the way notes work. As mart1n suggested in a comment, you need to push the notes either first, or simultaneously. Here's why:
A note "attached to" a commit exists (and thus can be shown by git log
and git show
) "now" if:
1234567...
.refs/notes/commits
exists, andrefs/notes/commits
points-to, there's a "file" whose file-name matches 1234567...
.The note is the content of the file with the funny name.
Let's explore the process of finding a note.
The lowest-level access command for most of the repo is git cat-file
. This lets you look at the type (git cat-file -t sha1
) and contents (git cat-file -p sha1
) of any object within the repository. The sha1 part here can be any git reference name, as long as it resolves to one of those 40-character hexadecimal SHA-1 values. The default ref-name for notes is refs/notes/commits
, and (if it exists) it should always point to a commit
object. Hence:
$ git cat-file -p refs/notes/commits
tree 28db2757c2b7c6e4bbfef35e61e8bd7c698626dc
parent ce97e80bfbdab9bc163ecb93779d071d7ed8c739
author A U Thor <author@example.example> 1376652910 -0600
committer A U Thor <author@example.example> 1376652910 -0600
Notes added by 'git notes edit'
Our next step would be to look at the tree
named here:
$ git cat-file -p 28db2757c2b7c6e4bbfef35e61e8bd7c698626dc
For a short set of notes this produces almost the same thing we'll see below. If there are a lot of notes, this leads to more tree
s, which in turn can have yet more subtrees, so it's a pain. There's a much easier way.
To see what the current notes are (if any), use git notes list
:
$ git notes list
b9458a531c3f93bd36af0025d56029ef58cf8d00 5e013711f5d6eb3f643ef562d49a131852aa4aa1
1c716d4d58325651ceecba14ce8974b0ac6d13e9 a546ad9299465c9cf304fecf01d1514337419e2f
The "note contents" use the SHA-1 on the left of each line, and each note-content-file is attached to the commit1 whose SHA-1 is on the right. Let's use the first line to see how this works:
$ git cat-file -t 5e013711f5d6eb3f643ef562d49a131852aa4aa1
commit
$ git cat-file -p 5e013711f5d6eb3f643ef562d49a131852aa4aa1
tree ead5cc295ae64c9186f392b80ca4ed10888f20d9
parent 309b36c8166f5ff330a6e8a0a674ed161d45b5f4
author ...[line snipped]
committer ...[line snipped]
add ast ... [rest snipped]
You can, of course, git show 5e0137
or git log -1 5e0137
, etc., to see that commit, which will also show you the note contents. To see just the raw note contents, though, use the SHA-1 on the left:
$ git cat-file -p b9458a531c3f93bd36af0025d56029ef58cf8d00
experiment: add a note
this is the text I put in the note
Let's do a git notes edit 5e0137
and change the note for the commit, and then git notes list
again:
$ git notes edit 5e0137
[editor session snipped]
$ git notes list
d87650a968ff684e69175eacde0880595f9f2989 5e013711f5d6eb3f643ef562d49a131852aa4aa1
1c716d4d58325651ceecba14ce8974b0ac6d13e9 a546ad9299465c9cf304fecf01d1514337419e2f
The two "file names" on the right are still exactly the same, but on the left, the first SHA1 is different. Let's look at it:
$ git cat-file -p d87650a968ff684e69175eacde0880595f9f2989
change some stuff in the note
I edited the note attached to 5e0137.
If you now git show
(git log
, etc) the commit the old note was attached to, you get the new note. What these do, in effect, is to run git notes list
, check on the right for a matching ID, and if found, git cat-file -p
the ID on the left (reformatted / indented). (Well, a more optimized version of that, of course.)
notes
list, is why notes can change.Adding a new commit under refs/notes/commits
adds/changes files under that "branch" (it's not really a branch, branches start with refs/heads/
, but it's otherwise just like a branch). The new files have new notes that apply to existing (old) commits. Those old commits are not changed at all, but when git log
and git show
look at the notes to see if the commit-ID is in there, they get new, different notes to show for the same old commit.
The commit object named by refs/notes/commits
must exist by now, though, and must point to the notes you want to see attached to the commit(s) you're asking about. If you push
a bunch of new commits to some remote-repo, and have not push
ed the refs/notes/commits
commit yet, anything looking on the remote-repo can't see your notes, as they simply are not there. Push the notes first, or at the same time, and they will be there to find.
1Actually a note can list any SHA-1: a commit object, a blob object, an annotated tag object, or even a tree object. You could even put in SHA-1 values that do not correspond to any object in the repo, a "detached note" if you will. I know of no uses for such a thing, but there's no technical reason it could not be done. [Edit to add: git notes
won't do this; I mean you could do it with git plumbing commands. I haven't tried it though.]
Naturally, refs/notes/commits
is itself a regular commit tree. We can therefore "go back in time" and look at what the notes looked like before the most recent git notes edit
. But there seems to be no "front end" interface for this. I tried, e.g.:
$ git log -1 --notes=refs/notes/commits^ 5e0137
but that just shows no note at all, which seems weird / broken, since --notes=refs/notes/commits
works.