Git:手动重命名文件,Git 感到困惑

69

我正在使用Git,并手动重命名了一个已添加到代码库的文件。现在,我将已重命名为“新”文件添加到了代码库中,但是Git抱怨“旧”文件已被删除。那么我该如何让Git忘记旧文件呢?更好的办法是,如何告诉Git这个“新”文件真正就是“新”文件,以便保持变更历史记录完整?


5
git mv old new本质上就是 git rm --cached old; mv old new; git add new,只不过加了一些智能化的处理。Git会通过查找相似内容来识别重命名操作,因此无论你是否使用git mv,它都能够检测到重命名。也就是说,没有办法“告诉”Git这两个文件对应着彼此。 - Cascabel
2
有趣的是,已经过去了将近8年,但git仍然无法检测到重命名。 - RSFalcon7
Git重命名检测取决于重命名阈值git配置设置。如果您重命名文件并且还更改了文件内容超过某个阈值,git将不会将其视为重命名。以下是一个起点 https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---find-renamesltngt - Devin Rhode
就我个人而言,我尝试了这些解决方案,但是git和github从来都没有理解我所做的重命名操作,所以我放弃了 :) - undefined
5个回答

51

没有问题。只需执行git rm old或甚至git add -A,Git会意识到这是一次重命名。 Git将视删除和添加的内容相同为重命名操作。

您不需要撤消、取消暂存、使用git mv等。 git mv old new只是mv old new; git rm old; git add new的快捷方式。


11
如果旧文件已经不存在了,您需要使用 git rm --cached old 命令,因为在工作树中没有要移除的文件。请注意,这不会改变原来的意思。 - Cascabel
7
如果你移动文件并更改几行内容,然后运行git add -A命令,Git会智能地识别出这个"类似的"文件与原文件是相同的吗? - Phil
1
此外,如果文件主体发生了一些变化,例如由于文件名更改而导致的不同 #include 语句,Git 仍然能够理解。 - Vlad
当我尝试时,git似乎无法理解重命名的更改文件 - 不过另一个答案起作用了。 - mikemaccana

18

首先,取消手动移动文件的暂存操作:

$ git reset path/to/newfile
$ mv path/to/newfile path/to/oldfile

然后,使用Git移动文件:

$ git mv path/to/oldfile path/to/newfile

当然,如果您已经手动移动了文件,您可能希望重置到移动之前的版本,然后从那里简单地使用git mv命令。


7
最后一个指令出错了:致命错误:没有处于版本控制下。 - mmersz
在最后一个命令之前,只需执行 git add oldfile。谢谢Amber! - mmersz
1
只是注意到我最初看到了 fatal: bad source, source=oldfile destination=newfile,然后意识到这个答案中的说明已经考虑到这一点,通过将已重命名的文件重新命名为原始文件来解决了这个问题 :) - mindthief
@mindthief 哎呀,是这样的;谢谢。第二步,mv path/to/newfile path/to/oldfile。我注意到,如果我在提交之前一直编辑文件并且将"更改"暂存,我需要再次执行git mv ...。不过这没什么大不了的;在我看来,效果很好。 - undefined

1

试试这个:

mv new old
git rm new
git mv old new

3
无效。Git仍未将该文件标记为重命名。 - Quentin Roy
1
你仍需要使用 git add new 命令将文件暂存。 - Michael Haren

0

这必须是自动化的。我只有在提交时才会记得 git,而我不想这样。

#!/usr/bin/env python3

# This `git rm` wrapper respects the `--cached` option (like `git rm`).

import sys
import subprocess

if "--cached" in sys.argv:
    dest = sys.argv[-1]
    rest = sys.argv[1:-1]
    subprocess.check_call(["git", "add", dest])
    subprocess.check_call(["git", "rm"] + rest)
else:
    subprocess.check_call(["git", "mv"] + sys.argv[1:])

我不想记住 "git mv",因为git mvgit diff后面添加了隐藏状态,即使您明确提交与其无关的内容,它也会被隐式地添加到下一个提交中。我知道,这就是所谓的 "staged"状态,但我不喜欢它。我喜欢没有惊喜地提交。


-3
如果出现此错误,可能意味着您正在尝试移动的文件不是由git原始跟踪的,或者您正在尝试将文件移动到的目录不是一个git跟踪的目录。

正如 OP 所提到的,他已经将之前已经在版本控制下的文件移动了。你所描述的是当尝试 git mv 一个还没有被版本控制的文件时的情况(即一个还没有使用 git add 添加过的文件)。现在,Git 的错误信息会非常明确地指出该文件尚未被检入 VC。 - Kim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接