让 Git 确认以前移动过的文件

我已经不假思索地手动移动了大量文件,而且找不到一种方法让 git 认识到这些文件只是移动了而不是实际上不同的文件。除了删除 old 并添加 new (从而丢失历史记录)或使用 git-mv 重做所有更改之外,还有其他方法可以做到这一点吗?

30795 次浏览

我觉得它已经这样了。现在,我可能错了,但是我读到 git 跟踪文件是基于它们的内容,而不是基于它们在文件系统中的位置或基于 delta/差异。在堆栈中,我认为它显示文件被删除,然后重新添加,但我想我已经尝试过一次,它仍然保持历史,由于前面提到的方式,git 跟踪事情。

还是希望有人能证实我是否正确。如果我误解了你的问题,我很抱歉。

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

如果你想在 git log中看到移动,除了列出哪些文件已经改变的选项之外,你还可以提供 -M

git log --summary -M

git将查看提交历史记录中相邻的树,并推断每次提交是否移动了任何文件。

为了查找副本和重命名,您可以使用 -C选项,您可以提供两次这样的选项,以牺牲一些性能为代价,使 git 更难查找可能的副本源。

git log --summary -M -C -C

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

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

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

git add -u

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

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

它有点笨重的 1,特别是如果你必须手工完成。但是它的优点是它留下了其他更改,比如更改名称空间或类名称,这样您就可以检查它们,并且只有在您打算这样做时才进行更改。


我希望找到一个更好的替代方案,当我找到它的时候,我会更新我的答案。

例如: 我将一大堆文件从 oldDir移动到 newDir,并开始热情地进行其他一些更改。现在我想看看还做了什么改动。使用 导致以下结果(在一条线上) :

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将重命名显示为“将要提交的更改”和“未进行提交的更改”下的文本修改

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

我所做的是创建两个分离的提交,一个当我移动文件,然后另一个编辑文件。我用这种方式保存着历史。