我以爲最近碰到的這個狀況應該不算少見,作一點總結。git
這個repository的流程是 remote master
分支受保護,不直接接受push,新增feature經過pull request合併到master
分支。web
某個組員本身的A分支中的P文件是舊版本,提交了pull request,因爲種種緣由沒有發現P文件的問題,結果合併到master
分支後,master
分支的P文件部分的代碼倒退回了N天前。我嘗試經過B分支(最新P版本)發起一個pull request,合併到master
試圖將P從新恢復到最新版本。但結果出乎意料,P仍然是舊版本。vim
問題出在git自身的三路合併(three-way merge)機制,若是base和X分支的某一部分代碼相同,但和Y分支不一樣,合併的結果就會採用Y分支不一樣的那部分
再加上以前我對git合併的一個誤區,覺得 merge conflicts 給出的結果涵蓋了兩個分支全部變更。事實上僅屬於單一分支的變更不會顯示。(本地除了用外部合併工具,還能夠git difftool --ours
or git difftool --theirs
or git difftool --base
)bash
如今用圖例來展現下合併的時間軸:工具
圖示:假設P5版本比P2新, M1是引入舊版本的合併, M2是我嘗試修復的合併:fetch
B: P5-----------------P5 / \ master: ---P5(M1 base)---P5(M2 base)---P2(M1)---P2(M2) \ / A: P2----------------------P2
在M2合併的時候,Git(包括GitHub上處理合並衝突的webIDE)生成的衝突文件不會顯示僅由P2改動的區域。code
目前我發現的解決方法只能經過外部合併工具(git mergetool
)好比Kaleidoscope, Beyond Compare, vimdiff或者JetBrains家自帶的衝突處理工具才能完整看到哪些是僅僅被P2改動的部分。
但彷佛GitHub的pull request不支持用外部合併工具處理衝突。除非在GitHub處理衝突的webIDE上直接粘貼P5,想經過M2更新到P5無解。若是P2不單單包含舊版本,還有新增的feature,人工處理就會很麻煩。three
後來個人解決方法是:在本地用外部合併工具解決衝突後,再提交pull request。
具體操做:從M1 pull到了B分支(這樣一來base就變成M1),在本地經過外部合併工具修復回P5(或者git checkout --ours path/to/P
),再發pull request合併到master
。
還有種方法就是 pull master
後,在本地把B分支合併到master
(經過外部合併工具修復回P5),用管理員權限push到 remote master
。rem
GitHub上pull request的Resolve conflicts
慎用
本地git生成的衝突文件慎用。
鑑於以上幾點,從此pull request出現衝突時,能夠採用以下流程:
(假設pull request對應的分支是feature
)get
feature
fetch到本地,把 remote master
合併到該分支(能夠先fetch master
,再合併到本地feature
,或者直接把 remote master
pull到本地的feature
),再用外部合併工具解決衝突,而後push,這時候pull request上顯示能夠合併,直接點Merge按鈕便可。master
不受保護或者可使用管理員權限強行push,則還能夠在本地 pull master
後,把feature
合併到master
,再 push master
到GitHub。https://www.git-tower.com/lea...
https://stackoverflow.com/que...
https://git-scm.com/docs/git-...