2

强烈推荐的做法是不要更改其他人将已拉取的其他地方的提交的历史记录。尽管如此,不理解这一点的人无论如何都会不可避免地这样做。从“其他用户”的角度来看,而不是从改变历史的人的角度来看,最好的恢复方式是什么?

这是一个使其具体的示例。

Ryan 创建了一些提交和推送:

ryan $ git init
ryan $ echo "initial stuff" > file.txt
ryan $ git add file.txt
ryan $ git commit -m "Initial commit" 
ryan $ echo "more stuff" >> file.txt
ryan $ git add file.txt
ryan $ git commit -m "More stuff"
ryan $ git remote add origin [some url]
ryan $ git push origin

Joe 克隆了 github 存储库

joe $ git clone [some url]

至此,一切都好,那么……

Ryan 更改了最后一次提交:

ryan $ vi file.txt
ryan $ git add file.txt
ryan $ git commit --amend -m "More stuff"
ryan $ git push origin
       [Fails]
ryan $ git push -f origin master

请注意,Ryan 在失败后进行了强制推送。如果他是唯一一个从原点撤离的人,这很好,但在这种情况下,他只是把乔搞砸了。

乔试图拉:

joe $ git pull origin
      [Conflict!]

现在这是一个非常简单的示例,但 Joe 可能不熟悉file.txt并且会发现很难合并更改。

再一次,我明白问题的根源是瑞恩做了坏事。但尽管如此,我正在寻找 Joe 和他的队友无需进行合并提交即可从中恢复的方法。

我知道一个技巧是删除远程分支的本地副本,然后从源重新检查它。但当然,这只有在您没有任何更改的情况下才有效。乔很可能做出了一些他自己想要做出的新改变。

想法?

4

2 回答 2

2

您需要在重写之前保存原始提交(或者您可以在之后找到它,但之前更容易)

git branch save_point origin/master (before fetch)

然后进行提取,这不会改变

git fetch

现在,Joe 存储库中尚未在 master 上的所有提交都需要重写/重新基于来自 origin 的重写提交

git rebase --onto origin/master save_point master

如果不同分支上的更改不相关,这应该可以正常工作。

您可以在手册中阅读有关此内容的信息,但理解起来并非易事。

于 2013-10-25T19:23:45.750 回答
1

绘制提交图。这是瑞恩的原话:

A - B

A是“初始提交”并且B是第一个“更多内容”。

乔得到了这个并开始工作。假设他也添加了一个 commit C,这样我们在 Joe 的图表中就有了更多的东西:

A - B - C

与此同时,瑞恩去修改和强制推进。这将创建:

A - B
  \
    B'

B'“修改后的”提交在哪里。

如果 Joe 现在进行 fetch(或 pull,当然会进行 fetch),他会得到以下结果:

A - B - C       <-- HEAD=master
  \
    B'          <-- origin/master

基本上,他还是有原版的B

为了恢复,Joe 需要将他的提交(在这种情况下,只是C)重新设置为新的origin/master提交,B'.

如果 Joe 使用git pull --rebase, git 会做一些聪明的事情:它可以告诉提交B 曾经是的提示提交origin/master,因此,只有提交C需要重新设置。

如果 Joe 使用git fetch(或git pull不使用--rebase),git 将更新origin/master为指向B'并更难找出B'对应于B. (在这些简化的手绘图中很容易看到,但在实际的 git commit DAG 中更难看到事后。)但是,如果 Joe 能够识别“他的”与“他们的”,尽管 Ryan 的残酷的把戏:-),他可以做同样的变基。

(我发现一个简单rebase -i的通常就足够了,因为我通常可以从“他们的”中分辨出“我的”提交并删除相应的pick行。)

(编辑:请参阅Andreas Wederbrand 对内部功能的回答pull --rebase它正在使用. 它以通常的方式获取任何拉动,并且它从步骤之前的内容中知道SHA - 1 。)rebase --onto upstream start_after branchupstreambranchstart_afterorigin/branchpull --rebase

于 2013-10-25T19:15:25.960 回答