这个问题与我今天提出的one有关。我在帖子和其他帖子上都阅读了不同的方法,这让我很困惑,所以我在这里澄清。
让我们说我在branch1中,我将branch2拉入其中,合并可以是快进或递归。 pull会在branch1中引入很多提交,我想要撤消。我在SO上看到的一种方法是使用命令
git reset --hard SHOW-HEAD
似乎工作正常。
我也试过这个通过这个命令完成同样的事情
git reset --hard HEAD~1
我已经阅读了一些评论,如果pull带来了多次提交,那么这个命令就不会起作用。但是,根据我的观察,无论提交的数量如何,HEAD~1总是指拉动之前的最后一次提交。那是对的吗?或者是否存在可能无法保留的情况?
这是我的git reflog,ce5fceb pull引入了多次提交,但是git reflog仅提升了1次提交。通过git reset --hard HEAD~1
,我可以撤消那个git pull。
f8e8370 HEAD@{0}: reset: moving to HEAD~1
ce5fceb HEAD@{1}: pull origin master: Merge made by the 'recursive' strategy.
f8e8370 HEAD@{2}: commit: commit at 11:35
b2c928b HEAD@{3}: commit: commmit at 11:32
a6fdbef HEAD@{4}: commit: commit at 7:35
40a147c HEAD@{5}: commit: commit at 7:27
答案 0 :(得分:1)
我想我知道为什么你会感到困惑(好吧,因为" git可能令人困惑" :-)但我的意思更具体。)
首先,我要提一下pull
只是fetch
后跟merge
。 1 fetch
步骤不会影响你的工作(这是将fetch
与其他所有内容分开的一点,fetch
让你的其他人工作但不接触你自己的任何事情。这是影响您自己工作的merge
步骤。 (它在这里并不重要,但它是我最初发现令人困惑的另一部分git。)
让我们来看看修订版ID,特别是像e59f6c2d348d465e3147b11098126d3965686098
那样丑陋的40个字符的内容。您将在整个地方看到这些内容,通常采用您在上面引用的缩写形式:f8e8370 HEAD@{2}: ...
这些东西 - 它们是SHA-1哈希值,因此它们被称为#sha; 1-shas" - git在内部使用它来识别提交。好吧,他们在存储库中识别所有,而不仅仅是提交,但重点是,这些是"真正的名称"提交。它们让人类使用起来很难看,但是这些数字始终有效,事实上,大多数时候你给git一个更人性化的名字,git只是立刻变成了一个sha -1。当您使用名称HEAD
时会发生这种情况,并且通常在您使用名称branch1
时也会发生。
("名称变成了sha-1"规则,这是你正在做git checkout
时的一个例外。这里保留了一个分支名称作为一个分支名称。你可以给checkout
一个sha-1代替,它可以让你获得git所称的"分离的HEAD&#34 ;;用一个分支名称,你的头不会被断头关闭,而git会把你放在分支上,但是其他命令,包括git reset
和git merge
,并不在乎。合并会将分支名称保存到放入提交消息,但合并操作使用sha-1。)
根据定义,任何提交只有一个sha-1。那个sha-1是真正的名字"提交。提交可以有许多其他名称 - 如果我们想要,我们可以称之为Joe-Bob:严重的是,您可以为任何提交分配名称 2 - 但最终git需要sha-1。
让我们再看看你引用的reflog输出(或者它的一点点):
f8e8370 HEAD@{0}: reset: moving to HEAD~1
ce5fceb HEAD@{1}: pull origin master: Merge made by the 'recursive' strategy.
f8e8370 HEAD@{2}: commit: commit at 11:35
这使用缩短的7个字符的sha-1而不是完整的sha-1,但显然第一个和第三个是相同的(如果我们查看剩余的33个字符,它们也匹配)。他们还有其他更人性化的名称:HEAD@{0}
和HEAD@{2}
。
这意味着HEAD@{2}
只是提交f8e8370...
的用户友好名称,HEAD@{0}
也是如此。这个@{text goes here}
后缀的内容还有很多,但目前只需注意有一个名称(HEAD
),at符号@
,然后卷曲数字周围的括号。该名称告诉git使用哪个reflog-- HEAD
,在这种情况下;每个分支都有一个 - 这个数字告诉git在reflog中看多久。所以HEAD@{0}
是" HEAD解决了0次之前",即,返回零次到HEAD
的早期版本。这意味着使用它现在拥有的值f8e8370...
。同时HEAD@{2}
是" HEAD在最后两次更改之前解决的问题"。之前有两个更改,HEAD
解析为与现在相同的提交sha-1。
现在,当您引用此位时,您还提到了HEAD~1
:
git reset --hard HEAD~1
虽然这看起来很像HEAD@{1}
,但它非常不同。它使用波形符~
字符而不是at符号和大括号。为了描述这是如何工作的,我们必须进入"提交图表"。我在这里完全没有完全涵盖这一点,但一般的想法是,这会重新计算一些"父提交"。所以git现在找到HEAD
的SHA-1,然后一次回到父提交。
(要查看所有规则,请使用git help revisions
或查看gitrevisions
page here。)
最后,让我们看一下git reset
。这个命令可以做很多事情, 3 但是你使用它的方式git reset --hard <revision>
只做了一件大事,至少在概念上:它解析了{{1提交sha-1的参数,然后它将当前的分支,索引和工作目录重新设置为该提交。
您可以随意拼写提交ID。 <revision>
解析为sha-1。 HEAD@{number}
解析为sha-1。 gitrevisions
page为您提供了指定sha-1的所有其他方法,包括缩短的sha-1,例如HEAD~number
(您可以从f8e8370
或git log
剪切和粘贴这些sha-1输出,例如)。
要撤消真正的合并(但不是&#34;快进合并&#34;,技术上根本不是合并),名称git reflog
实际上总是有效。这是因为真正的合并会创建一个包含两个父项的合并提交。 &#34;第一个父母&#34;是当前分支的前一个提示(第二个父项是合并的提交),波形语法总是使用第一个父项。 &#34;第一个父母&#34;是提交图中的一个重要概念,因为它确定了大多数人大多数人认为的主要发展方式&#34;。
名称HEAD~1
这是因为最近的更改是HEAD@{1}
所做的合并。之前的值HEAD
就是git pull
合并之前的值HEAD
。即使合并是快进的,这个版本也可以正常运行
HEAD
语法的一个大问题是,如果您对git pull
进行了任何其他更改,则必须不断提高数字:可能需要更改值2 -ago,或三个变化前。
(当HEAD@{n}
执行失败的合并时,会出现其余问题。在这种情况下,HEAD
尚未更改,撤消合并所需的内容是运行git pull
。)
&#34;原始SHA-1&#34;方法总是有效,但你必须找到(然后剪切和粘贴)SHA-1(通常不是那么大的交易,真的)。
1 您可以对此进行更改:您可以HEAD
执行git merge --abort
,然后执行pull
。重新定位可能更适合大多数人,但它不是默认值。
2 实际上,这就是git中的标签:提交的名称。 (Git有两种标签,&#34;注释&#34;标签提供额外的东西,不仅仅是一个名字,而轻量级标签只提供一个名字。)
3 Git通常会将两到五个单独的命令放入一个fetch
CLI命令中,通常是因为它们在内部相关,即使外部不是很多。例如,rebase
可以让您进入某个分支,或只需使用重新创建合并冲突等选项提取文件。第二个只与第一个相关,第一个(&#34;上一个分支&#34;)需要提取文件。
答案 1 :(得分:0)
为了撤消pull(或其他),你只需要在拉动操作之前使HEAD指向HEAD指向的提交。你可以在reflog中找到它(你知道的)。根据您显示的reflog,我可以说这是HEAD@{2}
(或f8e8370
),然后:
git reset --hard HEAD@{2}
或者您可以指定参考的旧值
git reset --hard f8e8370