git,在保留历史记录的同时移动/重命名文件的可靠方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35618507/
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
git, sure-fire way to move/rename files while keeping the history
提问by xpt
I know there are "lots" of existing questions that looks similar, so let me summarize them before asking mine.
我知道有“很多”看起来相似的现有问题,所以在问我的问题之前让我总结一下。
- The answer to Is it possible to move/rename files in git and maintain their history?is, "it is not possible".
- The conclusion for git moving file while keeping historyis, Git maysee it as a move, or it may stilltreat it as a delete + addition.
- 这个问题的答案是可以移动/重命名文件在Git和维护他们的历史?是,“这是不可能的”。
- git移动文件同时保留历史的结论是,Git可能将其视为移动,也可能仍将其视为删除+添加。
The answer to the first one, I don't agree, because I've done that before. The answer to the second one is the reason why I'm asking this question. I.e.,
第一个答案,我不同意,因为我以前做过。第二个的答案就是我问这个问题的原因。IE,
I found I am doing git mv
all the times, but sometime it is treated as move/rename, and sometime it is treated as delete + addition. Thus, I want to know how I can make it always a move/rename?
我发现我一直在做git mv
,但有时它被视为移动/重命名,有时它被视为删除 + 添加。因此,我想知道如何使它始终移动/重命名?
Take this oneas an example, at the bottom, we can see several move/rename cases, like easygenapi/tf-varcaser.go → tf-varcaser.go
. Note that such moves are across/between the folders! I.e., I didit!
就拿这个作为一个例子,在底部,我们可以看到几个移动/重命名的情况下,像easygenapi/tf-varcaser.go → tf-varcaser.go
。请注意,此类移动是在文件夹之间/之间进行的!即,我做到了!
But there are many other cases git mv
were treated as delete + addition, showing in the exactly same change log. Again, I am doing git mv
all the times. Why git
behave differently?
但是还有很多其他情况git mv
被当作删除+添加,显示在完全相同的更改日志中。再说一次,我一直在做git mv
。为什么git
行为不同?
Is there any sure-fireway to move/rename git files while keeping the history?
是否有任何可靠的方法可以在保留历史记录的同时移动/重命名 git 文件?
回答by Kevin Burdett
tl;dr; no
tl;博士; 不
Longer version: In my experience, git is very good at detecting the move/rename as long as the file is unmodified. Git uses heuristics to attempt and locate the move. It can be fooled by having several files that are too similar, or if the file has been modified during the move, causing it to be too dissimilar from its original.
更长的版本:根据我的经验,只要文件未修改,git 就非常擅长检测移动/重命名。Git 使用启发式方法来尝试和定位移动。它可能会被多个过于相似的文件所欺骗,或者如果文件在移动过程中被修改,导致它与原始文件过于不同。
The best way I have found to do this is to do multi-stage commits, separating all of your moves into one commit, followed by the changes in another. For example...
我发现做到这一点的最好方法是进行多阶段提交,将您的所有移动分成一个提交,然后在另一个提交中进行更改。例如...
git mv foo.txt bar.txt
git commit
... modify bar.txt ...
git add bar.txt
git commit
It will not guarantee your move is detected correctly, as it can still get confused when there are multiple candidates. However it has worked very well for me and catches the majority of cases.
它不能保证您的移动被正确检测到,因为当有多个候选时它仍然会感到困惑。但是,它对我来说效果很好,并且可以捕获大多数情况。
回答by J?rg W Mittag
Git doesn't track renames. Period. It also doesn't track adds. Or deletes. Or diffs. Or patches. Or moves. Or any sort of change, really.
Git 不跟踪重命名。时期。它也不跟踪添加。或者删除。或者差异。或者补丁。或者移动。或者任何形式的改变,真的。
Git is snapshot-based. Every commit records a snapshot of the entire project. That's it. Howthat snapshot came to be, Git neither knows nor cares.
Git 是基于快照的。每次提交都会记录整个项目的快照。就是这样。这个快照是怎么来的,Git 既不知道也不关心。
Diffs, patches, adds, deletes, moves, renames, etc. are shown by various visualization tools, which infer them after the fact using heuristics (which is another way of saying "guessing"). Sometimes, they may guess correctly what you did, and sometimes they don't. It doesn't matter, though, because it's only visualization, it's not part of the history in any way, shape, or form.
差异、补丁、添加、删除、移动、重命名等由各种可视化工具显示,这些工具在事后使用启发式(这是“猜测”的另一种说法)进行推断。有时,他们可能会正确猜出您做了什么,有时则不会。不过,这并不重要,因为它只是可视化,它不是以任何方式、形状或形式的历史的一部分。
Most tools use some form of similarity metric, and infer that a rename occurred if two files have a similarity greater than some threshold. In some tools, this threshold is configurable. In some tools, even the algorithm is configurable. (A slightly related example: git diff
allows you to choose between different algorithms for inferring differences withinfiles.)
大多数工具使用某种形式的相似性度量,如果两个文件的相似性大于某个阈值,则推断发生了重命名。在某些工具中,此阈值是可配置的。在某些工具中,甚至算法也是可配置的。(一个稍微相关的例子:git diff
允许您选择不同的算法来推断文件内的差异。)
Since Git doesn't record changes, it is possible to add new changes in later versions of the visualization tools which can infer those changes from older commits which were recorded before the new tools which understand new kinds of changes were even written. Imagine, for example, a tool which understands the syntax and semantics of the programming language you are using. It could visualize a certain commit not as a whole bunch of files each having a couple of lines changed, but as a single change which renames a subroutine and updates each callsite (i.e. the Rename Method Refactoring).
由于 Git 不记录更改,因此可以在更高版本的可视化工具中添加新更改,这些更改可以从旧提交中推断出这些更改,这些更改甚至在编写了解新类型更改的新工具之前记录。例如,想象一个工具,它可以理解您正在使用的编程语言的语法和语义。它可以将某个提交可视化,而不是将每个文件都更改为几行的一大堆文件,而是将其视为重命名子例程并更新每个调用站点(即重命名方法重构)的单个更改。
Renames are actually a good example of this. The rename detection heuristics and similarity metrics used by git log --follow
, for example, were improved multiple times. IIRC, in the beginning, renames weren't inferred at all, that capability was added later. This would simply not have been possible, if Git recorded changes instead of snapshots.
重命名实际上就是一个很好的例子。git log --follow
例如,使用的重命名检测启发式和相似性度量得到了多次改进。IIRC,一开始根本没有推断出重命名,后来添加了该功能。如果 Git 记录更改而不是快照,这根本不可能。