我可以删除git提交但保留更改

时间:2013-04-02 18:56:15

标签: git undo git-reset

在我的一个开发分支中,我对我的代码库进行了一些更改。在我能够完成我正在处理的功能之前,我不得不将当前分支切换到master来演示一些功能。但只是使用“git checkout master”保留了我在开发分支中所做的更改,从而破坏了master中的一些功能。所以我所做的是使用提交消息“临时提交”在我的开发分支上提交更改,然后为演示提供checkout master。

既然我已经完成了演示并重新开始在我的开发分支上工作,我想删除我所做的“临时提交”,同时仍然保留我所做的更改。这可能吗?

11 个答案:

答案 0 :(得分:1209)

这很简单:

git reset HEAD^
没有git reset--hard的{​​p> --soft会使您的HEAD指向指定的提交,而不会更改任何文件。 HEAD^指的是当前提交的(第一个)父提交,在您的情况下是临时提交之前的提交。

请注意,另一个选项是正常继续,然后在下一个提交点运行:

git commit --amend [-m … etc]

将改为编辑最近的提交,具有与上述相同的效果。

请注意,如果您已将错误提交推送到其他人可能已将其撤消的位置,则此问题(与几乎所有git答案一样)可能会导致问题。尽量避免

答案 1 :(得分:154)

有两种方法可以解决这个问题。哪个更容易取决于您的情况

重置

如果要删除的提交是最后一次提交,并且您还没有完成任何其他工作,则只需使用git-reset

git reset HEAD^

将您的分支恢复到当前HEAD之前的提交。但是,它实际上并不会更改工作树中的文件。结果,该提交中的更改显示为已修改 - 它就像一个'uncommit'命令。事实上,我有一个别名就是这样做。

git config --global alias.uncommit 'reset HEAD^'

然后你可以在将来使用git uncommit备份一个提交。

<强>挤压

压缩提交意味着将两个或多个提交合并为一个。我经常这样做。在你的情况下,你有一个半完成功能提交,然后你将完成它并再次使用正确的永久提交消息提交。

git rebase -i <ref>

我上面说的是因为我想说明这可能是任何数量的提交。运行git log并找到要删除的提交,复制其SHA1并使用它代替<ref>。 Git将带您进入交互式rebase模式。它将显示您当前状态与代替<ref>之间的所有提交。因此,如果<ref>在10次提交之前,它将向您显示所有10次提交。

在每次提交之前,它将包含单词pick。找到您要删除的提交,并将其从pick更改为fixupsquash。使用fixup只会丢弃提交消息并将更改合并到列表中的前一个前任中。 squash关键字执行相同的操作,但允许您编辑新组合提交的提交消息。

请注意,当您退出编辑器时,将按照它们在列表中显示的顺序重新提交提交。因此,如果您进行了临时提交,然后在同一分支上执行了其他工作,并在稍后的提交中完成了该功能,那么使用rebase将允许您重新对提交进行排序并压缩它们。

警告:

重新定位修改历史记录 - 不要对已经与其他开发人员共享的任何提交执行此操作。

<强>积攒

将来,为避免此问题,请考虑使用git stash临时存储未提交的作品。

git stash save 'some message'

这会将您当前的更改存储到存储列表中。以上是stash命令的最明确版本,允许用注释来描述你的存储内容。您也可以简单地运行git stash而不是其他任何内容,但不会存储任何消息。

您可以使用...

浏览您的存储列表
git stash list

这将显示你所有的藏匿处,它们完成了什么分支,消息和每行的开头,以及该存储的标识符,看起来像这个stash@{#},其中#是它的位置一堆藏匿。

要恢复存储(可以在任何分支上完成,无论最初创建存储的位置),您只需运行...

git stash apply stash@{#}

同样,#是stashes数组中的位置。如果要恢复的存储位于0位置 - 也就是说,如果它是最近的存储。然后你可以在不指定存储位置的情况下运行命令,git会假设你指的是最后一个:git stash apply

因此,例如,如果我发现自己在错误的分支上工作 - 我可能会运行以下命令序列。

git stash
git checkout <correct_branch>
git stash apply

在你的情况下,你移动分支更多,但同样的想法仍然适用。

希望这有帮助。

答案 2 :(得分:49)

我认为你正在寻找这个

git reset --soft HEAD~1

它撤消最近的提交,同时保持该提交中的更改进行暂存。

答案 3 :(得分:32)

是的,您可以删除提交而不删除更改:     git reset @〜

答案 4 :(得分:8)

对于使用zsh的用户,您必须使用以下内容:

git reset --soft HEAD\^

此处解释:https://github.com/robbyrussell/oh-my-zsh/issues/449

如果URL失效,重要的部分是:

  

在命令中转义^

     

您也可以使用HEAD〜,这样就不必每次都转义它。

答案 5 :(得分:8)

2020简单方法:

git reset <commit_hash>

(您要保留的最后一次提交的提交哈希)。

如果提交已被推送,则可以执行以下操作:

git push -f

您将在本地保留未提交的更改

答案 6 :(得分:6)

在我的情况下,我已经推到了回购。哎哟!

您可以通过执行以下操作来还原特定提交,同时保留对本地文件的更改:

MultiViews

通过这种方式,我能够保留所需的更改并解除已经推送的提交。

答案 7 :(得分:3)

使用git 2.9(正好是2.9.2.windows.1) git reset HEAD^提示更多;不知道这里的预期输入是什么。请参考下面的截图

enter image description here

找到其他解决方案git reset HEAD~#numberOfCommits,我们可以选择通过保持更改完整来选择要重置的本地提交数。因此,我们有机会丢弃所有本地提交以及有限数量的本地提交。

请参阅以下屏幕截图,其中显示了git reset HEAD~1的效果: enter image description here

enter image description here

答案 8 :(得分:2)

另一种方法。

在临时提交的顶部添加提交,然后执行:

git rebase -i

将两个提交合并为一个(命令将打开带有显式指令的文本文件,编辑它)。

答案 9 :(得分:1)

在某些情况下,我只想撤消第一次提交时对特定文件的更改,以将它们添加到第二次提交中,并获得更干净的git日志。

在这种情况下,我的工作是:

git checkout HEAD~1 <path_to_file_to_put_in_different_commit>
git add -u
git commit --amend --no-edit
git checkout HEAD@{1} <path_to_file_to_put_in_different_commit>
git commit -m "This is the new commit"

当然,即使在rebase -i的中间,如果要拆分的提交上具有编辑选项,此方法也能很好地工作。

答案 10 :(得分:0)

您正在寻找git reset HEAD^ --softgit reset HEAD^ --mixed

docs所述,reset命令有3种模式:

git reset HEAD^ --soft

撤消git commit。更改仍存在于工作树(项目文件夹)+索引(-缓存)中

git reset HEAD^ --mixed

撤消git commit + git add。更改仍然存在于工作树中

git reset HEAD^ --hard

就像您从未对代码库进行过这些更改一样。更改从工作树中消失了。