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


98

我已提交更改,但忘记将文件添加到更改集。其他提交之后,我意识到该提交现在缺少该文件HEAD^4

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


您是否推动了这4次提交?
mvp

@mvp不,它们仅在本地git存储库中。
kolrie

Answers:


53

对要修改的提交使用git rebase --interactive HEAD~4并设置edit选项。

请记住,您不应以这种方式修改推送到远程存储库的提交。在这种情况下,最好添加一个缺少文件的新提交。


谢谢。即使我是远程回购的唯一用户,还是这样吗?git push -f如果我确定上游没有变化,它是否可以让我做?
kolrie

1
如果您是远程仓库的唯一用户,则可以执行强制推送。
拉斐尔·拉威克

7
我认为这些说明不够详细。第一次尝试时,我被告知“无法重新设置基准:您的索引包含未提交的更改。” 我已经add-ed丢失的文件,所以我以“ xxx”作为消息进行了提交。然后,我执行了rebase命令,并将“ xxx”提交从“ pick”更改为“ edit”。然后我做了“ git rebase --continue”。现在,当我查看历史记录时,我将“ xxx”作为最新的提交,而我想将它们添加到的更早的提交则保持不变!我想知道我的错误在哪里?
Darren Cook

2
压缩最后一次提交不会将文件放入HEAD〜4。
贾斯汀

1
git添加editedFiles; git commit -m“布拉”;git rebase -i HEAD〜5; //现在添加了新的提交,因此我们需要以5而不是4为基数。现在将“ Blah”提交移至第二行,并将其从“ Pick”更改为“ s”(压扁),这将用HEAD压扁提交〜从上到下执行命令时显示5
zstring

273

我知道人们可以使用google并来到这里找到一个更简单的答案:如果这只是最后一次提交怎么办? (OP的问题是修复历史上的第四次提交)

如果您提交并意识到自己忘记立即添加一些文件,请执行以下操作:

# 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将保留相同的提交消息。

十分简单!


21
这就是答案。
亚当·比特林迈耶

5
值得一提的是,如果提交没有被推送到远程。
拉姆·帕特拉

1
是的,在这里的注释中值得一提:它是在push之前使用的。感谢您指出这一点。
Beco博士

2
一个通知是,提交前后的提交--amend具有不同的哈希值
sonlexqt

5
谢谢,但这不能是:OP要求HEAD^4。没关系,只是作为参考附录。;)
Beco博士

11

如果尚未推送这4个提交,则可以按以下步骤进行操作:

为所有这些提交创建补丁文件:

git format-patch -4

倒退4次提交:

git reset --hard HEAD~4

添加丢失的文件:

git add missing-file

提交--amend

git commit --amend

重新应用所有保存的补丁:

git am *.patch

如果已推送,则不应使用此方法。相反,只需承认您的错误并在HEAD之上再创建一个提交即可解决此问题。


如果您想逐步进行此操作,则在修改后的提交中选择樱桃提交要比将其导出为补丁更容易。
拉斐尔·拉威克

1
这是口味问题。我喜欢git format-patch/ git am好多了。最重要的是,如果您搞砸了某些东西,它会给您带来更大的信心-将补丁另存为物理文件是最好的安全网。
mvp

真正的信心在于,在git存储库上操作时,您永远不会删除任何东西。直到您运行旧提交可供git gc:)
拉法尔Rawicki

这对您和我来说都是微不足道的,显而易见的。但是,对于刚刚起步并且可能对git一无所知的用户-这个事实一点都不明显。
mvp

2
这些说明似乎很冗长,但是非常简单且易于遵循。谢谢。(我只想添加最后一步rm *.patch
达伦·库克

9

尽管接受的答案是正确的,但是它缺少有关在重新设置基准的过程中如何执行编辑提交的详细说明。

  • 首先,开始一个变基过程:

    git rebase --interactive HEAD~4
    
  • 将显示提交列表,通过将单词更改为pick来选择要编辑的提交edit并保存文件。

  • 在代码中进行必要的修改(记住要调用git add新文件)

  • 完成所有修改后,发布git commit --amend-这将修改标记为的提交edit

  • 调用git rebase --continue将完成该过程(如果还有更多标记为的提交edit,则需要重复上述步骤)

重要笔记:

  • 请勿删除标记为pick您不想编辑的行-保留原样。删除这些行将导致删除相关的提交

  • stash如果您的工作目录不干净,GIT会在重新设置基准之前强制您执行;但是git stash pop / git stash apply,您可以在重新设置基准期间将这些更改(即,在开始重新设置基准之前隐藏的更改)修改为标记为edit

  • 如果出了什么问题,并且您想在完成变基过程之前还原完成之前所做的更改(即,您想在开始变基之前还原到该点),请使用git rebase --abort-也请阅读:如果--abort不,如何中止交互式变基?工作吗?

  • 如公认的答案中所述:

    请记住,您不应以这种方式修改推送到远程存储库的提交。在这种情况下,最好添加一个缺少文件的新提交。

    问题的答案在《Git书》中(标题为“变基的危险”的段落):

    不要对存储库外部存在的提交进行基准化。

    如果您遵循该准则,就可以了。如果您不这样做,那么人们会讨厌您,并且您会受到朋友和家人的嘲笑。

    在对内容进行基础调整时,您将放弃现有的提交并创建相似但不同的新提交。如果您将提交推送到某个地方,而其他人则将它们下拉并在其上进行工作,然后使用git rebase重写这些提交,然后再次将其推上去,那么您的协作者将不得不重新合并其工作,并且当您尝试进行合并时,事情会变得混乱将他们的工作拉回到您的工作中。

    [...]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.