1

假设我知道一个文件已被重命名(重命名可以通过重命名文件名或将文件移动到另一个目录来实现)到特定的提交中。git show --summary <sha>显示提交中此类重命名的所有实例。但是,git 只标记了新旧文件路径之间的区别。下面是两个例子——

rename xbmc/interfaces/{ => builtins}/Builtins.cpp (100%)
rename xbmc/cores/AudioEngine/Engines/ActiveAE/{ActiveAEResample.cpp => ActiveAEResampleFFMPEG.cpp} (100%)

如何在重命名之前和之后有效地解析完整的文件路径,因为它可以通过多种方式完成?或者是否有另一个 git 命令以更简单的方式显示此信息?

4

1 回答 1

3

TL;博士

鉴于您知道提交哈希<hash>,您可能想要:

git diff-tree --find-renames -r --name-status --diff-filter=R --no-commit-id <hash>

或与-z添加相同。您可能还想指定合并的(第一个)父级,在这种情况下,这--no-commit-id是不必要的。

有几种方法可以做到这一点,具体取决于您想要输出的各种详细信息。关键是从可预测的管道命令开始。在 Git 中,管道命令本质上是为其他程序设计的,因此它具有机器可读、可预测、可靠的输出格式。您现在得到的是 的输出git diff --summary,并且git diff是一个瓷器命令,旨在具有人类可读的输出:

$ git diff --summary 99177b34db^ 99177b34db
 rename contrib/hooks/multimail/{README => README.rst} (95%)

git show --summary在其他操作结束时运行。

对于机械可解析的输出,我们可以切换到git diff-tree. 如果我们想要每个修改文件的名称和状态,我们可以要求:

$ git diff-tree --name-status -r 99177b34db^ 99177b34db
M       contrib/hooks/multimail/CHANGES
M       contrib/hooks/multimail/CONTRIBUTING.rst
D       contrib/hooks/multimail/README
M       contrib/hooks/multimail/README.Git
A       contrib/hooks/multimail/README.rst
M       contrib/hooks/multimail/doc/gitolite.rst
M       contrib/hooks/multimail/git_multimail.py
M       contrib/hooks/multimail/migrate-mailhook-config
M       contrib/hooks/multimail/post-receive.example

我们可以立即看到这里有一个缺陷:我们没有观察到重命名。这是因为在 commit 99177b34db( 99177b34db^) 的(第一个也是唯一的)父级和 commit99177b34db本身之间,没有实际的重命名。这两个快照只有两组文件。我们看到的重命名是一种猜测git diff --summary为了指示 Git 在使用时进行相同的猜测,git diff-tree我们必须添加--find-renames- 这让我们可以选择算作重命名的相似度阈值,但默认为与摘要相同的 50%:

$ git diff-tree --find-renames --name-status -r 99177b34db^ 99177b34db
M       contrib/hooks/multimail/CHANGES
M       contrib/hooks/multimail/CONTRIBUTING.rst
M       contrib/hooks/multimail/README.Git
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst
M       contrib/hooks/multimail/doc/gitolite.rst
M       contrib/hooks/multimail/git_multimail.py
M       contrib/hooks/multimail/migrate-mailhook-config
M       contrib/hooks/multimail/post-receive.example

R095行包含我们想要的内容:检测到的重命名、相似度值(在本例中为 95%)以及两个文件名,在本例中由制表符分隔。

我们可以使用--diff-filter缩小输出以包含重命名:

$ git diff-tree --find-renames --name-status -r --diff-filter=R 99177b34db^ 99177b34db
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

请注意,我们可以git diff-tree只使用一个提交哈希来运行。当提交是普通(非合并)提交时,这很有效:

$ git diff-tree --find-renames --name-status -r --diff-filter=R 99177b34db
99177b34db1d473e8f90544cf0bf83f47308e9ad
R095    contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

但是,现在我们在输出中获得了完整的哈希 ID。添加--no-commit-id告诉它不包含哈希 ID。

如果我们指定的提交是合并提交,它的工作方式也会有所不同。我不会在这里说明这一点,因为我没有方便的合并来查看这种方式,但请密切注意文档 对合并的差异格式的描述以及关于告诉我们的组合格式的单独注释有时我们根本看不到某些文件。

Dropping--name-status为我们提供了另一种格式,它更长,有时更有用:

$ git diff-tree --find-renames -r --diff-filter=R 99177b34db^ 99177b34db
:100644 100644 5105373aea044f2d8fde0c4fd927c8c492d02585 7c0fc4a6ef00362dcff476497a6045a420562d05 R095   contrib/hooks/multimail/README  contrib/hooks/multimail/README.rst

在这里,我们得到了两个文件的 blob 哈希,100644它们前面有两个模式 ( ),都以一个冒号为前缀:。如果我们得到合并提交的输出,细节将会改变。

在所有这些情况下,您都可以添加该-z选项。这将输出更改为更加机器可读(但非常人类不可读):每个输出记录的各个部分都有 ASCII NUL (0x00) 字节来分隔它们。文档中也描述了此选项,以及在使用-z.

于 2019-04-23T15:46:20.567 回答