什麼是合併衝突?
我們將在此處討論合併衝突解決如何協助開發人員,從兩個重疊的來源產生最佳結果。
GitHub 流程
除了提供共同作業軟體開發的平台,GitHub 也提供規定的工作流程,此工作流程的設計旨在最佳化其各種使用功能。 雖然本單元專門討論合併衝突,但還是建議您先檢閱了解 GitHub 流程。
合併分支
請考慮下列案例:開發人員根據 main
建立名為 feature-branch
的分支,並建立兩個認可。 隨著此工作進行,其他人會將不相關的提取要求合併到 main
。 當開發人員嘗試將 feature-branch
合併回 main
時,會發生什麼事?
答案:視情況而定。
儘管 feature-branch
是從 main
建立的,但並不是以分支本身為基礎。 而是以當時 main
的「HEAD 認可」為基礎。 其不會知道從那時起已套用到 main
的所有認可。 其目前追蹤的認可不一定會在未覆寫最近變更的情況下摺疊成分支的目前狀態。
如果事實證明自從建立分支以來,feature-branch
認可不會與對 main
所做的平行認可重疊,則不會有任何問題。 您可以新增檔案。 您可以刪除未受影響的檔案。 已在 main
中變更的程式碼行可以在 feature-branch
中變更,只要平行工作未在建立 feature-branch
之後變更那些程式碼行即可。
但是,如果這兩組認可同時包含對相同程式程式碼行所做的變更,該怎麼辦? 此合併嘗試會因為合併衝突而失敗。
什麼是合併衝突?
當開發人員嘗試合併會不小心覆寫平行變更的變更時,就會引發合併衝突。 如何將那些其他變更合併到基底分支的方式並不重要。 Git 將不會自動覆寫一組支持其他變更的變更。 相反地,會向嘗試合併的人員指出那些變更,讓人員能夠在比較分支上解決變更,然後再次嘗試合併。
解決合併衝突
為了協助您解決合併衝突,GitHub 會產生一個混合式暫存檔案,其中包含每個分支的差異。 此慣例是比較分支中的文字會顯示在基底分支上方,並利用一行等號 (=======
) 來分隔。
如果變更是次要的,您就能使用此檢視直接編輯檔案。 如果您決定保留最終結果,則會將其認可到比較分支。 或者,如果合併比較複雜,您可能想要使用其他開發工具來處理。 不論您使用哪種方式,請記得要先移除程式碼中的所有分支標記,然後再進行認可。 如果認可衝突解決時忘記移除這些標記,則標記會留在檔案中,而不會註解化。
注意
此單元將討論如何解決瀏覽器內容中的合併衝突。 還有許多開發平台 (例如 Visual Studio) 可提供整合的合併衝突解決體驗。
解決分支上的所有合併衝突之後,您就可以重試合併。
避免合併衝突
某些合併衝突是無法避免的。 任何合併可能都會針對其他等待核准的提取要求產生合併衝突。 不過,有一個降低合併衝突複雜度的有效方式是,經常提取您的分支。
及早並經常提取
git pull
命令會拉下任何尚未套用到最新分支的基底分支認可。 在概念上類似於取得最新版命令,許多版本控制系統使用此命令,讓您將本機程式碼更新為最新版本。 當您提取分支的更新時,即會合併在建立該分支 (或最後一次提取) 之後發生的所有變更。
將更新提取到您的分支可能會導致合併衝突,但這沒什麼問題。 無論如何,您都應該稍後再取得,但若早點取得,通常比較容易處理。
除了減輕合併衝突的影響,提取更新也可讓您在工作時,將認可的變更整合到分支。 這麼做可讓您儘早攔截潛在問題。 例如,其他檔案中的類別定義可能變更,導致無法再編譯程式碼。 此變更不會導致稍後合併時發生合併衝突,但如果不先測試,則無法組建。 最佳做法是經常提取更新,讓您的分支盡可能接近其基底。
使用 git rebase 整理歷程記錄
git rebase
(或 git pull --rebase
) 命令會重寫您的分支歷程記錄,以使用基底分支目前的 HEAD 認可作為基底。 換句話說,其會更新您的分支,使其行為如同只從基底分支的目前狀態分支。 此重訂基底表示您的所有變更都會與基底分支的最新狀態相比較,而不是與您原先從中分支的原始認可相比較。 因為認可依線性型態跟隨先前的平行認可,在最終合併之後,重訂基底可以使追蹤歷程記錄更容易。 最好先立即重訂分支的基底,然後再合併上游。
深入了解關於 Git 重訂基底 \(英文\) 和解決 Git 重訂基底之後的合併衝突 \(英文\)。