如何真正显示带有git的重命名文件的日志?


132

我对git比较陌生,我以前使用过Subversion。

我注意到,如果文件已重命名,大多数图形git前端和IDE插件似乎无法显示文件的历史记录。当我使用

git log --follow

在命令行上,我可以看到整个重命名日志。

根据Linus Torvalds的介绍,--follow开关是一个“ SVN noob”,令人满意的git用户不要使用它:

--follow是一个完全的hack,旨在满足那些从未对父母身份或漂亮的修订图一无所知的前SVN用户。

这并不完全是基础,但是当前的“ --follow”实现实际上是一种快速的预处理功能,它附加在修订步逻辑上,而不是任何真正不可或缺的东西。

从字面上看,它被设计为“ SVN新手”,而不是“真正的git功能”。这样做的想法是,您将摆脱那种(重新定义的)思维思维方式,这种思维方式在全局上重命名了物质。

我的问题:重命名的git用户如何在重命名文件时获取文件的历史记录?这样做的“真正”方法是什么?


17
@大卫厅:git mv oldfile newfile不会导致要记录的重命名,在所有 -它只是一样删除一个文件并添加另一个。git仅在事实发生后的每次提交时才从树的状态中计算出重命名和副本。
Mark Longair 2011年

20
@David Hall:如果您使用git以外的其他工具重命名文件(例如/bin/mv oldfile newfile),但是这样做git add newfile; git rm oldfile,结果与不会区别git mv oldfile newfile
Mark Longair 2011年

1
如果您曾经将文件移动到新的存储库,则这种意识形态会分崩离析,在这种情况下,无法移动其整个历史记录可能是一个主要问题。尽管当然有一个限制,在一个复杂的项目中,一个文件可以真正包含多少真实的历史记录。
Roman Starkov

1
注意:git log --follow使用git 2.9(2016年6月)有所改善:请参见下面的答案
VonC

1
从v2.15开始,您可能想尝试--color-movedwhen diff
Michael-Clay Shirky在哪里

Answers:


71

我认为,Linus观点背后的普遍动力是-坚持不懈地坚持-顽固的git用户根本不在乎“文件”的历史。您将内容放入git存储库中,因为整个内容具有有意义的历史记录。

文件重命名是“内容”在路径之间移动的一种特殊情况。您可能具有在文件之间移动的功能,而git用户可能会通过功能“ pickaxe”来跟踪文件(例如log -S)。

其他“路径”更改包括合并和拆分文件;git并不真正在乎您考虑重命名哪个文件以及考虑复制(或重命名和删除)哪个文件,它只是跟踪树的完整内容。

git鼓励“全树”思考,因为许多版本控制系统都以文件为中心。这就是为什么git引用“路径”比引用“文件名”更多的原因。


嗨,查尔斯,谢谢您的回答。看来我使用git的方式与使用SVN的方式非常相似。尽管我知道git与其他版本控制系统有很大的不同,但是git中的许多概念对我来说还是很陌生...我可能应该完成最近买的那本git书。
迈克

24
Linus的观点是,一个“适当的” gui能够跟踪整个文件中的代码块,而他希望现在能够拥有这样的工具。不幸的是,我们仍然没有那么奢侈,--follow仍然有用。
迈克尔·帕克

11
git确实会--follow为此提供其他解决方案吗?
Griwes

13
我认为--follow默认情况下会增强“整棵树”的思维。我的意思是,当我想查看文件中代码的历史记录时,我通常通常并不关心文件是否已重命名,我只是想查看代码的历史记录,而无论重命名如何。因此,我认为--follow将其设置为默认值是有意义的,因为我不在乎单个文件;--follow帮助我忽略单个文件的重命名,这通常是无关紧要的。
Eddified,2017年

2
所以...如果我决定关心“内容”而不是文件,我该如何打印与该文件中当前内容相关的提交?如果git为我在不同文件中跟踪了所有文件并报告了所有更改的日志,我会感到很高兴-我只是不知道如何获得它。
Ed Avis

36

我面临着与您完全相同的问题。即使我没有给您任何答复,但我相信您可以阅读Linus在2005年写的这封电子邮件,它非常相关,可能会给您一些有关如何解决该问题的提示:

…我声称,任何尝试跟踪重命名的SCM都会从根本上被破坏,除非它是出于内部原因(即,允许有效增量)而这样做,这完全是因为重命名无关紧要。他们不帮你,他们是不是你感兴趣的是什么

重要的是找到“这是从哪里来的”,而git体系结构确实做到了很好-比那里的其他任何东西都要好。…

我发现此博客文章引用了它这对于您找到可行的解决方案也可能有用:

