让Git确认先前移动的文件


Getting Git to Acknowledge Previously Moved Files

我已经手动移动了一堆文件,没有考虑,也找不到一种方法让Git认识到这些文件只是被移动了,实际上不是不同的文件。除了删除旧的和添加新的(从而丢失历史),或者用git mv恢复所有更改之外,还有其他方法可以做到这一点吗?


要让git删除已经删除或移动的文件,只需输入

1
git add -u


我想它已经做到了。现在,我可能错了,但我已经读到Git根据文件的内容跟踪文件,而不是基于文件系统中的位置或基于delta/differences。在堆栈中,我认为它显示的好像文件正在被删除,然后重新添加,但我认为我已经尝试过一次,它仍然保持了历史,因为前面提到的Git跟踪事情的方式。

如果我是正确的或不正确的话,还是会有帮助的。对不起,如果我误解了你的问题。


git不跟踪单个文件的历史记录,也不专门处理移动和复制,也就是说,没有特殊的元数据表明发生了移动或复制。相反,每个git提交都是工作树的完整快照。

如果您想在git log中看到移动,您可以提供-M除了列出已更改文件的选项外,例如:

1
git log --summary -M

git将查看提交历史中相邻的树,并推断每个提交所移动的文件。

要查找副本以及重命名,您可以使用-C选项,您可以提供两次,以使git查找可能的副本源更加困难,但会牺牲一些性能。

1
git log --summary -M -C -C

注意,由于Git不存储文件历史记录(仅提交历史记录),即使您执行了git rmgit mv文件,也不会丢失任何历史记录。对路径的所有更改仍将被记录并在git log中可见。


为了更好地理解为什么Git会执行重命名检测而不是(更常见的)显式重命名跟踪,以及git log路径限制是如何工作的,您可以阅读Git维护者Junio C Hamano(及其参考)的Linus的终极内容跟踪工具博客文章。


它发生在我身上,当我移动和编辑文件时,它将不再识别为移动文件,而是一个新文件,所以我丢失了历史。

我要做的是创建两个分离的提交,一个在移动文件时,另一个在编辑文件。这样我就保留了历史。


您可以将新文件移回/重命名为Git之外的旧文件名和路径,然后使用git mv进行移动;例如在bash中:

1
mv $NEW $OLD && git mv $OLD $NEW

这有点麻烦,特别是如果你必须用手做的话。但是它的优点是,它会保留其他更改,如更改命名空间或类名,以便您可以检查它们,并且仅在您打算这样做时才进行阶段化。

1我希望找到一个更好的选择,当我找到答案时会更新我的答案。

例子:我把一堆文件移到了oldDirnewDir上,并热情地进行了一些其他的更改。现在我想看看还有哪些修改。使用git-xargs-gawk和bash会导致以下结果(在一行上):

1
2
3
git status --short |
gawk '/^\?\?/ && match($0, /newDir\/(*.\.cs)/, a) {print"newDir/" a[1]"""oldDir/" a[1]}' |
xargs -n 2 bash -c 'mv $0 $1; git mv $1 $0'

现在,git status将重命名显示为"要提交的更改",并将文本修改显示为"不准备提交的更改"。