我不小心从一个不同的分支拉了一下,改变了HEAD
的说法:
HEAD is now at 7c0208906 Merge remote-tracking branch 'refs/remotes/origin/lorem-ipsum'
现在,它不断从origin/lorem-ipsum
而不是origin/master
被拉的文件也带来了冲突。现在已经过了几天,主分支机构中的其他人已经对主分支进行了新的更改,而我已经落后了。
如何将我的存储库的状态恢复为错误提取之前的状态,如何将HEAD
简单地转移到以前的状态?
请帮助,我被困住了!
答案 0 :(得分:0)
git pull
命令只运行git fetch
(任何时候总是 1 安全),然后git merge
2 (不太如此)。因此,您需要恢复的是git merge
。但是这个:
现在,它不断从
origin/lorem-ipsum
而不是origin/master
...建议你告诉Git 记住"上游" master
的{{1}}是origin/lorem-ipsum
,而不是origin/master
。如果这是真的 - 您不会显示您运行的实际git pull
,也不会显示git status
或git branch -vv
的输出,所有这些都是有用的线索 - 那么还需要修复master
的上游设置。
在我们进入下一步之前,还有一件事需要注意:
被拉的文件也带来了冲突。
记住Git不会提取文件非常重要。 Git获取,然后合并,提交。提交有文件,合并一些提交可能会导致文件冲突,所以这可能看起来像一个小问题,但它影响如何你恢复这些东西。
当做发生合并冲突时,你必须自己解决冲突的文件,git add
结果,并做最后的git commit
进行合并提交。 (当你没有得到合并冲突时,Git会为你添加并提交结果。)git status
命令 非常 很有用,因为它会告诉你,如果你正处于冲突合并的中间,还有很多其他好的信息。经常使用它。
如果您处于错误合并的中间并且您希望整件事情消失,那很简单:只需运行git merge --abort
即可。这会停止合并过程并将所有内容恢复到开始之前的状态。
如果你已经完成合并,但它很糟糕而且你想摆脱它,那就更难了,因为你或Git完成了合并进行新的提交,提交的全部内容是它们是永久性的,不变的。提交坚持"永远", 3 并且新的提交建立在先前的提交之上,因此它真的很难摆脱&# 34;中间"一。摆脱一些" end"更容易。的。
让我们绘制一些提交,包括合并,以了解我们在这里的含义。请注意,每次提交都有一些难以理解的哈希ID(1fc39a7
或deadc0d
或某些此类提交)。为了使事情更清楚,我们将为每次提交使用单个大写字母。另请注意,每个提交都有父提交,但具有两个父提交的合并除外。我们说每次提交都会回到"它的父母(或者,对于合并,父母复数):
... <-E <-F <-G <-K <-- master (HEAD)
\ /
H <-I <-J <-- origin/lorem-ipsum
此处K
是我们的合并提交,指向G
和J
。 G
是 最后一次提交master
的提交。名称master
现在表示(&#34;指向&#34;)此提交K
。名称origin/lorem-ipsum
指向提交J
。我们还将master
标记为HEAD
,注意这是我们现在已检出的分支。
完全删除 K
,我们可以使用git reset
。 git reset
命令可能具有相当大的破坏性,因此在使用它之前,请运行git status
以确保您无需担心会丢失。 (这是一个反复出现的主题:运行git status
。)确保您在master
之后,现在没有别的东西可以丢失,而且master
指向您 想要失败的合并提交K
:
git reset --hard master~1
~1
后缀告诉Git找到master
指向的提交,然后向后移动一步。也就是说,按照K
中出现的箭头。如果有两个箭头 - 那么,因为K
是一个合并 - Git应该遵循 first 一个,它总是指向master
上的提交的那个只是之前我们做了合并。所以Git按照箭头提交G
。
(另一种方法是使用git log
查找提交G
的实际哈希ID,并运行git reset --hard <hash-id>
。虽然输入更难,但是剪切和粘贴应该可以正常工作。但是我认为,这个&#34;退回1&#34; ~1
更容易。)
git reset --hard
做了三件事:
更改分支以指向所选提交。这意味着master
现在命名提交G
,而不是K
:
...--E--F--G <-- master (HEAD)
\
H--I--J <-- origin/lorem-ipsum
(这次我省略了内部箭头,因为他们很难画画而且不能给我们太多。K
发生什么事了?它还在那里,在你的存储库中,但它现在在回收站中,很难找到,Git通常不会再显示它。)
reset --hard
步骤还会重置Git的索引。我认为,Git的索引最好描述为&#34;在哪里构建下一个提交&#34;。在正常情况下,您希望索引与当前提交匹配,直到您开始编辑并git add
更改以进行新提交。所以这就是你想要的:你的索引匹配提交G
。
reset --hard
步骤还会重置您的工作树,即您以正常方式显示所有文件的位置,以便您可以使用或在他们。这会从K
中删除合并后的版本,并将其替换为G
中的版本,这也是您想要的版本。
现在好像合并从未发生过。
您的上游设置仍然可能是origin/lorem-ipsum
。
要更改当前分支的上游设置(仍为master
),只需运行git branch --set-upstream-to=new-upstream
即可。在这种情况下,您想再次将其设置为origin/master
,所以:
git branch --set-upstream-to=origin/master
现在您当前的分支(master
&#39; s)上游为origin/master
,因此git pull
表示&#34; fetch,然后与{{{}合并1}}&#34; -presumably你想要的。
origin/master
git pull
命令很方便。它是 ......但这种便利是一种陷阱。如果您知道自己正在git pull
后跟git fetch
,那么您就会知道如何撤消合并(并且有很多现有的SO答案)。
除此之外,无论如何使用git merge
通常会更好。那么你应该运行git rebase
,然后运行git fetch
。您可以让git rebase
为您执行此操作...但有时候, 。有时合并更好。当您了解更多Git时,您会发现merge-vs-rebase决定有时取决于您获取时获得的内容。在这种情况下,在看到获取的内容之前,如何提前决定是否要进行重组或合并?
我认为首先要学习单独的步骤会更好。然后,一旦你很好地了解它们,就可以决定只输入一个命令(git pull
)是否值得方便而不是偶然的头痛。到那时您也会知道默认情况下是要合并还是重新绑定,并且可以设置git pull
来执行此操作。
1 有些方法可以手动运行git pull
并非完全安全,但它们很难做到。你不会意外地得到这个。
2 您可以指示git fetch
使用git pull
作为第二步,而不是将git rebase
作为第二步。我认为,你所展示的,你没有这样做。
3 好吧,也就是说,提交是永久性的,直到你故意扔掉它们为止。然后他们最终被剩下的垃圾扔掉了,通过git merge
,垃圾收集器,之后一段合适的等待期,在此期间你可以从垃圾箱中恢复它们。