Git兩個分支改同一段怎麼解:看懂衝突標記與回復

兩個分支都改了同一段首頁標題,Git 合併時停下來,檔案多出幾行箭頭和等號。先不要把其中一半刪掉就提交:衝突標記只是指出兩邊不能自動合併,最後要保留的內容,仍得按頁面需求決定。

這裡以一般 git merge 的文字衝突為例,用兩個本機分支修改同一個 index.html 標題。沒有遠端推送,也不涉及正式網站部署;你可以先在自己的練習 repository 看一次完整流程,再處理實際團隊分支。

合併前先認清分支與尚未保存的修改

先確認目前所在分支,以及工作目錄和索引是否有尚未提交的變更:

git branch --show-current
git status --short
git diff
git diff --cached

分支位置只能保留已提交的內容,不能代替未提交檔案的備份。若還有自己的修改,先按專案方式保存再合併。Git 官方提醒,帶著複雜的未提交修改開始 merge,事後 abort 有時無法完整重建原狀;不要把中止指令當作一定能救回所有工作的保證。

本例合併前是乾淨的 codex/main。另一個 codex/topic-label 分支也已提交自己的修改,兩邊都從同一個原始標題「精品教程」分出來,不是其中一邊只多了幾個可直接快轉的提交。

三個標記指出兩份候選內容

在 codex/main 執行:

git merge codex/topic-label
git status --short

Git 真的停在內容衝突,status 顯示 UU index.html。示例檔案的衝突區如下:

<<<<<<< HEAD
<h1>精品教程:新手先讀</h1>
=======
<h1>精品教程:按主題分類</h1>
>>>>>>> codex/topic-label
<p>選擇需要的教學。</p>

在這次普通 merge 中,HEAD 上方那段是目前 codex/main 的「新手先讀」;等號下方是合進來的 codex/topic-label「按主題分類」。最下方的分支標籤幫你辨認另一邊。不要把它理解成上面一定正確、下面一定應刪。

同一個檔案可能有多個衝突區,某些段落則已經由 Git 自動合併。先讀完整檔案及相關差異,確認標題旁的連結、結構與說明是否還一致;只盯著一對箭頭,有時會留下另一處衝突或重複內容。

若你的工具採 diff3 樣式,還可能顯示共同祖先的內容。那是用來理解兩邊各自改了什麼,不是第三份要全部貼進結果的候選版本。這篇的實際示例採上面的普通雙邊標記。

兩段文字仍看不出修改意圖時,在尚未 add 的衝突狀態,可以查看索引保存的三個版本:

git show :1:index.html
git show :2:index.html
git show :3:index.html

這次普通 merge 的第一份是共同祖先「精品教程」,第二份是目前 HEAD 的「新手先讀」,第三份是合進來的「按主題分類」。比較共同祖先,才能知道兩邊各增加了什麼,而不是把整個檔案視為互相取代。

這些冒號版本是未合併索引的階段資料,不是每個檔案隨時都有三份。完成解決並 add 後,再用 cached 差異查看準備提交的版本。本文沒有把這套 HEAD/合入分支的標籤直接套到 rebase;遇到另一種操作,先認清正在進行的 Git 流程。

解衝突,是決定最後的意思

先問兩邊修改者想解決什麼問題。本例一邊想引導新手,一邊想強調分類入口;示例決定把標題整理成一句,而不是把兩個 h1 原封不動並排:

<h1>精品教程:新手先讀,按主題分類</h1>
<p>選擇需要的教學。</p>

修改後,把整組標記移除,留下有效 HTML。這個合併文字只是示例的需求決定;真實網站可能要保留其中一邊、改成標題與說明兩個元素,或採第三種寫法。不能以「Git 不再報錯」當作內容已符合產品需求。

也別先對整個檔案套用 ours 或 theirs,只因按鈕比較快。它可能一併丟掉衝突區以外、你本來想保留的修改。需要採用單邊內容時,先核對影響範圍及另一邊的意圖,再決定如何處理。

檢查工作檔,再檢查準備提交的版本

示例修正後依序執行:

git diff --check
git diff -- index.html
git add -- index.html
git diff --cached -- index.html
git status --short

diff --check 可提醒差異中的衝突標記或空白問題;它不是 HTML 語法或功能測試。仍要查看最終 HTML,確認只有一個預期標題,再在相應頁面或專案檢查它是否能正常使用。

git add 表示把這個檔案的解決結果放進索引,不是告訴 Git 隨便選一邊。add 後再看 cached 差異,因為下一個 commit 保存的是索引中的版本;若你之後又修改工作檔,尚未 add 的內容不會自動跟著提交。

有其他衝突檔案時,逐個處理。不要只因 index.html 已暫存,就以為整次 merge 已完成。全部核對後再完成合併提交:

git commit -m "Resolve tutorial heading"
git status --short

這個真實本機示例最後產生有兩個 parent 的 merge commit,工作目錄乾淨,標題是決定後的合併句。它確認 Git 層的合併已完成;網站內容與功能仍要按專案需要檢查,不能把提交成功當正式部署完成。

不確定要留哪邊,可以先中止

如果需求還沒談妥,而且 merge 尚未完成提交,先保存你想留下的衝突處理草稿,再執行:

git merge --abort
git status --short

另一份乾淨的本機案例先產生同樣 UU 衝突,再 abort。HEAD 回到合併前的提交,index.html 回到目前分支原本的「新手先讀」,status 也恢復乾淨;另一個分支已提交的「按主題分類」仍然存在,沒有被中止操作刪掉。

abort 是嘗試回復合併前狀態,不是替你保存尚未提交的衝突解法。若開始前已有修改,或中途又改了其他檔案,先核對並保存必要內容;命令失敗時不要接著硬重設整個工作目錄。

提交後的回復,另看是否已分享

merge commit 已經完成,merge --abort 就不是撤回那次提交的方法。先確認提交是否已經被其他人或部署流程使用,再按團隊約定安排新的回復變更。不要為了把圖形變回原樣,就直接重寫大家共用的歷史。

交接時保留衝突檔名、兩邊修改目的、最後採用的內容及檢查結果。下次有人看到同一段修改,就能理解為什麼合併成這樣;比只留一句「已解衝突」更容易核對。

參考資料

Git:merge、衝突標記、解決與中止
Git:工作目錄、索引差異與 diff --check
Git:狀態與衝突檔案
原文鏈接:https://wntheme.com/git-merge-conflict-resolution/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?