【问题标题】:How can I delete commits that are after the current HEAD?如何删除当前 HEAD 之后的提交?
【发布时间】:2015-02-23 03:31:42
【问题描述】:

在我的 Git 存储库中,我连续创建了三个提交:commit1commit2commit3

然后我意识到我在commit2commit3 中搞砸了,并决定回到commit1。为此,我跑了

git checkout commit1

现在我在commit1。如何删除commit2commit3

【问题讨论】:

  • 注意,在执行checkout commit1(其中commit1 是提交ID、远程分支或标签)之后,您处于分离头(=不在分支上)。然后,您必须检查您的分支并按照评论和答案中描述的reset 步骤操作。

标签: git git-commit


【解决方案1】:

检查你的分支然后重置它

根据您的描述,并假设您在查看 commit1(下图中的C1)之前位于某个名为 mybranch 的分支上,您必须处于以下情况:

C1 [HEAD]
 \
  C2 -- C3 [mybranch]

提交C2C3 仍然出现在git log 的输出中,因为它们仍然可以从mybranch 引用中访问。另请注意,HEAD 已分离。你应该做的是……

  1. 通过运行将HEAD 重新附加到mybranch

    git checkout mybranch
    

    这应该使您处于以下情况:

    C1
     \
      C2 -- C3 [HEAD -> mybranch]
    
  2. 通过运行将mybranch 分支重置为其尖端的祖父母

    git reset --hard mybranch~2
    

    这应该使您处于以下情况:

    C1 [HEAD -> mybranch]
    

由于提交 C2C3 现在已变得无法访问(即“已删除”),因此它们未显示在最后一张图中。


为什么不先重新连接 HEAD 就无法重置

这可能有点厚颜无耻,但这里解释了为什么其他两个答案不起作用。正如 cmbuckley 在his comment 中正确指出的那样,

git reset 重置您当前所在分支的状态(因此您需要在该分支上才能执行此操作)。如果您已签出 commit1,则您可能不在分支上(分离的 HEAD 状态)。

由于 OP (Imray) 处于分离 HEAD 状态,运行 git-reset before 将 HEAD 重新附加到分支将不会移动有问题的分支引用。这是一个说明这一点的玩具示例。

# set things up
$ mkdir test
$ cd test
$ git init
Initialized empty Git repository in /Users/jubobs/Desktop/test/.git/

# create a first commit
$ touch README
$ git add .
$ git commit -m "add README"
[master (root-commit) 85137ba] add README
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README

# create a second commit
$ printf "foo\n" > README
$ git commit -am "write 'foo' in README"
[master 3948e84] write 'foo' in README
 1 file changed, 1 insertion(+)

# inspect the log
$ git log --graph --decorate --oneline --all
* 3948e84 (HEAD, master) write 'foo' in README
* 85137ba add README

# check out the second commit (which detaches the HEAD)
$ git checkout 3948e84
Note: checking out '3948e84'.
# (boilerplate stdout is omitted...)
HEAD is now at 3948e84... write 'foo' in README

# reset to the first commit (equivalent to 'git reset --hard 85137ba')
$ git reset --hard HEAD^
HEAD is now at 85137ba add README
$ git log --graph --decorate --oneline --all
* 3948e84 (master) write 'foo' in README
* 85137ba (HEAD) add README

注意git reset 命令将HEAD 移动到初始提交,但没有移动master 分支。第二次提交没有被“删除”,因为它仍然可以从master 获得可访问;因此它被列在git log 的输出中。

【讨论】:

  • 我不在我的master 分支上,我在另一个分支上
【解决方案2】:

出于命名目的,我假设您位于存储库的主分支中,但任何分支都可以。这可以被认为是一个简单的指向提交对象的指针。您也可以将 HEAD 视为另一个指针,您可以使用 git checkout 移动它

commit1  ->  commit2  ->  commit3
                             ^
                             |
                           master

如果您想将主指针更改为提交 1,那么您需要发出 git reset 命令,正如其他人所指出的那样。

git reset --hard commit1

这会将上图中的主指针移动到与 commit1 对象相同的位置。

注意,您实际上并没有删除 commit2 和 commit3 对象,只是在 git 中没有指向它们的分支,因此 git 可以随意清理它们,或者您可以通过运行像这样的垃圾收集:

git gc --aggressive --prune

直到它从你的 repo 中被主动清除,你仍然可以检查 commit2 和 commit3,所以尽管你将主指针移回 commit1(使用git reset),如果(比如说)你不小心提交了,你必须小心存储库的密码并正在尝试恢复 - 在修剪之前,它们仍将位于您的本地存储库中。

【讨论】:

  • 我不在master 分支,而是在myFirstBranch,这有关系吗?
  • 不,我只说大师,所以其余的文本与该分支相关。所有分支都只是指针的名称。
  • 这个答案不正确。由于 OP 处于分离 HEAD 状态,git reset --hard commit1不会移动 master
  • 调用gc 不会摆脱提交,因为它们仍然被HEAD 的reflog 和提交它的分支引用。默认情况下,未引用的提交仅在 30 天后从 reflog 中删除。
  • @JosephK.Strauss git gc 带有适当的标志。
【解决方案3】:

强制您的分支为当前 HEAD 和 Checkout 分支

git branch -f mybranch
git checkout -

结帐分支并强制您的分支到当前 HEAD

git checkout -
git reset --hard HEAD@{1}

第二个选项特别有利,因为您不需要输入您的 branh 的名称或当前提交的标识。您甚至可以将其设为别名。

编辑:这假设您没有四处走动,并且您最近的结帐来自您的分支机构。

【讨论】:

  • 小心:git checkout - 假设 OP 没有在提交图上跳跃。
  • @Jubobs 你是对的。我没有意识到这一点。但是,当您第一次结帐而不是重置时它仍然很有用(这可能发生在我们中最优秀的人身上)。
【解决方案4】:

你想核对提交commit3(假设你目前在提交3 - 作为HEAD)。您可以执行以下操作:

git reset --hard HEAD~1

结果是:

commit1 -> commit2 
              ↑
             HEAD

您可以按照类似的流程移回commit1(即git reset --hard HEAD~2)。

【讨论】:

  • 假设commit1 是提交的哈希,你也可以只做git reset --hard commit1。如果分支像本地一样存在于远程,您还需要git push --force
  • @cmbuckley 你还在假设我在commit3 上(正如回答者所做的那样)还是在我在commit1 上时这样做?
  • git reset 重置您当前所在分支的状态(因此您需要在该分支上执行此操作)。如果您已签出commit1,则您可能不在分支上(分离的 HEAD 状态)。
  • OP 写道:我 [...] 决定回到 commit1 这不是你的答案。
猜你喜欢
  • 2015-12-01
  • 2015-12-22
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
  • 2018-08-20
  • 1970-01-01
相关资源
最近更新 更多