我可以删除git commit但可以保留更改


1054

在我的一个开发分支中,我对代码库进行了一些更改。在我能够完成正在使用的功能之前,我必须将当前分支切换为master来演示一些功能。但是仅使用“ git checkout master”保留了我在开发分支中所做的更改,因此破坏了master中的某些功能。因此,我要做的是使用“临时提交”提交消息在开发分支上提交更改,然后为演示结帐母版。

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


65
下一次:git stash
Matt Ball

51
@MattBall,不一定。虽然这git stash是一个很好的工具,但“进行中”的一次性提交也是相当合法的工具。
kostix

3
这是来自Github的重要资源:如何使用Git撤消(几乎)任何操作
jasonleonhard

9
@MattBall @kostix是的,存储是特别不适合“长期”存储的,因为它是整个回购协议的全局堆栈。我希望能够在分支上存储更改,然后转到其他分支,执行其他任何操作,几天后再回来,而不必担心git stash在过渡期间我可能会在其他某个分支上使用过。
亚历克

4
值得注意的一件事stash是,它完全是本地的,很容易因重新删除或重新创建或硬件故障或丢失而导致代码丢失。IMO,它实际上仅应用于非常短的WIP。在休假前爱上WIP提交:P ..称其为“头脑风暴”提交!
ϹοδεMεδιϲ 18/07/23

Answers:


1617

就这么简单:

git reset HEAD^

注意:某些外壳程序被^视为特殊字符(例如,某些Windows外壳程序或启用了globbing的ZSH),因此"HEAD^"在这种情况下可能必须引用。

git reset不使用--hard--soft将您HEAD移至指定的提交,而不更改任何文件。HEAD^指当前提交的(第一个)父提交,在您的情况下,它是临时提交之前的提交。

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

git commit --amend [-m … etc]

而是编辑最近的提交,效果与上述相同。

请注意,如果您已经将错误的提交推送到其他人可能将其撤出的地方,则此问题(几乎与每个git答案一样)可能会导致问题。尽量避免这种情况


47
到目前为止,这是最简单的方法,但是如果您已经将提交推送到远程并且其他人将其提交了,那么除了道歉之外,我会很犹豫地执行任何操作。
atw13 2013年

11
@sicophrenic,不要错过这次阅读“重设神秘面纱”的机会。
kostix

33
More?这样做之后得到的。无论我在该提示下键入的内容如何,​​都会给我fatal: ambiguous argument 'HEADwhateverItypedIn': unknown revision or path not in the working tree.
DaAwesomeP 2015年

50
@DaAwesomeP听起来好像您正在使用一个被视为^特殊字符的外壳。您可以引用引用"HEAD^",也可以使用HEAD~1未引用的替代语法
Gareth

8
为我工作,但不得不逃避性格git reset HEAD\^
cevaris

188

有两种处理方法。哪个更简单取决于您的情况

重启

如果要删除的提交是最后一次提交,并且您还没有做任何其他工作,则可以简单地使用 git-reset

git reset HEAD^

将您的分支带回到当前HEAD之前的提交。但是,它实际上并不会更改工作树中的文件。结果,该提交中的更改将显示为已修改-就像“取消提交”命令一样。实际上,我有一个别名可以做到这一点。

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

然后,您git uncommit将来就可以使用它来备份一次提交。

压扁

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

git rebase -i <ref>

我在上面说是因为我想说清楚,这可以是任意数量的提交。运行git log并找到要删除的提交,复制它的SHA1并用它代替<ref>。Git将带您进入交互式变基模式。它将显示您当前状态与您放置的所有内容之间的所有提交<ref>。因此,如果<ref>10次​​提交之前,它将显示所有10次提交。

在每次提交之前,都将带有单词pick。找到您要删除的提交,并将其从更改pickfixupsquash。使用fixup只是简单地丢弃提交消息,并将更改合并到列表中其前身。该squash关键字做同样的事情,但是,您可以编辑提交的新合并的提交信息。

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

警告:

