如何更改过去的提交以包含丢失的文件?

时间:2013-01-16 22:34:20

标签: git git-commit

我已提交更改,忘记将文件添加到更改集。在其他提交之后,我意识到该文件现在从HEAD^4提交中丢失了。

如何重写先前的提交以包含丢失的文件?

5 个答案:

答案 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 6ddecommit 到分离的头部。