Git无法识别重命名和修改的包文件
我有一个名为package/old/myfile.java
的java文件。 我通过git提交了这个文件。 然后我将我的包重命名为new
所以我的文件在package/new/myfile.java
。
我现在想将此文件重命名(和内容更改)提交给git。
当我做git status
我得到了
# Changes not staged for commit: # (use "git add/rm ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # deleted: package/old/myfile.java # # Untracked files: # (use "git add ..." to include in what will be committed) # # package/new/myfile.java
我已经尝试add
新的和旧的,反之亦然,我一直在努力
$ 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上尝试了一些针对类似问题的多个答案,但它们没有奏效。
git书中的相关部分解释了这一点。
与许多其他VCS系统不同,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
将文件移回,然后提交,并将实际移动放入单独的提交中。 Git不会记录移动(或重命名),但可以根据内容识别它们。 如果内容发生变化,则无法正确检测到移动。 因此,通常的做法是将移动和更改分成两个提交。
用于实现@Nevik Rehnel建议的两个提交的命令,通过重写历史记录来在编辑之前移动文件:
开始条件:
- 您最近的提交包括对文件的移动和修改以及
git log --follow newpath
将文件显示为最近提交中新创建的文件
脚步:
- 标记您当前的状态
git tag working_code
- 启动交互式rebase来编辑历史记录:
git rebase -i HEAD~2
- 在弹出的编辑器中,将第一行的“选择”更改为“编辑”,保存并退出。
- 您现在正在提交之前编辑历史记录
- 将移动创建为自己的提交
-
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
恢复文件 - 完成rebase:
git rebase --continue
- 你应该在newpath上发生冲突。 使用
- validation
git log --follow newpath
显示完整历史记录