在git log中重命名文件之前和之后获取完整的文件路径

时间:2019-04-23 04:22:15

标签: git git-show

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

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

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

1 个答案:

答案 0 :(得分:2)

TL; DR

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

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

或添加了-z的相同内容。您可能还需要指定合并的第一个父项,在这种情况下,--no-commit-id是不必要的。

有多种方法可以执行此操作,这取决于要输出的内容的各种详细信息。关键是从可预测的 plumbing 命令开始。在Git中,管道命令实际上是设计用于其他程序的命令,因此它具有机器可读,可预测,可靠的输出格式。您现在得到的是git diff --summary的输出,而git diff porcelain 命令,旨在提供易于理解的输出:

$ 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

我们可以立即看到这里存在一个缺陷:我们没有观察到重命名。这是因为在提交99177b34db99177b34db^)的(第一个和唯一的)父级与提交99177b34db本身之间,没有实际的重命名。这两个快照只有两组文件。我们看到的重命名是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。

如果我们指定的提交是合并提交,它也可以不同地工作。我不会在这里说明这一点,因为我没有方便的合并方式来查看这种方式,但是请密切注意the documentation's description of the diff format for merges和单独的note about the combined format我们有时候有时候根本看不到任何文件。

拖放--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)字节来分隔它们。此选项也是described in the documentation,还有一些有关不使用-z时对路径名进行哪些修改的详细信息。