`git checkout master && git merge feature`与反向操作的差异疑问
问题背景
请问git checkout master && git merge feature-branch与git checkout feature-branch && git merge master这两种操作有什么区别?
我阅读了相关回答但仍有困惑,由于权限限制无法在原问题下追问,故在此提出新问题。
假设执行git checkout master && git merge feature-branch,提交历史如下:
* Merge commit |\ | * First feature commit * | Third master commit |/ * Second master commit * First master commit
回答者的观点如下:
执行任何合并操作前,建议先fetch并pull,确保本地分支与远程同步。
将feature分支合并到master分支时,所有feature分支的变更会同步到master分支。
结果为:
feature分支不会发生变化。
master分支获得feature分支的所有变更。
但我们明确知道,merge commit有两个父节点:合并目标分支的最新提交,以及被合并分支的最新提交。
你可以在后添加数字来指定父节点;例如d9219702表示“d921970的第二个父节点”。该语法仅适用于有多个父节点的merge commit——merge commit的第一个父节点来自合并时所在的分支(通常是master),第二个父节点来自被合并的分支(比如topic)
《Pro Git》第223页
如果merge commit满足:
a) 包含master和feature的所有变更
b) 同时属于两个分支
那么我无法理解两种操作的区别。似乎两种操作下两个分支都会变化:feature获得master的变更,master获得feature的变更。我忽略了什么关键点?
核心区别:分支指针的移动对象不同
你忽略的最关键一点是:Git的merge操作只会修改当前你所检出的分支的指针,被合并的分支指针完全不会移动。merge commit并不会自动属于两个分支,它只属于指针指向它的那个分支。
1. 操作git checkout master && git merge feature-branch的实际效果
- 你当前处于
master分支,执行merge后,Git会在master分支上创建一个新的merge commit(即你历史里的Merge commit),它的第一个父节点是master原来的最新提交(Third master commit),第二个父节点是feature-branch的最新提交(First feature commit)。 - 执行完成后,
master分支的指针会移动到这个新的merge commit上,而feature-branch的指针仍然停留在First feature commit,完全没有变化。 - 此时,
master分支的历史包含了feature的所有变更,但feature分支的历史还是原来的路径:First master commit→Second master commit→First feature commit,完全不涉及merge commit和Third master commit。你可以用git branch --contains <merge-commit-hash>验证,只会看到master包含这个merge commit。
2. 操作git checkout feature-branch && git merge master的实际效果
- 你当前处于
feature-branch分支,执行merge后,Git会在feature-branch上创建新的merge commit,它的第一个父节点是feature原来的最新提交(First feature commit),第二个父节点是master的最新提交(Third master commit)。 - 执行完成后,
feature-branch的指针会移动到这个新merge commit上,而master分支的指针仍然停留在Third master commit,没有任何变化。 - 此时,
feature分支整合了master的所有变更,但master分支的历史完全没变,还是停留在原来的提交上,并没有获取到feature的变更。
为什么merge commit不会同时属于两个分支?
一个commit属于某个分支的前提是:该分支的指针可以通过父节点链回溯到这个commit。只有当分支指针直接指向它,或者指向它的后代commit时,这个分支才会包含该commit。merge commit创建后,只有当前检出的分支指针会移动到它上面,被合并的分支指针不动,所以merge commit只属于当前分支,不属于被合并的分支。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev

