如何撤消已完成的“ git commit --amend”而不是“ git commit”


1293

我不小心修改了以前的提交。提交应该分开进行,以保留我对特定文件所做更改的历史记录。

有什么方法可以撤消上一次提交?如果我执行类似的操作git reset --hard HEAD^,则第一次提交也将被撤消。

(我尚未推送到任何远程目录)

Answers:


2286

您需要做的是创建一个新提交,其详细信息与当前HEAD提交相同,但其父级为的早期版本HEADgit reset --soft将移动分支指针,以便下一次提交发生在与当前分支头所在位置不同的提交之上。

# Move the current head so that it's pointing at the old commit
# Leave the index intact for redoing the commit.
# HEAD@{1} gives you "the commit that HEAD pointed at before 
# it was moved to where it currently points at". Note that this is
# different from HEAD~1, which gives you "the commit that is the
# parent node of the commit that HEAD is currently pointing to."
git reset --soft HEAD@{1}

# commit the current tree using the commit details of the previous
# HEAD commit. (Note that HEAD@{1} is pointing somewhere different from the
# previous command. It's now pointing at the erroneously amended commit.)
git commit -C HEAD@{1}

32
很酷,+ 1。我什至在倒数第二个修改视图git reflog中找到了正确的数字,例如{2}
JJD 2011年

177
为了清楚起见,第一个命令是真正的“撤消”。它在之前产生HEAD,工作目录(未更改)和索引状态git commit --amend。第二个是对新提交的“重做”。这些对任何人都有用git commit,而不仅仅是--amend
cdunn2001 2011年

60
因此,如果您没有修改需要挽回的新提交消息,则第二部分可以只是常规代码git commit
马特·蒙塔格

18
由于某种原因,我在运行时遇到错误git reset --soft HEAD@{1}fatal: ambiguous argument 'HEAD@1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions。当我用(感谢JJD!)中HEAD@{1}所示的等效提交哈希替换时git reflog,此答案非常有用!
蒂姆·坎伯

20
@TimArnold取决于您的外壳,您可能需要在前后加上单引号或双引号HEAD@{1}echo HEAD@{1}例如,如果我在tcsh中运行,则输出是HEAD@1因为花括号是由tcsh解释的。如果我使用单引号,则保留大括号。
开尔文

136

使用ref-log

git branch fixing-things HEAD@{1}
git reset fixing-things

然后,您应该只在工作副本中拥有所有先前修改的更改,然后可以再次提交

查看以前的索引类型的完整列表 git reflog


7
这也擦除了索引-仍然有用,但超出了简单的“撤消”操作。
cdunn2001 2011年

3
HEAD@{1}和之间有什么区别HEAD~1
neaumusic 2015年

15
@neaumusic:是的!与当前提交的父级HEAD~1完全相同,HEAD^并且标识该父级HEAD@{1}另一方面,它是指HEAD在此之前指向的提交,即,当您签出其他分支或修改提交时,它们表示不同的提交。
knittl

@knittl啊,难怪我没想到这是可能的,再次感谢,良好的信息
neaumusic 2015年

9
第一步是多余的。简单git reset HEAD@{1}就足够了。
居住

79

通过以下方式查找修改后的提交:

git log --reflog

注意:--patch为了清楚起见,您可以添加以查看提交的正文。与相同git reflog

然后通过以下方法将HEAD重置为以前的任何提交:

git reset SHA1 --hard

注意: SHA1 替换为实际的提交哈希。另请注意,此命令将丢失所有未提交的更改,因此您可以将它们存放在前面。或者,改用--soft保留最新的更改,然后提交。

然后在它上面挑选另一个提交:

git cherry-pick SHA1

26
如果这样做git reset SHA1 --soft,则可以保留最新的更改,然后提交。
pravj

24

您可以随时拆分提交,请参见手册

  • 使用git rebase -i commit ^启动交互式rebase,其中commit是要拆分的提交。实际上,任何提交范围都可以,只要它包含该提交即可。
  • 用操作“ edit”标记要拆分的提交。
  • 在编辑提交时,执行git reset HEAD ^。结果是HEAD倒退了一个,索引也随之变化。但是,工作树保持不变。
  • 现在,将更改添加到您希望在第一次提交中拥有的索引。您可以使用git add(可能是交互方式)或git-gui(或两者都使用)来做到这一点。
  • 使用现在合适的提交消息来提交当前索引。
  • 重复最后两个步骤,直到工作树干净为止。
  • 使用git rebase --continue继续进行重新设置。

26
方式太复杂了。git reflog是您所需的吗
knittl

2
是的,步骤很多,但是每个步骤都很简单且易于执行。这为我工作,并获得我的投票。
OzBandit 2012年

5
此外,此答案还可以让您有选择地选择您意外“修改”的更改,从而为git reset --soft HEAD @ {1}方法(确实解决了我的问题)提供了一些额外的价值
Wiebe Tijsma

2
您也可以使用reflog方法有选择地选择更改。只是做git reset而不是git reset --softgit add --patch
geekofalltrades 2015年

1
这仍然会重写历史记录,并且需要强行推动。根据您的情况,可能会或可能不会出现问题。
Pajn


14

也许可以git reflog在修改之前和之后使用两次提交。

然后使用git diff before_commit_id after_commit_id > d.diff来获取修改前后的差异。

下次使用git checkout before_commit_id返回到提交之前

最后一次git apply d.diff应用您所做的实际更改。

那解决了我的问题。


11

如果您已将提交推送到远程,然后错误地修改了该提交的更改,则可以解决您的问题。发出a git log在提交之前找到SHA。(这假设远程被命名为origin)。现在,使用该SHA发出这些命令。

git reset --soft <SHA BEFORE THE AMMEND>
#you now see all the changes in the commit and the amend undone

#save ALL the changes to the stash
git stash

git pull origin <your-branch> --ff-only
#if you issue git log you can see that you have the commit you didn't want to amend

git stash pop
#git status reveals only the changes you incorrectly amended

#now you can create your new unamended commit

3
这是比较笼统的问题的特例,但恰好满足了我的迫切需求。
dmckee ---前主持人小猫,

8

您可以执行以下操作来撤消您的 git commit —amend

  1. git reset --soft HEAD^
  2. git checkout files_from_old_commit_on_branch
  3. git pull origin your_branch_name

===================================

现在,您所做的更改与之前相同。这样就完成了undo的操作git commit —amend

现在,您可以执行git push origin <your_branch_name>,以推送到分支。


3

距此晚了将近9年,但没有看到这种变化提到完成同一件事(这是其中一些的组合,类似于最佳答案(https://stackoverflow.com/a/1459264/4642530) 。

搜索分支上所有分离的头

git reflog show origin/BRANCH_NAME --date=relative

然后找到SHA1哈希

重置为旧的SHA1

git reset --hard SHA1

然后将其向上推。

git push origin BRANCH_NAME

做完了

这将使您完全恢复到旧的提交。

(包括先前覆盖的分离提交头的日期)


是的,但是我通常想重置--soft以保留我的更改。我只希望它单独提交
Juan Mendes

2
  1. 上次提交检出到临时分支

    git branch temp HEAD@{1}

  2. 重置上一次提交

    git reset temp

  3. 现在,您将拥有提交和先前提交的所有文件。检查所有文件的状态。

    git status

  4. 从git阶段重置您的提交文件。

    git reset myfile1.js (依此类推)

  5. 重新附加此提交

    git commit -C HEAD@{1}

  6. 添加文件并将其提交到新提交。

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.