4

我正在编写一个用于验证在 git 日志的注释部分中输入的 url 的钩子。我遍历每个提交以获取该特定提交的注释并对 url 进行字符串比较。如果提交是新提交,则会弹出问题,因为新提交不包含注释。

例子:-

git add sample
git commit -m "added sample"
git notes add -m "sample note" <commitID-of-sample>
git push origin master
git push origin refs/notes/*

上面示例的问题是,首先我推送提交但提交没有注释,因为 git push origin refs/notes/* 是在 master 之后推送的。我基本上想访问 pre-receive 钩子中的提交注释。

有什么建议么?

4

2 回答 2

10

你真的不能按照你展示的方式做到这一点。问题归结为笔记的工作方式。正如mart1n 在评论中建议的那样,您需要先推送笔记,或者同时推送。原因如下:

笔记的工作原理

如果出现以下情况,则存在“附加到”提交的注释(因此可以通过git log和显示git show)“现在”:

  1. 假设这个提交的 SHA1(我们试图找到它的注释)是1234567....
  2. refs/notes/commits存在,并且
  3. 通过指向的提交读取refs/notes/commits,有一个文件名匹配的“文件” 1234567...

注释是具有有趣名称的文件的内容。

让我们探索查找笔记的过程。

背景,使用低级“原始”git 命令

大多数 repo 的最低级别访问命令是git cat-file. 这使您可以查看存储库中任何对象的类型 ( ) 和内容 ( )。这里的sha1部分可以是任何 git 引用名称,只要它解析为那些 40 个字符的十六进制 SHA-1 值之一。notes 的默认引用名称是, 并且(如果存在)它应该始终指向一个对象。因此:git cat-file -t sha1git cat-file -p sha1refs/notes/commitscommit

$ 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'

我们的下一步将是查看tree此处的名称:

$ git cat-file -p 28db2757c2b7c6e4bbfef35e61e8bd7c698626dc

对于一组简短的注释,这产生了几乎与我们将在下面看到的相同的东西。如果有很多注释,这会导致更多tree的 s,而这些 s 又可以有更多的子树,所以这很痛苦。有一个更简单的方法。

获取笔记

要查看当前注释是什么(如果有),请使用git notes list

$ git notes list
b9458a531c3f93bd36af0025d56029ef58cf8d00 5e013711f5d6eb3f643ef562d49a131852aa4aa1
1c716d4d58325651ceecba14ce8974b0ac6d13e9 a546ad9299465c9cf304fecf01d1514337419e2f

“笔记内容”使用每行左侧的 SHA-1,每个笔记内容文件都附加到SHA-1 在右侧的提交1 。让我们使用第一行来看看它是如何工作的:

$ 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]

当然,您可以通过git show 5e0137git log -1 5e0137等方式查看该提交,这也会向您显示注释内容。但是,要查看原始笔记内容,请使用左侧的 SHA-1:

$ git cat-file -p b9458a531c3f93bd36af0025d56029ef58cf8d00
experiment: add a note

this is the text I put in the note

让我们做一个git notes edit 5e0137并更改提交的注释,然后git notes list再次:

$ git notes edit 5e0137
[editor session snipped]
$ git notes list
d87650a968ff684e69175eacde0880595f9f2989 5e013711f5d6eb3f643ef562d49a131852aa4aa1
1c716d4d58325651ceecba14ce8974b0ac6d13e9 a546ad9299465c9cf304fecf01d1514337419e2f

右边的两个“文件名”还是完全一样的,但是左边的第一个SHA1不同。让我们看一下:

$ git cat-file -p d87650a968ff684e69175eacde0880595f9f2989
change some stuff in the note

I edited the note attached to 5e0137.

如果您现在git showgit log等)旧注释附加到的提交,您将获得新注释。实际上,它们的作用是运行git notes list,检查右侧的匹配 ID,如果找到,git cat-file -p则检查左侧的 ID(重新格式化/缩进)。(当然,这是一个更优化的版本。)

这种在列表中查找提交 ID 的机制notes是注释可以更改的原因。

在该“分支”下的添加/更改文件下添加新提交refs/notes/commits(它不是真正的分支,分支以 开头refs/heads/,但它就像一个分支)。新文件具有适用于现有(旧)提交的新注释。那些旧的提交根本没有改变,但是当git log查看git show注释以查看提交 ID 是否在其中时,它们会得到新的、不同的注释来显示相同​​的旧提交。

但是,由命名的提交对象refs/notes/commits现在必须存在,并且必须指向您希望看到的附在您所询问的提交上的注释。如果您push对某个远程存储库进行了一堆新提交,并且尚未push编辑该refs/notes/commits提交,那么在远程存储库上查看的任何内容都看不到您的注释,因为它们根本不存在。先推送笔记,或者同时推送,它们就会在那里找到。


1实际上,注释可以列出任何SHA-1:提交对象、blob 对象、带注释的标记对象,甚至是树对象。您甚至可以输入与 repo 中的任何对象都不对应的 SHA-1 值,如果您愿意,可以输入“分离注释”。我知道这种东西没有用处,但没有技术原因无法完成。[编辑添加:git notes不会这样做;我的意思是你可以用 git 管道命令来做到这一点。不过我没试过。]

怪事

自然,refs/notes/commits它本身就是一个常规的提交树。因此,我们可以“回到过去”并查看最近的笔记之前的样子git notes edit。但是似乎没有“前端”接口。我试过了,例如:

$ git log -1 --notes=refs/notes/commits^ 5e0137

但这根本没有显示任何注释,这看起来很奇怪/损坏,因为--notes=refs/notes/commits有效。

于 2013-08-16T18:31:42.833 回答
3

要添加torek答案(这说明了为什么您需要推送注释和提交以使pre-receive钩子起作用),这是一个演变。


问题是:

自然,refs/notes/commits它本身就是一个常规的提交树。
因此,我们可以“回到过去”并查看最近一次 git 注释编辑之前的注释。但是似乎没有“前端”接口。我试过了,例如:

$ git log -1 --notes=refs/notes/commits^ 5e0137

但这根本没有显示任何注释,这看起来很奇怪/损坏,因为--notes=refs/notes/commits有效。


这将适用commits@{1}于 git 2.8(2016 年 3 月)。

请参阅Mike Hommey ( )的提交 ee76f92(2015 年 10 月 8 日) 。(由Junio C Hamano 合并——提交 b4e8e0e中,2016 年 1 月 20 日)glandium
gitster

一些“ git notes”操作,例如“ git log --notes=<note>”,应该能够从任何形状像笔记树的树状结构中读取笔记但笔记基础设施要求参数必须是 ref 下的引用refs/notes/
仅当操作将更新笔记时才需要一个有效的引用(在这种情况下,我们必须有一个地方来存储更新的笔记树,iow,a ref)。

通过此更改,可以将使用只读笔记的操作提供给任何可以使用的笔记形状的树形例如 git log --notes=notes@{1}。

(关于树形,见gitrevisions

如果您创建两个注释(b4, then b3):

MSG=b4 git notes add
MSG=b3 git notes add

b3然后您可以看到与提交树关联的最新注释 ( ):

test "b3" = "$(git notes --ref commits^{tree} show)"

后缀^后跟括在大括号对中的对象类型名称意味着<rev>递归地取消引用该对象,直到<type>找到该类型的对象。
<rev>^{tree}描述相应的树对象。

之前的注释确实是b4

test "b4" = "$(git notes --ref commits@{1} show)"

和:

<refname>@\{<n>\}, e.g. commits@{1}

一个 ref 后跟@一个包含在大括号对(例如{1}, {15})中的序号规范的后缀,指定该 ref 的第 n 个先前值。
例如commits@{1}是 的直接先验值commits

于 2016-01-21T08:01:17.253 回答