为什么git pull提供合并的机会,但git push没有?

时间:2017-07-13 01:21:20

标签: git

(我在下面描述的内容都发生在当地的git repo中进行实验。不涉及远程回购。)

我创建了2个本地分支lb1lb2。它们从同一个提交节点开始。

git branch lb1
git branch lb2

我把它们放在彼此的上游。如下:

$ git checkout lb2
Switched to branch 'lb2'

$ git branch -u lb1
Branch lb2 set up to track local branch lb1.

$ git checkout lb1
Switched to branch 'lb1'

$ git branch -u lb2
Branch lb1 set up to track local branch lb2.

然后我通过对每个进行不同的更改来使它们分歧。如下图所示:

enter image description here

$ git branch -vv
* lb1    6774aa6 [lb2: ahead 1, behind 1] lb1 change
  lb2    cdd1247 [lb1: ahead 1, behind 1] lb2 change

我目前正在lb1。然后我试图将一个分支(lb1)推到另一个分支(lb2),看看会发生什么:

$ git push . lb1:lb2
To .
 ! [rejected]        lb1 -> lb2 (non-fast-forward)
error: failed to push some refs to '.'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

因此,如果我理解正确,则表示推送分支提示lb1)位于其远程对应lb2)之后。我必须首先结帐lb1并从lb2拉出来整合lb2的更改。

所以我这样做:(注意我现在在lb1分店)

$ git pull
From .
 * branch            lb2        -> FETCH_HEAD
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
Automatic merge failed; fix conflicts and then commit the result.

所以git pull让我有机会合并。

合并后,我可以将lb1推送到lb2

$ git push . lb1:lb2
Total 0 (delta 0), reused 0 (delta 0)
To .
   cdd1247..2dfb555  lb1 -> lb2

修订图如下:

enter image description here

lb2的更改已添加到lb1的日志历史记录中:

enter image description here

总结:

  • lb1 - push - > lb2:失败
  • lb1< - pull - lb2:合并的机会

我的问题是:

为什么git push没有机会合并?从英语的角度来看,我认为pushpull是对称的。所以我希望他们得到相同的结果。

3 个答案:

答案 0 :(得分:4)

我认为当他们提到git pull实际上是两个不同操作的便利符号时,@ dunni在评论中击中了钉子(即将钉子合并到了棋盘中)。我将从你的问题断言中挑战的是git-pullgit-push对称。可能更准确地说明git-fetchgit-push对称。当然,正如你所说,在英语中,推拉是非常确实相互对立的;但是,这并不一定意味着它们在其他领域的使用是对称的。

至于为什么git的实现者决定让pull尝试自动注射,我只能推测。我的理论是,因为工作回购具有跟踪分支这样的概念,所以有意义的是将远程跟踪分支自动合并到本地分支中以执行拉取操作。这是因为您必须进行合并/快进,才能在非分离的HEAD状态下使用更新。存储库必须保持这种分离,以便了解远程提交的内容与本地提交的内容。但是,远程裸存储库没有跟踪分支这样的概念:它只是在后端运行git-receive-pack时更新其引用。它并不关心引用的提交;这就是强迫推(git push -f)存在的原因。实际上,强制推送甚至不是git-pack-protocol中的构造,而只是客户端选项忽略正常检查以保持历史记录不变。当您推送时,您并不意味着需要合并/快进:您只是暗示远程及其refs列表上的对象数据库的更新。在客户端,只需更新远程跟踪分支以匹配您成功推送的内容(无论是否强制)。

总结:fetch需要合并,因为必须将获取的远程跟踪分支合并到相应的本地分支中,以便在工作存储库中使用。然而,推动你可能不一定需要合并;你只是更新远程分支。

答案 1 :(得分:1)

你可能最好在git maiilist中问它,但是有一个重要区别:pull执行的合并仍然是你个人历史的一部分。您可以在合并之前测试它,或更新合并消息,或改变主意并重置为提交。你可以花时间解决冲突。

如果git push正在合并,则此自动合并提交将立即成为公共历史记录的一部分。它也会导致同步问题,以防有人在同一时刻推送,并且合并需要解决冲突或写提交消息。

实际上,我有script试图实现它,但我不能说我已经看到了很多关于它的反馈。现在,人们习惯于使用大多数个人功能分支,并且仅在服务器合并拉取请求时才进行合并。

答案 2 :(得分:0)

并入合并意味着您的本地分支保持其历史记录完整,并且其他提交堆叠在顶部。您拥有本地结果,可以在其他任何人不受影响之前对其进行测试。如果您不喜欢结果,请弹出堆栈中的委员会。

如果在一次推送中发生合并,则遥控器将获得前所未有的结果。然后,有人将不得不检索它甚至知道状态是什么。然后,必须对其进行测试。所有其他团队成员都可以接触到它。这只是一个可怕的场景。仅在回购是个人唯一关心的问题且没有相应的CD的情况下,这才有意义。