GIT:获取通过提交添加到存储库的 blob 的所有 git 对象哈希

GIT: Get all git object hashes of blobs added to the repository by a commit

是否可以使用 git 命令行工具获取已通过给定提交哈希添加到存储库的所有 git blob 对象哈希的列表?

我已经尝试使用 git 管道工具 git-diff-tree 将其存档。也许这是错误的方法。以下是迄今为止我能得到的最好结果。但是(很长的手册页)文档无助于找出必须如何解释输出的准确程度。

$ git diff-tree --no-commit-id 2b53d04dbb7cd35d030ddc59b13c0836a87daeb7 
:100644 100644 03f15b592c7d776da37e3d4372c215b14ff8820f 6e0ed0b1ed56e9a35a3be52a9de261c8ffcccae8 M      file1.ts
:100644 100644 b5083bdb9c31005ebd16835a0f49dc848d3f387a 4b7f9e6624a66fec0510d76823303017e224c9d7 M      file2.ts
:100644 100644 368d64862e6aa2a0110f201c8a5193d929e2956d 0e51626a9866a8a3896489f497fbd745a5f4a9f2 M      file3.ts
:040000 040000 c332b1e576af0dbb93cc875106bc06c3de6b74c8 f7f3478a9b0eaac85719699d97e323563a1b102b M      some_folder

第一个和第二个 git 对象 blob 散列是否分别显示修改文件的旧对象和新对象?在最坏的情况下,我可以通过解析输出来获取该信息。

我的主要目标是找到一个如下所示的命令行:

$ git <command> <option1> <option2> 368d64862e6aa2a0110f201c8a5193d929e2956d 
6e0ed0b1ed56e9a35a3be52a9de261c8ffcccae8 
4b7f9e6624a66fec0510d76823303017e224c9d7 
0e51626a9866a8a3896489f497fbd745a5f4a9f2 

在下面编辑以回应@torek

为了回应@torek 的回答,我想更清楚地说明我的意图是什么,因为他完全正确地指出新的不一定是新的。

我计划使用 git rev-list --reverse <branch> 获取该分支上所有提交的列表(按提交顺序)。然后我想按此顺序访问每个提交,并收集每个提交在该分支上首先看到的 blob 哈希值。

最终结果应该如下所示:

C:368d64862e6aa2a0110f201c8a5193d929e2956d
B:03f15b592c7d776da37e3d4372c215b14ff8820f
B:4b7f9e6624a66fec0510d76823303017e224c9d7
B:c332b1e576af0dbb93cc875106bc06c3de6b74c8
C:5521a02ce1bc4f147d0fa39a178512476764dd66 
B:e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e
B:adc83b19e793491b1c6ea0fd8b46cd9f32e592fc
C:a3db5c13ff90a36963278c6a39e4ee3c22e2a436
B:4888920a568af4ef2d2f4866e75b4061112a39ea
.
.
.

C: 提交 B: 斑点

如果这不容易做到,那么做两遍就可以了。由于您指出的原因,在第一遍中,可以在不同的提交中多次提及 blob:

然后我可以通过 awk '!x[[=19=]]++' 进行第二次管道传输文件,这将删除所有重复项。这不是很有效,但会得到我想要的结果。

我希望我现在表达了我的意图。有什么想法吗?

Is it possible to get a list of all git object hashes of blobs which have been added to the repository by a given commit hash using the git command line tools?

是 and/or 否:您必须准确定义 添加到存储库 .

的意思

例如,假设我从一个完全空的存储库开始:

$ mkdir foo && cd foo && git init
Initialized empty Git repository in ...

现在我创建 README.mdgit add 它并提交:

$ echo for testing > README.md
$ git add README.md
$ git commit -m initial
[master (root-commit) 19278e9] initial
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

README.md 是一个 blob,它的哈希 ID 是:

$ git rev-parse HEAD:README.md
43b18adf702be62761e3affd85c4c3ee5c396be7

稍后,我写一个新文件:

$ echo for testing > newfile.txt
$ git add newfile.txt
$ git commit -m 'add new file'
[master 5521a02] add new file
 1 file changed, 1 insertion(+)
 create mode 100644 newfile.txt

如果我们查看此提交,我们将看到新文件。如果我们用 git show --raw 查看它,我们将以 git diff-tree 格式看到它:

$ git show --raw
commit 5521a02ce1bc4f147d0fa39a178512476764dd66 (HEAD -> master)
Author: Chris Torek <chris.torek gmail.com>
Date:   Fri Oct 18 14:10:55 2019 -0700

    add new file

:000000 100644 0000000 43b18ad A        newfile.txt

这似乎是 一个已添加到存储库的 blob,但是等等,43b18ad:

有一些非常熟悉的东西
$ git rev-parse HEAD:newfile.txt
43b18adf702be62761e3affd85c4c3ee5c396be7

是的,那是README.md相同的哈希ID:

$ git ls-tree -r HEAD
100644 blob 43b18adf702be62761e3affd85c4c3ee5c396be7    README.md
100644 blob 43b18adf702be62761e3affd85c4c3ee5c396be7    newfile.txt

它是一个 blob,但有两个文件。真的是新增的吗?

如果您对上述问题的回答是 "yes, it's new, even though it's old",那么第二个问题可能就得到了解答。如果您的答案是 "no, it's not new",重新引入在上一次提交中删除的 blob 的提交怎么样?或者,如果两个提交 IJ 在两个分支上并行进行:

          I   <-- br1
         /
...--G--H
         \
          J   <-- br2

两者都引入了相同的 blob,哪一个实际上将其添加为全新的,哪一个只是复制了另一个?

一般来说,如果你想要全新的,你必须遍历整个提交图,检查每个提交的树(参见git ls-tree -r),并且select 提交首先引入一个 blob 对象 ID,该 ID 不存在于较早的(父级 and/or 日期和时间)提交对象中。如果您想要 "newly added as a new file in this commit",检查提交及其父项,可能使用 git diff-tree 或类似的。请注意,一个全新的 文件 在其父级中具有全零模式,并且状态字母为 A (已添加),而从其父级修改的文件具有M(已修改)的状态字母和两个非零散列。名义上删除的文件——存在于父文件中但不再存在于子文件中的文件——的状态字母为 D(已删除)。如果启用重命名检测,您将获得 R status-es 和相似性索引值;您可能想要禁用它,或者至少将相似性测试强制为 100%。