Git日志(--follow)无法显示重命名后的历史记录

Git日志(--follow)无法显示重命名后的历史记录,git,version-control,git-log,Git,Version Control,Git Log,我试图通过gitlog在git中显示文件的完整历史记录。 问题是该文件的partent文件夹在历史记录中被重命名,我希望看到完整的历史记录 表示参数--follow和-M在重命名后显示make git log 我尝试了gitlog参数的不同组合,如 git log-M--oneline--all--follow newpath/my file.php git log-M--oneline--all--newpath/my file.php 甚至 git rev list--all--newpat

我试图通过gitlog在git中显示文件的完整历史记录。 问题是该文件的partent文件夹在历史记录中被重命名,我希望看到完整的历史记录

表示参数
--follow
-M
在重命名后显示make git log

我尝试了gitlog参数的不同组合,如

git log-M--oneline--all--follow newpath/my file.php

git log-M--oneline--all--newpath/my file.php
甚至

git rev list--all--newpath/my-file.php--objects--in提交顺序| git log--no walk--oneline--stdin

但是无论我尝试什么,历史总是在提交时结束,文件的父文件夹被重命名

我已经可以确认:

  • 在重命名提交中,只有文件夹被重命名,文件的内容100%不变,因此git应该简单地发现旧路径上的文件和新路径上的文件是相同的,并且yust已重命名

  • 重命名提交的git shot name status显示
    R100 oldpath/my-file.php newpath/my file.php
    (确认文件内容100%相同)

  • 历史的“旧的一半”和“新的一半”似乎都是正确的,都包括重命名commt

  • 当我运行
    git log-M--oneline--all--follow newpath/my file.php时
    最早的提交是
    0979744重命名:oldpath/->newpath/

  • 当我运行
    git log-M--oneline--all--follow oldpath/my file.php
    时,最新的提交是
    0979744重命名:oldpath/->newpath/

所以看起来我的git成功理解了新路径中的文件和旧路径中的文件被重命名。 有谁能告诉我,为什么在使用
-M
--follow
选项时,重命名提交时历史记录仍然中断?

因为
--follow
选项必须位于指示选项列表结束的独立
--
之前


即使这样,下面的重命名现在也似乎起作用了,当我添加
--grep=“rename”-invert grep
以删除“rename”提交时,我得到了0个结果

这是有道理的(但这是一种缺陷),1因为
--follow
的工作方式。这里的问题是Git根本没有任何类型的文件历史记录。Git所拥有的只是存储库中的一组提交。提交是历史记录:

  • 每个提交都通过其丑陋的大散列ID进行编号,该ID对于该特定提交是唯一的。任何Git repository2中的其他提交都没有该散列ID

  • 每次提交都有每个文件的完整快照

  • 每个提交还存储以前提交的哈希ID,对于合并提交,存储两个或多个以前提交的哈希ID

因此,这些数字向后串在一起:

... <-F <-G <-H
要显示所有提交,
git log
必须遍历commit
O
,然后
N
,然后
M
,然后
K
L
(按一定顺序),然后
K
之前的所有提交和
L
之前的所有提交返回到
C
D
,然后在commit
B
处重新加入一个线程,并从那里向后继续

但是,如果我们不打算显示所有提交,可能只是在提交
M
时,我们可以返回到只提交
K
或只提交
L
并完全忽略合并的另一面。这将节省大量工作和时间,并避免向您展示无关的内容。这通常是一件非常好的事情

然而,对于
——遵循
,这通常是一件非常糟糕的事情。这是
——follow
的问题之一:有时候Git在进行这种简化时会走上“错误的道路”。添加
--完整历史记录
可以避免这种情况,但我们立即陷入另一个问题。
--follow
选项只有一个文件名。如果我们在提交的两个分支中有一个重命名,但在另一个分支中没有,并且
git log
首先进入重命名分支,那么它在进入另一个分支时可能会查找错误的名称

如果文件在两个分支中都被重命名,那么它将从
M
重新命名为
K
,从
M
重新命名为
L
,或者如果Git恰好在第一个位置进入了正确的分支,而您不关心另一个分支,那么一切都正常。但这是需要注意的。(这不是
--grep
给您带来的问题,或者在没有
--grep
的情况下会发生)

我认为您看到的错误是,
--grep
正在“太早”启动。
--grep
选项的工作原理是,从
git log
的输出中删除任何提交消息中包含(
--invert grep
)或缺少(
--grep
而不包含
--invert grep
)某些特定文本的提交。那么,假设重命名commit导致
-git log--follow
知道使用名称
oldpath/my file.php
——被
--grep
选项跳过。Git不会看到
R
状态,也不会知道将名称从
newpath/my file.php
更改为
oldpath/my file.php
。因此,
git log--follow
将继续查找新路径,并且您将只得到那些既满足grep标准又使用新名称修改文件的提交

这个bug可以通过让git log--follow
运行diff引擎来修复,即使它会因为其他原因跳过提交。但更一般地说,follow需要完全重写:它有一堆奇怪的特殊情况代码
             I--J   <-- feature1
            /
...--F--G--H
            \
             K--L   <-- feature2
          C--...--K
         /         \
...--A--B           M--N--O   <-- branch
         \         /
          D--...--L