所以我想将大文件的一部分提取到一个新文件中并保留 git 历史记录,这样我就可以运行 git blame
并像重构之前一样查看更改。
最佳答案
在 Git 中,历史就是提交。没有文件历史记录。这与大多数其他版本控制系统不同:那些跟踪“文件身份”的其他 VCS 需要您通知他们新文件 path/to/new.ext
源自 path/to/existing.ext
以便他们可以将新文件的历史记录与旧文件的历史记录相关联。类似地,他们需要您通知他们有关文件重命名的信息——尽管某些(例如 ClearCase)可以通过简单地充当工作树的文件系统来自动检测重命名。 Git 不需要任何这些,因为它不能那样工作。 1
相反,在 Git 中,当你比较一次提交时——称之为 a
—对于另一个( b
),Git 尝试(动态地,在比较时)发现某个文件 a/path/to/name
与另一个文件“相同”b/some/other/path/to/anothername
.比较的程度和判断这些是同一个文件还是不同文件的算法,由Git命令决定。 git diff
命令首先查看实际路径名:如果它们相同,则文件相同,2 否则它们可能不同。如果您启用了重命名检测,那么“可能”部分就是重命名检测的用武之地。普通 git diff
还有-C
和 --find-copies-harder
启用“文件复制自”检测。使用 -C
两次(或 --find-copies-harder
)设置内容以查找从 a
中的任何文件复制的新文件提交(这被认为过于昂贵而无法自动执行;通常,只有被视为“已修改”的文件才会被视为副本源候选者)。git blame
命令有些不同(并且 a
和 b
提交只是每个提交的自动父子提交),但它仍然有 -C
选项。它的 -C
工作方式略有不同:一个 -C
查找从提交之间修改的文件中复制的行 a
和 b
.使用 -C
两次查找从提交 a
中的任何文件复制的此类行,和三个 -C
标志,它将“更难找到副本”:它将查看每个提交中的每个文件以查找复制的代码。
因此,在大多数情况下,您可以只使用一个 -C
在您的 git blame
.您应该使用 -C -C
如果复制的代码来自未修改的文件。使用三个 -C
s 如果您认为某些代码在很多次之前被删除,然后又复活了,并且您想找到原始来源。请注意 git blame
的 -C
选项打开 git blame
的 -M
选项,它检测移动的代码(因此与 git diff
的 -M
选项大不相同——文件重命名检测,总是启用的 git log --follow
,3)。
1这是 Git 优于其他 VCS 的一个很好的优势,因为 Git 可以检测人类忘记的情况,还可以在比较“相距甚远”的修订时检测重命名。这对 Git 来说是一个可怕的劣势,因为即使人类不会忘记,它也必须检测案例,从而错过重命名。这对 Git 来说是一个很大的优势,因为 future 更智能的算法会以更好的方式使用现有数据。简而言之,对于为什么它更好和为什么它更糟存在争论,但最终它只是不同的。
2对于git diff
,您可以使用其 -B
有条件地拆分这些自动配对的“同名意味着相同的文件”配对。选项。这对 git blame
来说是不可用的,但对它来说是不必要的。 ,这不是在做这种配对。
3由--follow
启用的代码在 git log
是一个可怕的黑客,基本上只适用于 git blame
要求的一种情况.不要尝试使用 --follow
逆序 git log
.
关于git - 如何将代码重构为新文件并保留 git 历史记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40466194/