正如在CodeWizard 的回答中一样,您可以使用“用户友好”(或瓷器)命令git diff
而不是git diff-tree
Git 所谓的管道命令,用于脚本中。但是,您应该知道这意味着什么。
由于瓷器命令是为人类设计的,它们试图以人类可读的方式呈现事物。这意味着他们遵守特定人在各种配置文件中为他/她自己设置的任何设置。这包括diff.renames
和diff.renameLimit
配置。他们也可能会修改他们的输出,使眼球更容易处理,但计算机程序更难处理。最糟糕的是,如果人们似乎更喜欢某些默认值,他们可能会将输出从一个 Git 版本更改为另一个版本。
由于脚本不适用于上述情况,它们以可预测的方式运行,输出不会改变,也不依赖于配置项。这样,无论您提出什么要求,您都会得到:您将以可靠的形式获得可靠的输出,因此,如果您编写自己的可靠代码,它不仅适用于今天,在一种情况下;在所有可能的情况下,它将在未来继续工作。1
最后,这意味着如果您使用git diff-tree
并设置正确的标志,您将获得更可靠的输出。如果您使用git diff
,您的重命名检测取决于:
正如您所发现的,rename-detection 的输出是两个路径名,这不是您可以通过管道传输到存档器的内容。存档者通常会遇到文件删除问题(这可能是存档和备份/快照之间的一个典型区别;请注意,这两者都与版本控制有关)。
如果您的目标是所有文件的一种联合 - 即,如果差异表明A
添加了一个名为的D
文件,删除了一个名为的文件,并且R
通过重命名旧名称来创建文件O
(并且可能还修改它:注意 Git 的相似性索引字母后面的数字R
),那么您希望收集文件A
,忽略文件D
,并R
在忽略文件的同时收集文件O
- 那么,您想要的是首先不检测重命名!如果您未检测到重命名git diff-tree
(默认情况下不会检测到),则相同的差异将显示为:添加文件A
、删除文件D
、删除文件O
和添加文件R
. 因此,包含和排除git diff-tree
的 a就足够了。不太清楚如何处理类型更改:例如,从普通文件到符号链接,或者从文件到子存储库提交哈希(Git 称之为gitlink条目,用于子模块)。diff-filter
AM
D
T
同样,您不想启用复制检测:C
状态,如R
,表示相似性索引和一对路径名。如果您将其禁用,您只需将新路径名作为A
dded 文件获取。
即使你做了所有这些,你仍然会陷入陷阱。假设提交哈希C1有一个名为 的文件problem
,而(可能是稍后的)提交哈希C2有两个名为problem/A
和的文件problem/B
。这意味着在这两点之间删除了原始文件,因为大多数系统(包括 Git 本身)都禁止同时拥有一个problem
名为的文件和一个名为的problem
目录来保存各种problem
文件。鉴于每个 tar-archive 本身不是一个完整的快照——你忽略了C1和C2之间未修改的文件——你的解压过程这些快照必须是附加的:提取较早的快照,然后在较早的快照之上提取较晚的快照。此过程将在文件处于创建目录的方式时失败。显然,您可以检查此类问题并删除有问题的文件(您现在可以看到我为什么将文件命名为:-)),但更一般地说,由于您首先没有存储“删除”指令,因此您不会知道,在将来您使用这些档案来重建快照的情况下,某些文件根本不属于该快照。problem
problem
problem
(这个问题的经典解决方案是在 update-archives 前面加上某种清单或指令。如果您决定使用这样的解决方案,那么,根据清单或指令中所需的详细信息类型,您可能想要进行第一次检查以检测准确的重命名和/或准确的副本。)
1显然,新添加的功能会给每个人带来问题,不仅仅是脚本,也不仅仅是人类,但 Git 人员确实努力不给依赖管道命令的脚本带来不必要的问题。例如,考虑一下推动 Git 使用某种 SHA-256 替代或补充 SHA-1 的新动力。由于 SHA-1 产生 160 位散列,而 SHA-256 产生 256 位散列,因此它们必须分别表示为 40 位和 64 位十六进制数字。Linus 建议默认将 256 位哈希缩写为 40 个字符,以帮助现有的假设40 个字符的脚本,但我预见到一些问题...... :-)