Github - 如何从错误的分支恢复拉动

时间:2017-05-11 19:30:48

标签: git github git-shell

我不小心从一个不同的分支拉了一下,改变了HEAD的说法:

HEAD is now at 7c0208906 Merge remote-tracking branch 'refs/remotes/origin/lorem-ipsum'

现在,它不断从origin/lorem-ipsum而不是origin/master

被拉的文件也带来了冲突。现在已经过了几天,主分支机构中的其他人已经对主分支进行了新的更改,而我已经落后了。

如何将我的存储库的状态恢复为错误提取之前的状态,如何将HEAD简单地转移到以前的状态?

请帮助,我被困住了!

1 个答案:

答案 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 statusgit branch -vv的输出,所有这些都是有用的线索 - 那么需要修复master的上游设置。

在我们进入下一步之前,还有一件事需要注意:

  

被拉的文件也带来了冲突。

记住Git不会提取文件非常重要。 Git获取,然后合并,提交。提交有文件,合并一些提交可能会导致文件冲突,所以这可能看起来像一个小问题,但它影响如何你恢复这些东西。

发生合并冲突时,必须自己解决冲突的文件,git add结果,并做最后的git commit进行合并提交。 (当你没有得到合并冲突时,Git会为你添加并提交结果。)git status命令 非常 很有用,因为它会告诉你,如果你正处于冲突合并的中间,还有很多其他好的信息。经常使用它。

摆脱不良合并

如果您处于错误合并的中间并且您希望整件事情消失,那很简单:只需运行git merge --abort即可。这会停止合并过程并将所有内容恢复到开始之前的状态。

如果你已经完成合并,但它很糟糕而且你想摆脱它,那就更难了,因为你或Git完成了合并进行新的提交,提交的全部内容是它们是永久性的,不变的。提交坚持"永远", 3 并且新的提交建立在先前的提交之上,因此它真的很难摆脱&# 34;中间"一。摆脱一些" end"更容易。的。

让我们绘制一些提交,包括合并,以了解我们在这里的含义。请注意,每次提交都有一些难以理解的哈希ID(1fc39a7deadc0d或某些此类提交)。为了使事情更清楚,我们将为每次提交使用单个大写字母。另请注意,每个提交都有提交,但具有两个父提交的合并除外。我们说每次提交都会回到"它的父母(或者,对于合并,父母复数):

... <-E <-F <-G <-K   <-- master (HEAD)
       \         /
        H <-I <-J   <-- origin/lorem-ipsum

此处K是我们的合并提交,指向GJG 最后一次提交master的提交。名称master现在表示(&#34;指向&#34;)此提交K。名称origin/lorem-ipsum指向提交J。我们还将master标记为HEAD,注意这是我们现在已检出的分支。

完全删除 K,我们可以使用git resetgit 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做了三件事:

  1. 更改分支以指向所选提交。这意味着master现在命名提交G,而不是K

    ...--E--F--G   <-- master (HEAD)
          \
           H--I--J   <-- origin/lorem-ipsum
    

    (这次我省略了内部箭头,因为他们很难画画而且不能给我们太多。K发生什么事了?它还在那里,在你的存储库中,但它现在在回收站中,很难找到,Git通常不会再显示它。)

  2. reset --hard步骤还会重置Git的索引。我认为,Git的索引最好描述为&#34;在哪里构建下一个提交&#34;。在正常情况下,您希望索引与当前提交匹配,直到您开始编辑并git add更改以进行新提交。所以这就是你想要的:你的索引匹配提交G

  3. reset --hard步骤还会重置您的工作树,即您以正常方式显示所有文件的位置,以便您可以使用或在他们。这会从K中删除合并后的版本,并将其替换为G中的版本,这也是您想要的版本。

  4. 现在好像合并从未发生过。

    您的上游设置仍然可能是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,垃圾收集器,之后一段合适的等待期,在此期间你可以从垃圾箱中恢复它们。