如何使用 git 真正显示重命名文件的日志?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5743739/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to REALLY show logs of renamed files with git?
提问by Mike
I'm relatively new to git, I used Subversion before.
我对 git 比较陌生,我以前用过 Subversion。
I noticed that most of the graphical git front-ends and IDE plugins don't seem to be able to display the history of a file if the file has been renamed. When I use
我注意到,如果文件已重命名,大多数图形 git 前端和 IDE 插件似乎无法显示文件的历史记录。当我使用
git log --follow
on the command line, i can see the whole log across renames.
在命令行上,我可以看到整个重命名日志。
According to Linus Torvaldsthe --follow switch is a "SVN noob" pleaser, serious git users don't use it:
根据 Linus Torvalds的说法,--follow 开关是一个“SVN noob”取悦者,严肃的 git 用户不使用它:
--follow is a total hack, meant to just satisfy ex-SVN users who never knew anything about things like parenthood or nice revision graphs anyway.
It's not totally fundamental, but the current implementation of "--follow" is really a quick preprocessing thing bolted onto the revision walking logic, rather than being anything really integral.
It literally was designed as a "SVN noob" pleaser, not as a "real git functionality" thing. The idea was that you'd get away from the (broken) mindset of thinking that renames matter in the big picture.
--follow 是一个彻底的黑客,旨在满足那些对父母身份或漂亮的修订图等事情一无所知的前 SVN 用户。
这并不完全是基本的,但是“--follow”的当前实现实际上是一个快速预处理的东西,附在修订行走逻辑上,而不是真正不可或缺的任何东西。
从字面上看,它被设计为“SVN noob”取悦者,而不是“真正的 git 功能”。这个想法是你会摆脱重命名在大局中很重要的(破碎的)思维模式。
My Question: How do the hardcore git users among you get the history of a file when it was renamed? What is the 'real' way to do this?
我的问题:当文件重命名时,你们中的铁杆 git 用户如何获得文件的历史记录?什么是“真正”的方式来做到这一点?
回答by CB Bailey
I think that the general drive behind Linus point is that - and take this with a pinch of salt - hardcore git users don't ever care about the history of a "file". You put content in a git repository because the content as a whole has a meaningful history.
我认为 Linus 观点背后的一般驱动力是——用一点点盐来理解这一点——铁杆 git 用户从不关心“文件”的历史。您将内容放在 git 存储库中,因为内容作为一个整体具有有意义的历史。
A file rename is a small special case of "content" moving between paths. You might have a function that moves between files which a git user might trackdown with "pickaxe" functionalitly (e.g. log -S
).
文件重命名是“内容”在路径之间移动的一个小特例。您可能有一个在文件之间移动的函数,git 用户可能会在功能上使用“pickaxe”来追踪这些文件(例如log -S
)。
Other "path" changes include combining and splitting files; git doesn't really care which file you consider renamed and which one you consider copied (or renamed and deleted) it just tracks the complete content of your tree.
其他“路径”更改包括合并和拆分文件;git 并不真正关心您认为重命名的文件以及您认为复制(或重命名和删除)的文件,它只是跟踪树的完整内容。
git encourages "whole tree" thinking where as many version control systems are very file centric. This is why git refers to "paths" more often than it refers to "filenames".
git 鼓励“整棵树”思考,其中许多版本控制系统都非常以文件为中心。这就是为什么 git 更频繁地提到“路径”而不是“文件名”。
回答by Alberto Bacchelli
I have exactly the same issue that you are facing. Even though I can give you no answer, I believe you can read this emailLinus wrote back in 2005, it is very pertinent and might give you a hint about how to handle the problem:
我和你面临的问题完全一样。尽管我不能给你答案,但我相信你可以阅读Linus 在 2005 年写的这封电子邮件,它非常中肯,可能会给你一个关于如何处理问题的提示:
…I'm claiming that any SCM that tries to track renames is fundamentally broken unless it does so for internal reasons (ie to allow efficient deltas), exactly because renames do not matter. They don't help you, and they aren't what you were interested in anyway.
What matters is finding "where did this come from", and the git architecture does that very well indeed - much better than anything else out there. …
...我声称任何试图跟踪重命名的 SCM 都从根本上被破坏,除非出于内部原因(即允许有效的增量)这样做,正是因为重命名无关紧要。他们不帮你,他们是不是你感兴趣的是什么呢。
重要的是找到“这是从哪里来的”,而 git 架构确实做得很好——比其他任何东西都好。…
I found it referenced by this blog post,which could also be useful for you to find a viable solution:
我发现这篇博客文章引用了它,这对您找到可行的解决方案也很有用:
In the message, Linus outlined how an ideal content tracking system may let you find how a block of code came into the current shape. You'd start from the current block of code in a file, go back in the history to find the commit that changed the file. Then you inspect the change of the commit to see if the block of code you are interested in is modified by it, as a commit that changes the file may not touch the block of code you are interested in, but only some other parts of the file.
When you find that before the commit the block of code did not exist in the file, you inspect the commit deeper. You may find that it is one of the many possible situations, including:
- The commit truly introduced the block of code. The author of the commit was the inventor of that cool feature you were hunting its origin for (or the guilty party who introduced the bug); or
- The block of code did not exist in the file, but five identical copies of it existed in different files, all of which disappeared after the commit. The author of the commit refactored duplicated code by introducing a single helper function; or
- (as a special case) Before the commit, the file that currently contains the block of the code you are interested in itself did not exist, but another file with nearly identical contents did exist, and the block of the code you are interested in, together with all the other contents in the file existed back then, did exist in that other file. It went away after the commit. The author of the commit renamed the file while giving it a minor modification.
In git, Linus's ultimate content tracking tool does not yet exist in a fully automated fashion. But most of the important ingredients are available already.
在消息中,Linus 概述了理想的内容跟踪系统如何让您了解代码块是如何形成当前形状的。您将从文件中的当前代码块开始,返回历史记录以查找更改文件的提交。然后您检查提交的更改以查看您感兴趣的代码块是否被它修改,因为更改文件的提交可能不会触及您感兴趣的代码块,而只会触及该文件的其他一些部分文件。
当您发现在提交之前文件中不存在代码块时,您可以更深入地检查提交。您可能会发现这是许多可能的情况之一,包括:
- 提交真正引入了代码块。提交的作者是你正在寻找它的起源的那个很酷的特性的发明者(或引入错误的有罪方);或者
- 该代码块不存在于文件中,但它的五个相同副本存在于不同的文件中,所有这些在提交后都消失了。提交的作者通过引入单个辅助函数来重构重复的代码;或者
- (作为特殊情况)在提交之前,当前包含您感兴趣的代码块的文件本身并不存在,但确实存在另一个内容几乎相同的文件,以及您感兴趣的代码块,与当时存在的文件中的所有其他内容一起,确实存在于该其他文件中。提交后它就消失了。提交的作者重命名了文件,同时对其进行了小的修改。
在 git 中,Linus 的终极内容跟踪工具还没有以完全自动化的方式存在。但大多数重要成分已经可用。
Please, keep us posted about your progress on this.
请让我们随时了解您在这方面的进展。
回答by Michael Parker
I noticed that most of the graphical git front-ends and IDE plugins don't seem to be able to display the history of a file if the file has been renamed
我注意到,如果文件已重命名,大多数图形 git 前端和 IDE 插件似乎无法显示文件的历史记录
You'll be happy to know that some popular Git UI tools now support this. There are dozens of Git UI tools available so I won't list them all, but for example:
你会很高兴知道一些流行的 Git UI 工具现在支持这个。有许多 Git UI 工具可用,所以我不会一一列出,但例如:
- SourceTree, when viewing a file log, has a checkbox "Follow renamed files" in the bottom left
- TortoiseGit has a "follow renames" checkbox on the log window in the bottom left.
- SourceTree,在查看文件日志时,在左下角有一个复选框“关注重命名的文件”
- TortoiseGit 在左下角的日志窗口中有一个“跟随重命名”复选框。
More info on Git UI tools:
关于 Git UI 工具的更多信息:
回答by VonC
Note: git 2.9 (June2016) will improve quite a bit the "buggy" nature of git log --follow
:
注意:git 2.9(2016 年 6 月)将大大改善以下“错误”性质git log --follow
:
See commit ca4e3ca(30 Mar 2016) by SZEDER Gábor (szeder
).
(Merged by Junio C Hamano -- gitster
--in commit 26effb8, 13 Apr 2016)
请参阅SZEDER Gábor ( )提交的 ca4e3ca(2016 年 3 月 30 日)。(由Junio C Hamano合并-- --在commit 26effb8,2016 年 4 月 13 日)szeder
gitster
diffcore: fix iteration order of identical files during rename detection
diffcore:修复重命名检测期间相同文件的迭代顺序
If the two paths '
dir/A/file
' and 'dir/B/file
' have identical content and the parent directory is renamed, e.g. 'git mv dir other-dir
', thendiffcore
reports the following exact renames:
如果两个路径“
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
(note the inversion here: B/file -> A/file
, and A/file -> B/file
)
(注意这里的倒置:B/file -> A/file
, 和A/file -> B/file
)
While technically not wrong, this is confusing not only for the user, but also for git commands that make decisions based on rename information, e.g. '
git log --follow other-dir/A/file
' follows 'dir/B/file
' past the rename.This behavior is a side effect of commit v2.0.0-rc4~8^2~14 (
diffcore-rename.c
: simplify finding exact renames, 2013-11-14): the hashmap storing sources returns entries from the same bucket, i.e. sources matching the current destination, in LIFO order.
Thus the iteration first examines 'other-dir/A/file
' and 'dir/B/file
' and, upon finding identical content and basename, reports an exact rename.
虽然技术上没有错,但这不仅让用户感到困惑,而且让根据重命名信息做出决定的 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
”,并在找到相同的内容和基本名称时报告准确的重命名。
回答by prusswan
On Linux, I have verified that SmartGit and GitEye is able to follow renames when following the history of a particular file. However, unlike gitk and GitEye, SmartGit shows a separate file view and repository view (which contains the directory structure but not the list of files contained within)
在 Linux 上,我已验证 SmartGit 和 GitEye 在跟踪特定文件的历史记录时能够跟踪重命名。但是,与 gitk 和 GitEye 不同,SmartGit 显示单独的文件视图和存储库视图(其中包含目录结构但不包含其中包含的文件列表)