在此消息中,Linus概述了理想的内容跟踪系统如何使您能够发现代码块是如何形成当前形状的。您将从文件中的当前代码块开始,返回历史记录以查找更改文件的提交。然后,您检查提交的更改,以查看是否对您感兴趣的代码块进行了修改,因为更改文件的提交可能不会触及您感兴趣的代码块,而只会触及您感兴趣的代码块。文件。

当您发现在提交之前代码块在文件中不存在时,您将更深入地检查提交。您可能会发现这是许多可能的情况之一,包括:

  1. 该提交确实引入了代码块。提交的作者是您正在寻找其出色功能的凉爽功能的发明者(或引入错误的有罪党);要么
  2. 该文件中不存在代码块,但是在不同文件中存在五个相同的副本,所有这些副本在提交后消失。提交的作者通过引入单个辅助函数来重构了重复的代码;要么
  3. (作为一种特殊情况)在提交之前,当前尚不包含您感兴趣的代码本身的文件,但是确实存在另一个内容几乎相同的文件,并且您所感兴趣的代码的块,文件中的所有其他内容一起存在于那时,并且确实存在于该其他文件中。提交后它消失了。提交的作者对文件进行了重命名,同时对其进行了较小的修改。

在git中,Linus的最终内容跟踪工具尚未以全自动方式存在。但是大多数重要成分已经存在。

请向我们发布您在此方面的进展情况。


感谢您发布这些文章。直到我阅读它们,我才完全掌握了内容历史的概念!我一直在想这是错误的方法!
DavidG

来自Linus的电子邮件非常棒,感谢您发布此邮件。
mik01aj 2016年

有趣的是,Git v2.15增加--color-moved了向“理想跟踪系统”的发展。我在玩它时看到它跟踪文件中的移动行,但意外地意识到它跟踪整个差异
Michael-Clay Shirky在哪里,

2
Linus解释了一个复杂的情况。但是在这里,我们有一个简单的情况:一个文件刚刚被重命名(或移动到另一个目录)。因此,应该有一个简单的解决方案。我认为问题出在事实上,而不是与Subversion相反,用户不能在提交时指示Git文件的来源,这--follow可能是错误的(例如,如果2个文件具有相同的内容,或者是否有修改)除了文件移动)。
vinc17

13

我注意到大多数图形git前端和IDE插件似乎都无法显示文件的历史记录(如果文件已重命名)

您会很高兴知道一些流行的Git UI工具现在支持此功能。有数十种Git UI工具可用,因此我不会一一列举,但例如:

  • 当查看文件日志时,SourceTree在左下方有一个复选框“跟随重命名的文件”
  • TortoiseGit在左下方的日志窗口中具有“跟随重​​命名”复选框。

有关Git UI工具的更多信息:


Source在重命名一次,重命名两次,重命名之前无法用于提交的更改详细信息时非常有用。我在这里报告了该错误:jira.atlassian.com/browse/SRCTREE-5715
英特尔

即使文件在历史记录中两次重命名,gitk也能很好地工作。该命令看起来像这样的“ gitk --follow path / to / file”
英特尔

6

注意:git 2.9(2016年6月)将大大改善以下内容的“笨拙”性质git log --follow

提交ca4e3ca(二〇一六年三月三十○日)由SZEDER的Gabor( )szeder
(通过合并JUNIOÇ滨野- gitster-提交26effb8 4月13日2016)

diffcore:修复重命名检测期间相同文件的迭代顺序

如果两个路径“ dir/A/file”和“ dir/B/file”具有相同的内容,并且父目录已重命名,例如“ git mv dir other-dir”,则 diffcore报告以下确切的重命名:

renamed:    dir/B/file -> other-dir/A/file
renamed:    dir/A/file -> other-dir/B/file

(请注意此处的反转:B/file -> A/fileA/file -> B/file

尽管从技术上讲并没有错,但这不仅使用户感到困惑,而且使基于重命名信息做出决定的git命令(例如,“ git log --follow other-dir/A/file'跟随' dir/B/file”经过重命名)变得令人困惑。

此行为是commit v2.0.0-rc4〜8 ^ 2〜14的副作用(diffcore-rename.c:简化查找确切的重命名,2013-11-14):存储源的哈希图从同一存储桶返回条目,即与当前目标匹配的源,按LIFO顺序排列。
因此,迭代首先检查“ other-dir/A/file”和“ dir/B/file”,并在找到相同的内容和基本名称后报告确切的重命名。


2

在Linux上,我已验证SmartGit和GitEye在遵循特定文件的历史记录时能够遵循重命名。但是,与gitk和GitEye不同,SmartGit显示了单独的文件视图和存储库视图(其中包含目录结构,但不包含其中的文件列表)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.