git 中状态码“C”和“T”是如何触发的?有人可以给我一组非常简单的运行命令来模拟所需的步骤,以便在运行时git log --name-status
看到上面的状态代码吗?我尝试过复制文件并更改已被跟踪的文件的扩展名类型,但它只是标记为已修改或已添加。
https://git-scm.com/docs/git-diff
\n\n\n\n\n仅选择已添加 (A)、已复制 (C)、已删除 (D)、\n 已修改 (M)、已重命名 (R) 且具有其类型的文件(即常规文件、\n 符号链接、子模块、\xe2\x80 \xa6\xe2\x80\x8b) 已更改 (T)、未合并 (U)、未知\n (X),或者其配对已损坏 (B)。可以使用过滤字符的任意组合(包括无)。当 * (All-or-none)\n 添加到组合中时,如果有任何\n 文件与比较中的其他条件匹配,则选择所有路径;如果没有\n 与其他条件匹配的文件,则不会选择任何内容。
\n
谢谢
\n对于C状态(已复制),您需要添加--find-copies-harder
git log --find-copies-harder --name-status -3
Run Code Online (Sandbox Code Playgroud)
如果您在新提交中添加文件的完整未修改副本,您将看到:
C100 b.bat b1.bat
Run Code Online (Sandbox Code Playgroud)
如果文件较大,-C -M
则足以检测副本。
对于(T)
,一个简单的chmod 755
orchmod 644
就足够了。
或者用文件替换符号链接。
或者文件的gitlink(父存储库索引中记录的特殊条目,模式 16000)。
--diff-filter
在 Git 中很早就引入了:commit f2ce9fd, Git v0.99, Jun 2005
你可以看到diff.h
. 它用于diff.c#diff_resolve_rename_copy()
因此,如果您以不同的类型复制文件,它就是(T)
.
DIFF_PAIR_TYPE_CHANGED
定义为:
#define DIFF_PAIR_TYPE_CHANGED(p) \
((S_IFMT & (p)->one->mode) != (S_IFMT & (p)->two->mode))
Run Code Online (Sandbox Code Playgroud)
(S_IFMT 0xF000 /* File type mask */
,用于“如何读取git-ls-tree
输出的模式字段”)
DIFF_PAIR_TYPE_CHANGED
很早就在2005 年 5 月的 Git v0.99中引入了。并在Git v1.4.0-rc1, Apr. 2006中进行了重构。
为了详细说明VonC\'s 答案,请注意文档git diff
中提到了这-C
一点--find-copies-harder
说明:
\n\n\n出于性能原因,默认情况下,
\n-C
仅当副本的原始文件在同一变更集中被修改时,该选项才会查找副本。\n 此标志使命令检查未修改的文件作为副本源的候选文件。对于大型项目来说,这是一个非常昂贵的操作,因此请谨慎使用。给出多个-C
\n 选项具有相同的效果。
这是“非常昂贵”的原因是近似匹配代码。在进一步阅读之前,请考虑一下您在典型差异中看到的内容:
\n\ndiff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh\nindex 96d208d..80b2387 100755\n--- a/t/t5000-tar-tree.sh\n+++ b/t/t5000-tar-tree.sh\n@@ -347,7 +347,7 @@ test_lazy_prereq TAR_HUGE \'\n test_cmp expect actual\n \'\n\n-test_expect_success \'set up repository with huge blob\' \'\n+test_expect_success LONG_IS_64BIT \'set up repository with huge blob\' \'\n obj_d=19 &&\n obj_f=f9c8273ec45a8938e6999cb59b3ff66739902a &&\n obj=${obj_d}${obj_f} &&\n
Run Code Online (Sandbox Code Playgroud)\n\n这里我们有\xe2\x80\x94,Junio Hamano 已\xe2\x80\x94 删除了原来的text_expect_success
行并插入了一个新的、略有不同的test_expect_success
行。
嗯,真的,他刚刚插入LONG_IS_64BIT
队列。我们刚刚掩盖了一个非常大的主题,即:我们如何选择“块”来进行比较和显示?我们假设正确的答案是“一次一行”。在内部,Git 需要做出各种不同的选择,并且它并不总是做出相同的选择,或者做出一致的选择;它做得更多是临时性的,无论出于什么目的,只要效果好就可以。
给定一个 diff\xe2\x80\x94,找到一个本身就有点困难,有点计算密集型;朴素算法是 O(MN),迈尔斯算法大致是 O(ND)\xe2\x80\x94 然后我们可以定义一个相似性索引t/t5000-tar-tree.sh
:新的中有多少原始的t/t5000-tar-tree.sh
,有多少不同?Git 将其定义为:
\n\n\n与文件\xe2\x80\x99s 大小相比的添加/删除量
\n
(再次,来自git diff
文档)。另请参阅Edward Thomson 的回答,其中详细介绍了相似性指数的计算。出于性能原因,它更多地作为一种精简的差异,而不是完整的差异。
还有另一个重要的性能技巧:只需通过比较 blob 哈希值即可预先处理精确匹配(100% 相似的文件)。这消除了运行任何差异的需要,甚至是精简的差异。由于文件在更改刚刚发生时具有完全匹配命名时文件具有精确匹配,因此我们可以非常快地完成此操作。
\n\ngit diff
考虑一下这里必须做什么。我们正在比较两个目录树,我们可以将其称为“左”(通常是旧版本)和“右”(新版本)。左边的树有一些文件:a.txt
、b.txt
等(可能在子树中,例如dir/e.txt
)。右边的树也有一些文件。
假设左右树都有相同的文件(按名称)。在这种情况下,我们可能只想停在这里,并声明没有文件被重命名,也没有文件被复制;我们也许可以继续比较每个文件的内容,一次一对。这将是 Git 的默认操作。
\n\n同样,如果我们没有右侧文件也没有左侧对应文件,则这是默认设置。
然而,如果我们添加-B
(“打破”大的变化),我们需要添加另一遍。我们逐对比较每个已经配对的文件对(例如“左a.txt
,右a.txt
”)。如果这些文件足够相似,我们就声明它们是同一个文件。如果它们差异太大,我们就会中断配对,然后返回寻找重命名和/或副本。当然,“差异太大”的“差异量”是 的论点-B
。
(这个有点简化了\xe2\x80\x94-B
实际上有两个参数,一个用于“重写”检测,一个用于“重命名”检测。这第一遍的主要功能是记录相似度索引。前面提到,出于性能原因,这种相似性索引计算diff
与我们将看到的补丁不同。)
现在我们回到了这样的情况:我们可能有右侧文件,但没有左侧“原始”版本。无论我们是否有任何此类右侧文件,此时我们都可能拥有没有右侧版本的左侧文件。这就是-C
进来的地方-M
。
请注意,-M
也称为--find-renames
,并-C
暗示-M
。也就是说,我们可能只启用了重命名检测,或者我们可能启用了重命名和复制检测。
我们先来看看重命名检测。
\n\n如果它被禁用,则将所有未配对的右侧文件声明为新文件。我们完成了!那很简单!
否则,对于每个未配对的右侧文件,尝试找到一个足够相似的左侧文件。这意味着我们必须将每个未配对的左侧文件与该右侧文件进行比较。
\n\n假设我们有R 个未配对的右侧文件和L 个未配对的左侧文件。假设我们没有想出一些聪明的办法,我们会进行多少次比较?对于每个R,我们必须查看L中的每个文件,因此答案是R * L比较。但每次比较都是相似性索引 diff,这本身就很昂贵。
如果双方都没有多少未配对的文件,那么这没什么大不了的。但假设左侧有 10,000 个文件。好吧,只要这些文件中的 9,995 个已经配对,这仍然不是什么大问题:现在我们只有 5 个左侧未配对的候选文件,无论右侧有多少未配对的文件。假设有 10 个这样的文件,即 10 个R文件,以及 5 个(共 10,000 个)未配对的L文件。
\n\n这就是-M
工作原理。它只查看未配对的左侧文件。所以它的成本并不算太离谱:10 个R文件乘以 5 个L候选 = 50 个相似性差异。当然,如果您的计算机每秒可以进行大约 100 次相似性比较,那么计算时间仍然约为半秒。
计算机现在的速度相当快,因此它们可能可以做更多的事情。并且假设改变只是重命名,那么相似度指数为100%。Git 可以非常快地检测到这一点,根本不需要做任何 diff。Git 首先执行这些操作,一旦将它们配对,它们就会从“硬” R集中退出,从而变得-M
更便宜。
-C
或多或少,这也是默认的工作方式。我说“或多或少”是因为它不是查看未配对的左侧文件,而是查看已修改或未配对的左侧文件。也就是说,文件a.txt
同时存在于左树和右树中,但如果a.txt
左侧的哈希值a.txt
与右侧的哈希值不匹配,则 Git 将添加a.txt
到左侧集合中。假设除了5个未配对的L文件外,还有7个修改过的文件。因此,Git 现在必须执行 120 ((5 + 7) * 10) 相似性测试,而不是 50 (5 * 10) 相似性测试。
然而,添加--find-copies-harder
告诉 Git:不要只查看未配对或修改过的文件,还要查看每个文件左侧文件。现在我们有 10 个新文件乘以 10,000 个旧文件:需要计算 10 万个相似性索引值。即使我们每秒可以计算 1000 个,找到 100,000 个相似性索引值仍然需要 100 秒。
这意味着配置中的一个-C
选项或设置diff.renames
(copies
而不仅仅是true
)并不那么昂贵。不过,使用起来--find-copies-harder
仍然相当昂贵。
归档时间: |
|
查看次数: |
1649 次 |
最近记录: |