获取提交的所有注释,包括他们的作者和提交者

Get all notes for a commit including their author and committer

是否有一种简单的方法来检索某个提交的所有注释,包括有关注释作者和注释提交者的信息?

使用 git show --notes=refs/notes/* <commit_hash> 我能够得到所有笔记。但是我没有找到如何使用管道命令获取笔记的作者和提交者。

虽然 git notes 实际上是通过提交某些内容来工作的,但附加到 git notes 提交的作者 and/or 提交者名称被认为没有用,因此不可用。这有一些很好的理由。

让我们快速浏览一下有注释的存储库。在这里,我将使用 GitHub 上的 freebsd 存储库,因为它有 refs/notes/commits(由于 $reasons 我已经映射到 refs/notes/origin/commits)。目前,我们有:

$ git rev-parse refs/notes/origin/commits
af51c6d65d574faa11ab8026398e045e5f584040
$ git show af51c6d65d574faa11ab8026398e045e5f584040 | sed 's/@/ /'
commit af51c6d65d574faa11ab8026398e045e5f584040
Author: hselasky <hselasky FreeBSD.org>
Date:   Mon Aug 14 12:59:14 2017 +0000

    Adding Git note for current refs/heads/stable/10

diff --git a/13/06/ece6bde0e4291eaf08139085990e5f55a622 b/13/06/ece6bde0e4291eaf08139085990e5f55a622
new file mode 100644
index 000000000000..3d1ba58d02fa
--- /dev/null
+++ b/13/06/ece6bde0e4291eaf08139085990e5f55a622
 @ -0,0 +1 @@
+svn path=/stable/10/; revision=322500

看看这个提交中发生了什么:它添加了一个名为 13/06/ece6bde0e4291eaf08139085990e5f55a622 的文件。此文件包含 ID 为 1306ece6bde0e4291eaf08139085990e5f55a622:

的对象的注释
$ git show --decorate 1306ece6bde0e4291eaf08139085990e5f55a622 | sed 's/@/ /'
commit 1306ece6bde0e4291eaf08139085990e5f55a622 (origin/stable/10)
Author: hselasky <hselasky FreeBSD.org>
Date:   Mon Aug 14 12:59:14 2017 +0000

    MFC r314878:
    Add support for constant pointer constructs to READ_ONCE() in the
    LinuxKPI. When the type of the argument is constant the temporary
    variable cannot be assigned after the barrier. Instead assign the
    temporary variable by initialization.

    Approved by:            re (kib)
    Sponsored by:           Mellanox Technologies

Notes (origin/commits):
    svn path=/stable/10/; revision=322500

[diff snipped]

(我将此存储库配置为使用 refs/notes/origin/commits,因此注释会显示在此处。)在这种情况下(这是典型的),注释本身的作者和提交者是 相同的 作为注释所附提交的作者和提交者。

但是,如果我们仔细观察对象 af51c6d65d574faa11ab8026398e045e5f584040,我们会发现它有许多具有这些奇怪名称的文件:

$ git ls-tree af51c6d65d574faa11ab8026398e045e5f584040
040000 tree 598b9e08b0138536da55f5ef55868b2a3a607194    00
040000 tree 5101bb91ab93102057e242b41e19c55fdf3314e7    01
040000 tree 2105ada31d9191d03b50a7ad5c97471c0b531283    02
040000 tree 3e42537c937f0f36cff65b7b19570d2e301a17d2    03
[and so on for 256 names]

如果我们查看 598b9e08b0138536da55f5ef55868b2a3a607194,我们会发现另外 253 个子树,名为 000102、...。最上面的是:

$ git ls-tree 598b9e08b0138536da55f5ef55868b2a3a607194 | head -1
040000 tree 825029e67b3e99c8c9f36c68c26c57b7f4c2edb4    00

825029e67b3e99c8c9f36c68c26c57b7f4c2edb4本身只有7个条目:

$ git ls-tree 825029e67b3e99c8c9f36c68c26c57b7f4c2edb4
100644 blob 47efcb375199433eaff1932ab03ff51ffbc0f4b2    067319a197c517553b4bd00eeca22fbbb7bb
100644 blob a6aa47f5b27bc95afedb4178da68958d10c0665a    252549bd16445f7a9c45ff41b295a8bc653d
100644 blob b892978bc9120fe06997841b48e6cc05027234db    a5b6354a4d39247d26563c2cf96ea644af63
100644 blob b50a07b6e41e178bc374ab25e860a33560929801    b2ecb7b200786a0a17d90036510a2aa4fa86
100644 blob 5725ea47215dd0697cb4510c53b63c49f6285a1b    d86e693087beab26f4d49d7e3eb86a611efb
100644 blob 86754af5a4c9077db1e0bc52952823b3012278b4    e846eae3e7cb94a93496931c64d69682818f
100644 blob 8798a0048bf97bce373e24f0fb0456544c127406    fe19d1123431f6cbad809f708ab744b4d02c

左边的名字是文件名:这些是存储在提交的00树的00子树中的文件.所以这个由 hselasky 制作的 "top level" 注释提交包含数十万个文件(目前为 332,670 个),所有文件的名称都是这些时髦的哈希 ID,分成多个目录,因此没有一个子目录文件太多。

git show 对真正的提交所做的事情,例如 1306ece6bde0e4291eaf08139085990e5f55a622refs/heads/stable/10 的当前提示),是在提交 af51c6d65d574faa11ab8026398e045e5f584040 中查看它是否有一个名称为 1306ece6bde0e4291eaf08139085990e5f55a622 或目录名称以 13 开头的文件。如果它找到一个目录,它会检查其中是否有名称以 06ece6bde0e4291eaf08139085990e5f55a622 开头的文件或名称以 06 开头的目录。如果它找到一个目录,它会去掉接下来的两个字符,依此类推。最终,它要么找到文件,要么找不到。

如果Git确实找到了一个名称与提交哈希匹配的文件,那么该文件包含该提交的注释。

如果Git没有找到这样的文件,那么该提交没有注释。

现在,可以更新 笔记。更新笔记只是意味着我们做了一个新的提交,其内容与之前的笔记提交相同,除了一个文件。假设我们决定更新提交 1306ece6bde0e4291eaf08139085990e5f55a622 的注释。我们发现已经放到13/06/ec...里了,所以我们把notes-commitaf51c6d6...提取到树中,编辑文件13/06/ec...,改note,写文件,写一个新的commit其父提交是 af51c6d6...。我们将这个新提交的新哈希值填充到 refs/notes/origin/commitsrefs/notes/commits 中……现在我们已经替换了注释。

像这样替换注释是我们可以获得 不同 作者和提交者的一种方法,该注释与原始提交 1306ec....

但让我们看一下较早的提交。 stable/10 上的下一个提交是 8f2e6e2e028ef61fd105967432ff2838153110f7。我们通过查看 refs/notes/origin/commits 指向的提交找到它的注释:又是 af51c6...。它有一个名为 8f 的目录吗?为什么是的,确实如此。该目录是否有一个名为 2e 的子目录?果然如此。是否有一个名为 6e2e... 的文件?

$ git rev-parse refs/notes/origin/commits:8f/2e/6e2e028ef61fd105967432ff2838153110f7
46fa8873ffcf4c9e0d0270b02a3e2abcdf10e31e

确实如此,这是我们可以查看的 blob:

$ git cat-file -p 46fa8873ffcf4c9e0d0270b02a3e2abcdf10e31e
svn path=/stable/10/; revision=322462

所以这是提交 8f2e74c5... 的注释。但是我们查看的地方的作者和提交者——refs/notes/origin/commits 又名 af51c6...——是 hselasky,而 8f2e6e2e028ef61fd105967432ff2838153110f7 的作者和提交者是 avos。

要找到 最近更改 8f2e6e2e028ef61fd105967432ff2838153110f7 注释的作者和提交者,我们必须从顶层开始 refs/notes/origin/commits 提交并查看谁触摸了名称看起来像这样的文件。目前,名称本身实际上是 8f/2e/6e2e...;但在更早的某个时候,名称应该是 8f/2e6e2e...,并且随着存储库的不断增长,名称会在某个时候突然更改为 8f/2e/6e/2e...。因此,我们需要一个工具,它不仅可以识别时髦的哈希 ID 作为文件名,而且还知道拆分为包含包含文件的子目录的目录会随着时间的推移而演变。这使得很难找到音符何时更改(如果曾经更改过的话)。

如果注释 从未 更改,它第一次被添加到存储库通常是 "when the commit itself is created" 因此它的作者和提交者将与提交的作者和提交者匹配.所以这通常就足够了。如果它对您的用例来说不够好,您将不得不编写自己的工具。