我已提交更改,忘记将文件添加到更改集。在其他提交之后,我意识到该文件现在从HEAD^4
提交中丢失了。
如何重写先前的提交以包含丢失的文件?
答案 0 :(得分:262)
我意识到人们可以谷歌来这里找一个更简单的答案:如果它只是最后一次提交怎么办? (OP的问题是修复历史上的第4次提交)
如果您提交并意识到您忘记立即添加某个文件 ,请执行以下操作:
# edited file-that-i-remember.txt
git add file-that-i-remember.txt
git commit
# realize you forgot a file
git add file-that-i-forgot.txt
git commit --amend --no-edit
--no-edit
将保留相同的提交消息。
轻松自在!
答案 1 :(得分:55)
使用git rebase --interactive HEAD~4
并为您要修改的提交设置edit
选项。
请记住,不应该修改以这种方式推送到远程存储库的提交。在这种情况下,最好添加一个缺少文件的新提交。
答案 2 :(得分:9)
如果你没有推送这4个提交,你可以按如下方式进行:
为所有这些提交创建补丁文件:
git format-patch -4
以4次提交回退:
git reset --hard HEAD~4
添加遗失文件:
git add missing-file
使用--amend
:
git commit --amend
应用所有已保存的补丁:
git am *.patch
如果您已推,则不应使用此方法。相反,只是承认你的错误并在HEAD之上再创建一个修复此问题的提交。
答案 3 :(得分:5)
虽然接受的答案是正确的,但它缺乏关于如何在rebase过程中执行编辑提交的详细说明。
首先,启动一个rebase过程:
git rebase --interactive HEAD~4
将显示提交列表,通过将单词pick
更改为edit
来选择要编辑的提交并保存文件。
对您的代码进行必要的修改(记得为新文件调用git add
)
完成所有修改后,发出git commit --amend
- 这将修改标记为edit
的提交
调用将完成此过程的git rebase --continue
(如果有更多提交标记为edit
,则需要重复上述步骤)
重要说明:
请勿删除标记为pick
但您不想编辑的行 - 保留原样。删除这些行将导致删除相关提交
如果您的工作目录不干净,GIT会在您进行变基之前强制您stash
;但是,在rebase期间你可以git stash pop / git stash apply
,以便将这些更改(即在开始rebase进程之前发生的更改)修改为标记为edit
的提交
如果出现问题并且您希望在完成之前还原在rebase过程中所做的更改(即您希望在启动rebase之前恢复到该点),请使用git rebase --abort
- 同时阅读:{ {3}}
正如接受的答案所说:
请记住,您不应该以这种方式修改推送到远程存储库的提交。在这种情况下,最好添加一个缺少文件的新提交。
答案原因在于How to abort an interactive rebase if --abort doesn't work?(标题为“ Rebasing的危险”的段落):
不要重新定义存储库外部的提交。
如果您遵循该指南,您会没事的。如果你不这样做,人们会恨你,你会被朋友和家人嘲笑。
当您重新设置内容时,您将放弃现有提交并创建相似但不同的新提交。如果你将提交推送到某个地方而其他人将它们拉下来并依赖它们,然后你用git rebase重写这些提交并再次推送它们,那么你的协作者将不得不重新合并他们的工作,当你试图将事情变得混乱把他们的工作拉回你的工作。
[...]
答案 4 :(得分:0)
这是一种非交互式 map
方法。
这需要额外的提交(因此不会按照 OP 的要求“重写之前的提交”),但我发现它更容易记住。
初始状态:
rebase
第 1 步 - 在应该包含文件 (* e834111 (HEAD -> master) do something that depends on file x
* 6dde62a do stuff, forget to add file x
...
) 的提交处签出一个新的临时分支:
git checkout -b temp 6dde
第 2 步 - * e834111 (master) do something that depends on file x
* 6dde62a (HEAD -> temp) do stuff, forget to add file x
...
丢失的文件和 add
:
commit
第 3 步 - 将原始分支和 * 50d1412 (HEAD -> temp) add file x
| * e834111 (master) do something that depends on file x
|/
* 6dde62a do stuff, forget to add file x
...
签出到 rebase
:
temp
第 4 步 - 删除临时分支 (* dd6f2dd (HEAD -> master) do something that depends on file x
* 50d1412 (temp) add file x
* 6dde62a do stuff, forget to add file x
...
)
注意:这也可以在不创建临时分支的情况下完成,例如使用git branch -d temp
后跟 git checkout 6dde
和 commit
到分离的头部。