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

Mik*_*ike 121 git

我对git比较新,我之前使用过Subversion.

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

git log --follow
Run Code Online (Sandbox Code Playgroud)

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

根据Linus Torvalds的说法--follow switch是一个"SVN noob",严肃的git用户不使用它:

--follow是一个彻底的黑客,意味着只是满足前SVN用户,他们从来不知道任何事情,如父母身份或漂亮的修订图表无论如何.

这并不是完全基本的,但是" - follow"的当前实现实际上是一个快速的预处理事物,它固定在修订行走逻辑上,而不是真正的整体.

它实际上被设计为"SVN noob",而不是"真正的git功能".我们的想法是,你要摆脱思维的(破碎)思维方式,重新命名大局.

我的问题:你们中的硬核git用户如何在重命名时获取文件的历史记录?这样做的"真实"方法是什么?

CB *_*ley 68

我认为Linus背后的一般驱动力是 - 并且用一点点盐 - 硬核git用户不关心"文件"的历史.您将内容放在git存储库中,因为整个内容具有有意义的历史记录.

文件重命名是在路径之间移动的"内容"的一个小特例.您可能有一个在git用户可能跟踪的文件之间移动的功能与"pickaxe"功能(例如log -S).

其他"路径"更改包括合并和拆分文件; git并不关心您考虑重命名的文件以及您认为复制(或重命名和删除)的文件只跟踪树的完整内容.

git鼓励"整树"思考,因为许多版本控制系统都是以文件为中心的.这就是为什么git比"文件名"更频繁地引用"路径"的原因.

  • Linus的观点是,"适当的"gui能够跨文件跟踪代码块,他希望我们现在可以使用这些工具.不幸的是,我们仍然没有那么奢侈,而且 - 关注仍然有用. (21认同)
  • git实际上为你提供了除了`--follow`以外的解决方案吗? (11认同)
  • 我认为`--follow`是默认的"全树"思维.我的意思是当我想要查看文件中代码的历史记录时,我通常不关心文件是否被重命名,我只想查看代码的历史记录,而不管重命名.所以在我看来,`--follow`是默认的,因为我不关心单个文件; `--follow`帮助我忽略单个文件重命名,这通常是非常无关紧要的. (9认同)
  • 问题是文件名实际上具有相关性。例如,用户想知道一个跨越 20 年历史的项目中存在的文件发生了什么。当这样的用户尝试升级到较新的版本并且他们几年前修改过的文件根本不存在时,他们如何找出现在需要应用本地更改的位置? (3认同)
  • @Griwes 目前没有。我认为 Linus 考虑的“正确”方式是 `log <path>`,`show` 日志中最旧的提交,手动识别内容的来源,然后从 `log <old-path>` 重复。这假设你的承诺很小,所以它是实用的——但话又说回来,微小的承诺已经对生活质量产生了巨大的提升。 (2认同)
  • 所以......如果我决定关心"内容"而不是文件,我该如何打印与此文件中当前内容相关的提交?如果git为我跟踪了所有不同的文件并报告了所有更改的日志,我会很高兴 - 我只是不知道如何获得它. (2认同)

Alb*_*lli 35

我遇到了与你面临的问题完全相同的问题.即使我不能给你回答,我相信你可以阅读Linus在2005年写的这封电子邮件,这是非常贴切的,可能会给你一个关于如何处理问题的提示:

...我声称任何试图跟踪重命名的SCM都会从根本上被破坏,除非出于内部原因(即允许有效的增量)这样做,因为重命名并不重要.他们不帮你,他们是不是你有兴趣.

重要的是找到"这是从哪里来的",而git架构确实做得非常好 - 比其他任何东西都要好得多....

我发现这篇博文引用了它,这对你找到一个可行的解决方案也很有用:

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

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

  1. 提交真正引入了代码块.上提交的作者是你猎杀它的起源为很酷的功能的发明者(或谁介绍的bug有罪的一方); 要么
  2. 文件中不存在代码块,但是在不同的文件中存在五个相同的副本,所有这些副本在提交后都消失了.提交的作者通过引入单个辅助函数重构了重复的代码; 要么
  3. (作为特殊情况)在提交之前,当前包含您感兴趣的代码块的文件本身不存在,但是存在具有几乎相同内容的另一个文件,以及您感兴趣的代码块,与当时存在的文件中的所有其他内容一起,确实存在于该另一个文件中.提交后它就消失了.提交的作者重命名了该文件,同时对其进行了一些小修改.

在git中,Linus的终极内容跟踪工具尚未以完全自动化的方式存在.但大多数重要成分已经可用.

请告诉我们您在此方面取得的进展.

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

Mic*_*ker 11

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

您会很高兴知道一些流行的Git UI工具现在支持这一点.有许多可用的Git UI工具,所以我不会全部列出它们,但是例如:

  • SourceTree在查看文件日志时,左下角有一个复选框"关注重命名的文件"
  • TortoiseGit在左下角的日志窗口中有一个"关注重命名"复选框.

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


Von*_*onC 6

注意:git 2.9(2016年6月)将改善相当多的"错误"性质git log --follow:

提交ca4e3ca通过(2016年3月30日)SZEDER的Gabor( )szeder.
(由Junio C gitsterHamano合并- -提交26effb8,2016年4月13日)

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
Run Code Online (Sandbox Code Playgroud)

(注意这里的反演:B/file -> A/file,和A/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)的副作用:存储源的hashmap返回来自同一存储桶的条目,即与当前目标匹配的源,以LIFO的顺序.
因此,迭代首先检查' other-dir/A/file'和' dir/B/file',并在找到相同的内容和基名后,报告确切的重命名.


Wil*_*ken 5

操作方法如下:

git log -M --summary | grep rename | grep BASENAME
Run Code Online (Sandbox Code Playgroud)

只需将基本名称放入其中即可。

如果结果太多那么你也可以串行grep每个中间目录名称。