强制推送后修复历史

时间:2016-08-18 19:05:44

标签: git

我有一个裸git存储库B,我从中克隆了两个存储库C和D.然后我添加了一些更改为C,后来被推送到B,最后由D拉。所以一切都是同步的。

现在我想从C中删除最后一次推送的提交,所以我这样做:

$ git reset HEAD^ --hard
$ git push -f

(来自http://christoph.ruegg.name/blog/git-howto-revert-a-commit-already-pushed-to-a-remote-reposit.html

在D我做:

$ git pull

我输出如下:

[mkm@horklum git1]$ git pull
From /home/mkm/projects/git_tests/git1
 + a5d681f...c481973 master     -> origin/master  (forced update)
Already up-to-date.

git log给了我与之前完全相同的输出。我希望D上的历史与C上的历史相同。我从What and where does one potentially lose stuff when git says "forced update"?知道最后git pull将我的历史与服务器上已更改的历史合并,但它真的会发生什么?我希望历史在任何地方都能保持同步。

我知道我可以做git revert提交,这是在这样的场景中推荐的方法,但我想理解为什么在强制推送的情况下,历史不会在任何地方保持同步。

1 个答案:

答案 0 :(得分:3)

让我们尝试绘制存储库的历史记录(更高版本更旧):

commit 1   --> o <-- the initial commit
               |
              ...
               |
commit N-1 --> o <-- B and C are here now
               |
commit N   --> o <-- D is here

您在N上创建了一些提交(最多提交C),从B推送到D。所有三个repos都与指向commit master的{​​{1}}分支同步。 (如果您的分支未命名为N,则只需将其名称改为名称并继续阅读。

然后你强迫master的{​​{1}}分支返回提交master并检查出来(这是C的作用。)

此外,您强制N-1的{​​{1}}分支返回提交git reset --hard。这就是master在这种情况下的作用。

现在,提交BN-1git push -f存储库中不再存在。 1 就像您创建了提交一样N上的B .. C,将其推送到1,将其从N-1CBD同步)然后您在B上创建了提交C。从未在DN上创建提交D

然后您在N上运行B并且没有任何变化。这是因为在后台C运行git pull后跟D

git pull从远程存储库(git fetch)检索本地存储库中尚未存在的所有可执行提交。在这种情况下没有; git mergegit fetch上有一部分提交。它还了解B上分支的当前位置。

B发现本地仓库(D)是远程仓库(B)之前的一次提交,它无关。

为了使git merge看起来像D,您可以在B上运行D然后B。它将强制移动git fetch的{​​{1}}分支git reset --hard B/master D分支master然后将检查出来。它基本上执行了Dmaster所做的事情。

1 这不完全正确。提交仍然存在,但无法使用分支访问。这使得它成为将在下一个垃圾收集中删除的孤立提交。虽然它仍然存在于存储库中,但可以使用其哈希来访问它,并且可以通过创建指向它的分支来恢复它。