变基修改历史记录-不要对您已与其他开发人员共享的任何提交执行此操作。

藏匿

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

git stash save 'some message'

这会将您当前的更改存储在存储列表的侧面。上面是stash命令的最明确的版本,允许使用注释来描述要存储的内容。您也可以简单地运行git stash,什么也没有,但是不会存储任何消息。

您可以使用...浏览藏匿清单

git stash list

这将向您显示所有存储区,它们完成了哪些分支,消息以及每一行的开头,以及该存储区的标识符,如下所示stash@{#},其中#是其在存储区数组中的位置。

要恢复存储(可以在任何分支上完成,而不管存储是在哪里创建的),只需运行...

git stash apply stash@{#}

同样,#是隐藏数组中的位置。如果要还原的存储区在该0位置-也就是说,如果它是最新存储区。然后,您可以运行命令而无需指定存储位置,git会假设您的意思是最后一个:git stash apply

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

git stash
git checkout <correct_branch>
git stash apply

在您的情况下,您在分支机构周围移动了一些,但是同样的想法仍然适用。

希望这可以帮助。


6
git config --global alias.uncommit reset HEAD^仅别名取消提交即可。取而代之的是git config --global alias.uncommit 'reset HEAD^'
mernst

3
请注意,如果在Windows命令提示符下使用,则必须使用^^而不是^。
Pramod BR

106

我想你在找这个

git reset --soft HEAD~1

它撤消最近的提交,同时保留对该提交所做的更改以暂存。


7
谢谢。这对我有用。git reset HEAD^在Windows上调用只会提示“更多?” -意味着什么
泰隆(Tyron)

12
@Tyron ^是DOS中的转义字符。与新行配对时,它用作前面命令的继续提示。键入git reset HEAD^^应该在Windows上工作。
trk

40

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


7
这确实是我想要的,在我看来,它将是可以接受的答案,非常感谢!
卡洛斯·刘

2
有趣的紧凑语法,我以前从未见过或使用过。这与git reset --soft或有git reset --keep什么不同?
user776686 '19

18

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

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

git reset HEAD^ --soft

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

git reset HEAD^ --mixed

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

git reset HEAD^ --hard

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


9

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

git reset --soft HEAD\^

在这里解释:https : //github.com/robbyrussell/oh-my-zsh/issues/449

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

在命令中转义^

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


15
我永远不会记住此命令,而必须用Google搜索并找到我自己的答案哈哈哈哈
Greg Hilston

2
git reset HEAD^正在为我在zsh中工作,可能已修复。
Ben Kolya Mansley,

@BenKolyaMansley您正在运行哪个版本的zsh?
格雷格·希尔斯顿,

我正在使用zsh 5.3 (x86_64-apple-darwin18.0)
Ben Kolya Mansley,

7

就我而言,我已经推送到了仓库。哎哟!

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

git revert -n <sha>

这样,我可以保留我需要的更改,并取消已经推送的提交。


就我而言,我需要还原已经推送到远程存储库的内容。哎呀!最好的方法是先到git revert bad-commit-sha,然后git revert -n revert-commit-just-created-sha再从那里进行维修。你让我中途了。谢谢!
TinkerTenorSoftwareGuy

这似乎是相反的,不是吗?它创建新的更改,这些更改对应于所选提交中所做的更改的还原。如果要进行这些新更改,则将撤消您实际上想要保留的工作。
svaens

3

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

在此处输入图片说明

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

请参阅下面显示的屏幕截图git reset HEAD~1在此处输入图片说明

在此处输入图片说明


您可能需要转义^字符-尝试git reset“ HEAD ^”或git reset HEAD \ ^
Mark Fisher

除此之外,git reset HEAD ^^可以作为单个^视为新行。
约翰·奥斯

2

另一种方法。

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

git rebase -i

要将两个提交合并为一个(命令将使用明确的指令打开文本文件,对其进行编辑)。


2
从技术上讲是正确的,但远不及简单的优雅git reset HEAD^。Git rebase在这里有很多错误的余地。
TheBuzzSaw
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.