合併發生衝突了,怎麼辦? - 為你自己學Git | 高見龍

文章推薦指數: 80 %
投票人數:10人

git merge dog Auto-merging index.html CONFLICT (content): Merge conflict in index.html ... 這問題看來是溝通不良造成的,所以遇到問題,當然是解決有問題的人… 讓您精通業界最常用Git版本控制!Git線上直播課程熱烈報名中現在就報名!學員評價 為你自己學Git 目錄 勘誤表 電子書 單元劇 面試題 系列文章 練習場 關於我 ←上一章:另一種合併方式(使用rebase) 下一章:【冷知識】為什麼大家都說在Git開分支「很便宜」?→ 合併發生衝突了,怎麼辦? Git有能力幫忙檢查簡單的衝突,所以並不是改到同一個檔案就一定會發生衝突,但改到同一行就沒辦法了。

假設我在cat分支修改了index.html的內容如下:

首頁
我是Cat
然後在dog分支剛好也修改了index.html,內容如下: 首頁
我是Dog
這時候進行合併,不管是一般的合併或是使用Rebase進行合併,都會出現衝突,我們先使用一般的合併: $gitmergedog Auto-mergingindex.html CONFLICT(content):Mergeconflictinindex.html Automaticmergefailed;fixconflictsandthencommittheresult. Git發現那個index.html檔案有問題了,我們先看一下目前的狀態: $gitstatus Onbranchcat Youhaveunmergedpaths. (fixconflictsandrun"gitcommit") (use"gitmerge--abort"toabortthemerge) Changestobecommitted: newfile:dog1.html newfile:dog2.html Unmergedpaths: (use"gitadd..."tomarkresolution) bothmodified:index.html 說明一下: 對cat分支來說,dog1.html跟dog2.html是新來的檔案,但已被放置至暫存區。

但是index.html這個檔案因為兩邊都修改到了,所以Git把它標記成「bothmodified」狀態。

使用SourceTree來看: 可以看到那個有衝突的檔案用驚嘆號標記出來了。

解決問題 看看那個index.html的內容長什麼樣子: 首頁 <<<<<<我是Cat =======
我是Dog
>>>>>>>dog Git把有衝突的段落標記出來了,上半部是HEAD,也就是目前所在的cat分支,中間是分隔線,接下是dog分支的內容。

那要解決這個問題?這問題看來是溝通不良造成的,所以遇到問題,當然是解決有問題的人…不是,是把兩邊的人請過來討論一下,到底是該用誰的code。

經過一番討論後,決定還是要採納cat分支的內容,順便把那些標記修掉,最後內容如下: 首頁
我是Cat
修改完後,別忘了把這個檔案加回暫存區: $gitaddindex.html 然後就可以Commit,完成這一回合: $gitcommit-m"conflictfixed" [cata28a93c]conflictfixed 如果是使用Rebase的合併造成衝突? 衝突這回事,不管是一般合併或是Rebase,會打架就是會打架,不會因為合併方式而就不會衝突。

但Rebase的過程如果發生衝突會跟一般的合併不太一樣。

例如: $gitrebasedog First,rewindingheadtoreplayyourworkontopofit... Applying:addcat1 Applying:addcat2 Applying:add123 Applying:updateindex Usingindexinfotoreconstructabasetree... M index.html Fallingbacktopatchingbaseand3-waymerge... Auto-mergingindex.html CONFLICT(content):Mergeconflictinindex.html error:Failedtomergeinthechanges. Patchfailedat0004updateindex Thecopyofthepatchthatfailedisfoundin:.git/rebase-apply/patch Whenyouhaveresolvedthisproblem,run"gitrebase--continue". Ifyouprefertoskipthispatch,run"gitrebase--skip"instead. Tocheckouttheoriginalbranchandstoprebasing,run"gitrebase--abort". 這時候其實是卡在一半,從SourceTree可以看得更清楚: HEAD現在並沒有指著任何一個分支,它現在有點像是在修改歷史的時候卡在某個時空縫隙裡了(其實是3a5a802這個Commit)。

看一下目前的狀態: $gitstatus rebaseinprogress;ontoed06d49 Youarecurrentlyrebasingbranch'cat'on'ed06d49'. (fixconflictsandthenrun"gitrebase--continue") (use"gitrebase--skip"toskipthispatch) (use"gitrebase--abort"tocheckouttheoriginalbranch) Unmergedpaths: (use"gitresetHEAD..."tounstage) (use"gitadd..."tomarkresolution) bothmodified:index.html nochangesaddedtocommit(use"gitadd"and/or"gitcommit-a") 訊息寫著rebaseinprogress,而且那個index.html的確也是被標記成「bothmodified」狀態。

跟上面提到的方法一樣,把index.html有衝突的內容修正完成後,把它加回暫存區: $gitaddindex.html 搞定,接著繼續完成剛剛中斷的Rebase: $gitrebase--continue Applying:updateindex 這樣就算完成Rebase了。

那如果不是文字檔的衝突怎麼解? 上面的index.html因為是文字檔案,所以Git可以標記出發生衝突的點在哪些行,我們用肉眼都還能看得出來大概該怎麼解決,但如果是像圖片檔之類的二進位檔怎麼辦?例如在cat分支跟dog分支,同時都加了一張叫做cute_animal.jpg的圖片,合併的時候出現衝突的訊息: $gitmergedog warning:Cannotmergebinaryfiles:cute_animal.jpg(HEADvs.dog) Auto-mergingcute_animal.jpg CONFLICT(add/add):Mergeconflictincute_animal.jpg Automaticmergefailed;fixconflictsandthencommittheresult. 這下糟了,要把兩邊的人馬請過來,討論到底誰才是最可愛的動物。

討論後決定貓才是這世上最可愛的動物,所以決定要用cat分支的檔案: $gitcheckout--ourscute_animal.jpg 如果是要用對方(dog分支),則是使用--theirs參數: $gitcheckout--theirscute_animal.jpg 決定之後,就跟前面一樣,加到暫存區,準備Commit,然後結束這一回合。

如果使用SourceTree,可在那個有衝突的檔案上按滑鼠右鍵,選擇「ResolveConflicts」→「ResolveUsing‘Mine’」等同於上面使用--ours參數的效果: 如果是選擇「ResolveUsing‘Theirs’」則等同使用--theirs參數。

←上一章:另一種合併方式(使用rebase) 下一章:【冷知識】為什麼大家都說在Git開分支「很便宜」?→ Comments


請為這篇文章評分?