Git重置和强制推送

4

状态:正在学习 git。

我在两个系统之间进行以下操作:

系统 1

git reset --hard "SHA Key"  
git push origin master # fails  
git push -f origin master # succeeds  

System 2

git pull origin master

我收到了这条信息“已经是最新的了。”

为什么系统1中的更新/重置没有在系统2中反映出来呢?


在System 2上,执行git fetch命令,然后在两个系统上比较git rev-parse origin/mastergit rev-parse master。它们是否完全相同? - cmbuckley
1
在两个系统上都执行 git branch -vv 命令以查看跟踪分支的设置。可能其中一个系统中,master 分支跟踪的是其他分支而不是 origin/master,或者根本没有进行跟踪。 - Cristian Lupascu
更多关于跟踪分支的详细信息请参见此处:http://git-scm.com/book/zh/v2/Git-分支-远程分支#跟踪分支 - Cristian Lupascu
2
System 1 中的 origin 是什么?它是 System 2,反之亦然吗?您是指向第三个共同位置吗? - John Szakmeister
1
@jszakmeister 的观点很好。运行 git remote -v 以查找。 - Cristian Lupascu
源代码在系统1和系统2中都存储在Github仓库中。 - Subramanian
2个回答

5
原因可能是您回退了主分支。您从这里开始:

原因可能是您回退了主分支。您从这里开始:

A --- B --- C --- D

变成这样:

A --- B --- C

System 2 的本地主干分支仍然看起来像第一张图片,从 Git 视角来看,它包含了 origin 主干的所有历史记录,因为您的本地分支已经包含了提交 A、B 和 C。

我发现最好的解释方式是在 Git 中有三个视图:

1) 您的本地分支。这是您通常检出并操作的内容。 2) 远程分支。这些是远程存储库上实际的分支。 3) 您对远程分支的本地快照。这些可以在 refs/remotes 下找到。它是您上次拉取时可用于远程存储库的分支的副本。

当您执行以下操作时:

git reset --hard "SHA Key"

你影响了本地主分支。这意味着:
git push -f origin master

已经更新第2点和第3点。我的意思是远程仓库已经被更新(refs/heads/master已指向新的提交)。同时,本地的refs/remotes/origin/master也被更新以匹配您的推送。

在第二个系统中,执行以下操作:

git pull origin master

说的是从远程主干获取任何更新并将其应用于本地分支。由于此操作的结果,3)也会更新。 refs / remotes / origin / master 现在将指向远程服务器对主分支拥有的相同提交。但是,从Git的角度来看,您已经在System 2的本地主分支上拥有了所有提交。你只是碰巧有这个其他的提交D,它继承自A,B和C的历史记录。换句话说,现在看起来像的是System 2有一个额外的提交D。 Git不会回滚您的分支并使您失去该工作-它不理解您想要在哪里消失。它只了解集合(如数学种类)。您已经进行了修订,因此您是最新的。

顺便说一下,这就是为什么您随处可见警告不要强制推送与他人共享的分支的原因。倒带主分支需要团队协调,在足够大的组中,这根本是不可行的。某人不会意识到发生了什么,提交将重现。或者,别人会在之间提交,导致他们的推送失败,然后他们拉动,导致看起来有点傻的历史,但提交仍将返回。

如果D导致问题,并且您已经与世界共享了它,那么git revert D 是更好的选择。它不会遇到这些问题,但它意味着现在在您的历史记录中进行了还原。它还意味着D仍然在主分支的集合中,只是有一个-D来撤消它。这还有其他一些影响,但这可能太多了,不直接与您的问题相关。

此外,如果System 1指向System 2,反之亦然,则我很惊讶Git没有关于不更新远程分支或工作树的警告。 git push 不会更新另一台机器上的工作树,并且它并不介意让您知道这一点。如果失败了,那么很可能是一个错误。


感谢详细的解释,我已经理解了大部分。这个链非常长 - A -> B -> C -> ------ R -> S。我在系统1中从S重置到C。那么撤销操作[git revert C]是解决方案吗?还是需要要求团队在继续之前手动恢复到“C”? - Subramanian
在这种情况下,“git revert C”绝对是您想要的。 “git reset --hard B”会导致您失去C到S,我确定您不想这样。 :-) - John Szakmeister

0

你将分支的HEAD重置为旧的提交,然后将其作为该(主)分支的HEAD推送。

另一个存储库已经有了那个旧的提交,所以当你执行git pull时,它会显示已经是最新的 - 它已经有了这个提交。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接