Git无法识别重命名和修改的包文件

16

我有一个名为package/old/myfile.java的Java文件,已经通过Git提交了此文件。然后我将我的包重命名为new,因此我的文件位于package/new/myfile.java

现在我想将此文件重命名(和内容更改)提交到Git。

当我运行git status时,会得到:

# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    package/old/myfile.java
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       package/new/myfile.java

我尝试过添加新的并删除旧的,或者反过来操作,但结果都是一样的。

$ git status
# On branch develop
# Changes to be committed: 
#        delete:    package/old/myfile.java
#        new file:  package/new/myfile.java

由于旧文件不存在,我无法执行mv old new操作,因此出现了bad source错误。

我还有其他可以尝试的方法吗?

我尝试了一些关于类似问题的SO上的多个答案,但它们都没有起作用。

3个回答

21

有关部分可以在Git 书籍中找到。

与其他许多版本控制系统不同,Git 不显式跟踪文件移动。如果您在 Git 中重命名文件,则 Git 中不存储元数据以告知您已重命名该文件。但是,Git 在事后对此非常聪明 - 我们稍后会解决检测文件移动的问题。

这意味着如果您移动文件并进行重大更改,则 git 将不知道它是一个移动操作。 它将看到删除一个文件和创建一个新文件,因为新文件看起来不像旧文件。 为了解决这个问题,人们经常使用 git mv 命令移动文件,提交移动,然后再进行更改。 在你的情况下,你可以这样做:

git reset # Move changes from index to working copy
git checkout package/old/myfile.java # Undo delete
git mv package/old/myfile.java package/new/myfile.java # Move file

7

将文件移回原位置,然后提交,并将实际的移动操作放入单独的提交中。 Git不会将移动(或重命名)记录为移动操作,但可以根据内容在之后识别它们。如果内容发生更改,则无法正确检测移动操作。因此,将移动和更改分成两个提交是常见做法。


那么你的意思是检出旧文件,重命名它,提交,添加内容更新,再次提交? - Sotirios Delimanolis
不需要检出旧文件。您只需将新文件移回其旧位置(不要忘记更新索引),并首先提交内容更改。然后再提交移动操作。 - Nevik Rehnel
当您将文件移回时,“delete:”和“new file:”将仍然首先保留在暂存区中。您需要再次添加更改(例如,使用git add -A)。 - Nevik Rehnel

4

命令用于实现@Nevik Rehnel的建议,通过重写历史记录将文件移动到编辑之前:

开始条件:

  • 您最近的提交包括对文件的移动和修改,git log --follow newpath 显示该文件在最近的提交中是新创建的。

步骤:

  • 为当前状态打标签 git tag working_code
  • 开始交互式变基以编辑历史记录:git rebase -i HEAD~2
    • 在弹出的编辑器中,将第一行上的“pick”更改为“edit”,保存并退出。
  • 现在正在编辑提交之前的历史记录
  • 将移动操作作为自己的提交创建
    • git mv oldpath newpath
    • 包含新文件位置的目录必须存在;您可能需要先运行 mkdir 命令来创建它
    • (可选)对文件进行编辑,以应对文件重命名而需要的任何小更改(例如,在Java中:类名和/或包和导入行)- 避免进行其他更改 Git会根据相似性检测到这些更改为同一文件
    • git add . 并检查 git status 是否显示: renamed: oldpath -> newpath
    • git commit -m "Rename oldpath newpath"
  • git rebase --continue
    • 您应该会在 newpath 上遇到冲突。使用 git checkout working_code newpath 恢复文件。
    • 完成变基: git rebase --continue
  • 验证 git log --follow newpath 是否显示完整的历史记录

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