Git合並


一次合並會結合兩個或多個歷史提交分支。盡管Git還支持同時合並三個,四個或多個分支,但是大多數情況下,一次合並只結合兩個分支。

在Git中,合並必須發生在一個版本庫中------也就是說,所有要進行合並的分支必須在同一個版本庫中。版本庫中的分支怎么來的並不重要。

 

當一個分支中的修改與另一個分支中的修改不發生沖突的時候,Git會自動計算合並結果,並創建一個新的提交來表標識新的統一狀態。

但是當分支沖突時,Git並不解決沖突,所以,當Git無法自動合並時,需要在所有沖突都被認為解決后做一次最終提交。

 

1,一個最簡單的合並的例子

  

  創建一個新的版本庫,新建文件"file",添加圖片中的內容。然后提交到版本庫。

  

  

  ok,在當前分支 master 下繼續添加文件”other_file“,添加圖片中的內容,並提交到版本庫中。

  

  至此,版本庫里已經有一個包含連詞提交的分支 master,每次提交引入都引入了一個新文件。接下來,新建並切換到不同的分支。

  

  新的分支 alternate 基於 master^(master的前一次提交,本例中就代表master的初始提交,master~數字 代表是同一一個意思),在該分支下修改文件”file“,新增圖片中的內容,最后提交到版本庫中。

  

  現在就有了兩條分支,兩條分支都開始了自己的工作,都針對文件”file“進行了修改,因為這兩個修改並不影響相同文件的相同部分,所以合並應該會順利進行,不會發生事務。

  git merge 操作是區分上下文的。當前分支始終是目標分支,其他一個或多個分支之中是被合並到當前分支。現在想要 alternate 分支合並到 master 分支,所以在操作之前必須檢出 master 分支,然后再進行 git merge 操作。

  

  nice,合並順利進行,兩個分支對文件”file“的修改順利的合並在一起。然后來看看提交歷史:

  

  兩個分支在 53d24be 這個提交處分開(當時的 master 是提交了other file,所以分支基於的 master^ 就是"init 3 line in file"這個提交),分支修改了文件”file“,產生了一個提交 4a547440。最后執行提交產生一個新的提交 475e5e8 。

  可以看出,Git執行合並的操作都會產生一個合並后的提交,並添加到當前分支中,而被合並分支不受合並的影響。

 

2,有沖突的合並

  不廢話,直接來實際的操作。首先在 master 分支上,繼續修改文件“file”,然后提交到版本庫

  

  然后,切換到 alternate 分支上,用不同的內容修改文件“file”,然后也提交到版本庫

  

  

  

  繼續,檢出 master 分支並嘗試着進行合並

  

  Git已經提示我們了:合並的時候在文件“file”檢測到沖突,自動合並失敗,解決沖突后才能提交。一旦遇到沖突,一定要使用 git diff 命令來查看一下沖突的程度

  

  結果顯示了 工作區 和 暫存區 之間的差異。

  在傳統的 UNIX/Linux 系統中 diff 命令的輸出風格里,改變的內容顯示在<<<<<<<和=======之間;替代的內容在=======和>>>>>>>之間。

  在解決合並沖突時,根據實際工作情況自己選擇任何解決方案。包括只取一邊或另一邊的版本,或者兩邊的混合,甚至是全新的內容。

  ok,開始手動解決沖突,解決后。文件“file”的內容如圖,如果對沖突解決很滿意,那么就應該 git add 命令,為合並提交而暫存之。

  

  

  Git的提示已經很明顯了:沖突已解決,但是依然處於合並狀態(當前的分支為 master | MERGING),使用 git commit 命令來結束掉本次合並。執行 git commit 命令,Git會進入到vim編輯器中,並准備了一條模板消息。ok,搞定!

 

 

深入處理合並沖突

  重新初始化一個版本庫,創建一個文件“hello”,內容為“hello”,提交到版本庫中

  

  創建一個名為 alt 的分支,在文件“hello”末尾追加內容 world。然后提交到版本庫

  

  切回到 master 分支,此時文件”hello“的內容為 hello,在末尾追加 worlds,並提交大版本庫

  

  

  此時,hello的內容,master 分為 hello worlds,alt 分支為 hello world。嘗試合並 alt 分支,一定會發生沖突,Git提示文件”hello“里有沖突,使用命令 git status 查看當前狀態,Git會定位沖突的文件以及提示可以做的操作:

  1,Git提示我們有未完成的合並。

  2,建議我們解決沖突后運行 git commit 命令,又或者可以執行 git merge --abort 命令來取消本次合並。

  3,Git提示我們沖突發生在 hello 這個文件里。

  

  現在,使用 git diff 命令來檢查沖突的細節:

  

  這里的 alt 有一個特殊的名字------MERGE_HEAD,所以我們完全可以拿 HEADMERGE_HEAD 版本跟工作區("合並的")版本進行比較:

  

  在較新版本的Git中,git diff --ours 是 git diff HEAD 的同義詞,--ours 更好理解。同樣,git diff MERGE_HEAD 可以寫成 git diff --theirs

  在解決沖突的過程中,可以使用一些特殊的 git log 選項來幫助我們尋找出變更的確切來源和原因:git log --merge --left-right -p <file|path>git log 的選項如下

    --merge:只顯示根產生沖突的文件相關的提交。

    --left-right:如果提交來自合並的”左邊“則顯示<(”我們的“版本,當前分支的版本),如果提交來自由合並的”右邊“則顯示>(”它們的“版本,目標分支的版本)

    -p:顯示提交消息和每個提交相關聯的補丁。

    <file|path>:如果版本庫很復雜,且沖突的文件很多,可以指定確切的路徑或文件。

  

  可以看到,輸出的信息還是很多的。有一種手段可以緩解來自大合並中繁多的沖突的痛苦:那就是定義良好的小提交。Git對小規模提交處理的很好,因此沒有必要等到最后才提交一個又龐大又影響廣泛的修改小規模的提交和更頻繁的合並周期可以減少解決沖突的痛苦

  

  

  那么,Git是如何追蹤沖突的呢?

    主要有以下幾個部分:

    1,.git/MERGE_HEAD,任何使用提到 MERGE_HEAD,Git都知道去查看哪個文件。

    2,.git/MERGE_MSG,包含當前解決沖突后執行 git commit 命令是用到的日志消息。

    3,Git的索引項包含每個沖突文件的三個副本:合並基礎,”我們的“版本 和 ”他們的“版本,分別給這三個副本分配各自的編號 1,2,3。

    4,沖突的版本不保存在暫存區。只保存在工作區。

  

    查看Git索引項是如何存儲的,可以使用 git ls-files 底層。如果指向查看根沖突相關的文件,可以使用 -u 選項

    

    可以看出,hello 文件存儲了三次,用前面說過的 git cat-file -p 命令來查看各個版本的內容

    

    更可以使用 git diff 來比較兩個指定版本之間有什么區別

    

 

  了解了Git是如何追蹤沖突之后,就可以很淡定的處理沖突了。

  

  這里執行 git add 命令是把索引項重寫,只有一份 hello 的副本。

  必須解決索引中記錄的所有沖突文件。只要有未解決的沖突,就不能提交。因此,當解決一個文件的沖突之后,執行 git add(或者 git rmgit-update-index等)以清除它的沖突狀態。

  注意:不要對有沖突標記的文件執行 git add命令。雖然會清楚索引中的沖突,並允許提交,但是文件內容將是錯誤的。

  最終,執行 git commit 命令,解決沖突過程中產生的 .git/MERGE_HEAD .git/MERGE_MSG 都會被Git刪除。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM