【问题标题】:git: get the commit-id and the note of a commitgit:获取提交 ID 和提交注释
【发布时间】:2013-08-18 21:26:31
【问题描述】:

我正在编写一个钩子来验证在 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 钩子中访问提交的注释。

有什么建议吗?

【问题讨论】:

  • 可能是个愚蠢的问题,但你不能先推送笔记吗?

标签: git


【解决方案1】:

要添加到torekanswer(这说明了为什么需要push notes 并提交,以使pre-receive 挂钩起作用),这是一个演变。


问题是:

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

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

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


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

参见Mike Hommey (glandium)commit ee76f92(2015 年 10 月 8 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit b4e8e0e,2016 年 1 月 20 日)

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

通过此更改,使用只读注释的操作可以提供任何 可以使用笔记形tree-ish,例如git log --notes=notes@{1}.

(在树上,请参阅gitrevisions

如果你创建了两个笔记(b4,然后是b3):

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

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

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

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

前面的注释确实是b4

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

与:

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

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

【讨论】:

    【解决方案2】:

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

    笔记的工作原理

    存在“附加到”提交的注释(因此可以通过git loggit show 显示)“现在”如果:

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

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

    让我们探索一下寻找笔记的过程。

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

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

    $ 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
    

    对于一组简短的注释,这几乎与我们将在下面看到的相同。如果有很多注释,这会导致更多的trees,这反过来又可以有更多的子树,所以很痛苦。有一个更简单的方法。

    获取笔记

    要查看当前注释是什么(如果有),请使用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(重新格式化/缩进)。 (当然,这是一个更优化的版本。)

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

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

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


    1其实一个笔记可以列出any 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 有效。

    【讨论】:

    • 树状符号可用于阅读笔记! (即将推出的 git 2.8)。见my answer below
    • @VonC:很好。这些新版本的 git 让我很难保持最新状态:-)
    猜你喜欢
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 2014-10-29
    • 2013-06-09
    • 2016-08-20
    • 2015-05-20
    • 2021-10-13
    相关资源
    最近更新 更多