2016-08-18 85 views
1

我有一个裸露的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

和DI做:

$ git pull 

和我得到的输出如下:

[[email protected] 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恢复提交,这是在这样的场景中推荐的aproach,但我想了解为什么在强制推送的情况下,历史将不会保持同步。

+0

我不认为在这种情况下恢复提交,即使*有意义*,因为你已经正式覆盖(并丢失)从C的角度提交。 – Makoto

+0

你不想做'git pull'因为它会合并您的本地更改。由于您只删除了最后一次提交并且在本地仍然有提交,这只是一个提升。所以'git pull'是你不“看到”这个变化的原因。 'git fetch'和'git reset --hard'更好地反映了这一点。保管和备份,因为这是版本控制,而不是备份。 – hakre

+0

@Makoto通过使用git-revert我的意思是完全取代'git reset HEAD^--hard; git push -f'。 – mike

回答

3

让我们试着画出你的资料库的历史(越高以上):

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

你创造了一些提交对C(最多提交N),推到B,从D拉。所有三个回购与他们的master分行同步指向承诺N。 (如果您的分支没有命名为master,那么只需输入它的名字并阅读)。

然后你强制master分支C回去承诺N-1并检查出来(这是什么git reset --hard做什么)。

另外,您还强制Bmaster分支返回承诺N-1。这是git push -f在这方面所做的。

现在,承诺NBC存储库中不再存在。 这是您创造上C的提交1 .. N-1,他们推到B,从D(有B,同步CD)拉它们,然后在你创建的D提交N。它似乎从未在BC上创建提交N

然后在D上运行git pull,没有任何变化。这是因为在后台git pull运行git fetch其次是git merge

git fetch从远程存储库(B)检索本地存储库中尚不存在的所有可重新提交的提交。这种情况没有; B具有D上的提交子集。它还了解B上分行的当前位置。

git merge发现本地回购(D)是远程回购(B)之前的一次提交,它无关。

为了使D样子B你可以D然后git reset --hard B/master运行git fetch。它将强制移动的master分支,其中的master分支然后将检查出来。它基本上做git reset --hard HEAD~1做的B


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

+0

现在其全部清楚:-) – mike