【學了就忘】Git分支 — 46.合併衝突(典型合併)

1、典型合併

繼續上面的前一篇文章的示例:

我需要繼續開發dev分支上的功能。

需求:

  1. 繼續修改dev.txt文件。
  2. 修改readme.txt文件,因爲該文件和master分支都有的文件,修改一下爲之後創造一個小衝突。

1)在dev分支繼續工作,並提交版本

# 1.查看工作目錄中文件狀態,非常乾淨
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git status
On branch dev
nothing to commit, working tree clean

# 2.查看版本庫提交歷史
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git log --oneline --graph --all
* 0690030 (master) 第5次提交,新增內容:branch test v4
| * 9eb3224 (HEAD -> dev) 第4次提交,dev分支開發 dev.txt文件
|/
* b97ccfd 第3次提交,新增內容:branch test v3
* f72a9fe 第2次提交,新增內容:branch test v2
* fa2439a 第1次提交,新增readme.txt文件

# 3.開始修改dev.txt文件和readme.txt文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ echo "dev new file v2 100%" >> dev.txt

L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ echo "branch test v4 dev 100%" >> readme.txt

# 4.提交到版本庫中
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git commit -a -m '第6次提交,修改dev和readme文件'
warning: LF will be replaced by CRLF in dev.txt.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in readme.txt.
The file will have its original line endings in your working directory
[dev e94af28] 第6次提交,修改dev和readme文件
 2 files changed, 2 insertions(+)

2)查看當前版本庫的歷史提交記錄

# 1.查看歷史提交記錄
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git log --oneline --graph --all
* e94af28 (HEAD -> dev) 第6次提交,修改dev和readme文件
* 9eb3224 第4次提交,dev分支開發 dev.txt文件
| * 0690030 (master) 第5次提交,新增內容:branch test v4
|/
* b97ccfd 第3次提交,新增內容:branch test v3
* f72a9fe 第2次提交,新增內容:branch test v2
* fa2439a 第1次提交,新增readme.txt文件

此時工作目錄的圖解如下:

3)把dev分支合併到master分支上

假設你已經開發完成新需求,並且打算將你的工作合併入 master 分支。

爲此,你需要合併 dev 分支到 master 分支,這和之前你合併 hotfix 分支的時候,看起來有一點不一樣。你會發現的提交歷史從一個更早的地方開始分叉(diverged:發散)。

master 分支所在提交節點,並不是 dev 分支所在提交點的直接祖先,所以 Git 不得不做一些額外的工作。

出現這種情況的時候,Git 會使用兩個分支的末端提交的快照(C5C6)以及這兩個分支的公共祖先(C3),做一個簡單的三方合併。

如下圖:

你只需要切換到你想合併入的分支上,然後運行 git merge 命令:

# 1.查看工作目錄中文件狀態,非常乾淨
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git status
On branch dev
nothing to commit, working tree clean

# 2.切換到master分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (dev)
$ git checkout master
Switched to branch 'master'

但這裏要注意,和之前合併 hotfix 分支的不同的是,指針向前推進所不同。Git 將此次三方合併的結果,做了一個新的快照,並且自動創建一個新的提交指向它。 這被稱作一次合併提交(典型提交),它的特別之處在於他有不止一個父提交。

如下圖所示:

既然你的修改已經合併進來了,就不再需要 dev 分支了, 現在你可以刪除這個分支。

$ git branch -d dev

2、遇到衝突時的分支合併

有時候合併操作不會如此順利。 如果你在兩個不同的分支中,對同一個文件的同一個部分進行了不同的修改,Git 就沒法乾淨的合併它們。

如果你在dev分支的開發時,也進行了和 hotfix 分支有關的修改,都涉及到同一個文件的同一處,在合併它們的時候就會產生合併衝突:

接上面練習:

1)合併dev分支到master分支上

# 直接合並分支dev到master分支上
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git merge dev
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

說明:

  • Auto-merging readme.txt:在自動合併readme.txt文件的過程中,
  • CONFLICT (content): Merge conflict in readme.txt:衝突(內容),在readme.txt文件中發生衝突。
  • Automatic merge failed; fix conflicts and then commit the result.:自動合併失敗,你需要手動解決衝突,然後提交結果。

此時 Git 做了合併,但是沒有自動地創建一個新的合併提交。 出現衝突時,Git 會暫停下來,等待你去解決合併產生的衝突。

你可以在發生合併衝突後的任意時刻,使用 git status 命令來查看,那些因包含合併衝突,而處於未合併(unmerged)狀態的文件。

L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
        new file:   dev.txt

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   readme.txt

2)解決readme.txt文件中的衝突內容

在合併分支時,產生衝突的文件都會被標識成未合併狀態(Unmerged),你需要打開這些文件,手動解決衝突。

出現衝突的文件會包含一些特殊區段,

打開衝突文件readme.txt如下:

# 編輯readme.txt文件
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ vim readme.txt

# 內容如下:
branch test v1
branch test v2
branch test v3
<<<<<<< HEAD
branch test v4
=======
branch test v4 dev 100%
>>>>>>> dev

說明:

  • HEAD======= :表示所在分支的內容,也就是master分支的內容。
  • =======dev :表示被合併的分支,也就是dev分支的內容

解決衝突方式:

  • 你選擇使用由 ======= 分割的兩部分中任何的一個。
  • 或者你也可以自行合併這些內容。
  • 並且 <<<<<<< , ======= , 和 >>>>>>> 這些標識要刪除。

本例修改衝突內容如下:

branch test v1
branch test v2
branch test v3
branch test v4 for master
branch test v4 for dev

這樣衝突文件就解決完成了。

提示: 自己和自己的分支合併時,所產生衝突還好解決,關鍵是自己和同事的分支合併時產生衝突,就比較難解決(基本靠吼,哈哈)。

3)把修改完的衝突文件加入暫存區並提交

在你解決了所有文件裏的衝突之後,對每個文件使用 git add 命令,將其添加到暫存區中。

一旦暫存這些原本有衝突的文件,Git 就會將它們標記爲衝突已解決。

如果你對結果感到滿意,並且確定之前有衝突的的文件都已經暫存了,這時你可以輸入 git commit 來完成合並提交。

# 1.查看工作目錄中文件狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Changes to be committed:
        new file:   dev.txt

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   readme.txt

# 2.添加到暫存區中
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ git add ./

# 3.再次查看工作目錄中文件狀態
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
        new file:   dev.txt
        modified:   readme.txt

# 4.提交
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master|MERGING)
$ git commit -m '第7次提交,完成dev分支的新功能'
[master 3110083] 第7次提交,完成dev分支的新功能

4)查看版本庫中的提交歷史

# 查看提交歷史
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git log --oneline --graph --all
*   3110083 (HEAD -> master) 第7次提交,完成dev分支的新功能
|\
| * e94af28 (dev) 第6次提交,修改dev和readme文件
| * 9eb3224 第4次提交,dev分支開發 dev.txt文件
* | 0690030 第5次提交,新增內容:branch test v4
|/
* b97ccfd 第3次提交,新增內容:branch test v3
* f72a9fe 第2次提交,新增內容:branch test v2
* fa2439a 第1次提交,新增readme.txt文件

此時dev分支已經完成了自己的使命,可以刪除了,留着沒有任何的意義。

# 1.刪除dev分支
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git branch -d dev
Deleted branch dev (was e94af28).

# 2.查看版本庫歷史提交信息
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/learngit (master)
$ git log --oneline --graph --all
*   3110083 (HEAD -> master) 第7次提交,完成dev分支的新功能
|\
| * e94af28 第6次提交,修改dev和readme文件
| * 9eb3224 第4次提交,dev分支開發 dev.txt文件
* | 0690030 第5次提交,新增內容:branch test v4
|/
* b97ccfd 第3次提交,新增內容:branch test v3
* f72a9fe 第2次提交,新增內容:branch test v2
* fa2439a 第1次提交,新增readme.txt文件
# 可以看到信息中,沒有dev分支的標識了。

此時工作目錄的圖解如下:

如上所示,就是解決一個衝突的全部流程。

3、補充:Git與SVN文件衝突對比

Git的衝突檢測單位是文件,即當不同分支對同一個文件進行修改後進行合併,就會產生衝突。

這是與SVN是不同的。SVN檢測衝突是以文件中的列爲單位,什麼意思?

  • 若兩個分支修改的不是同一個文件,合併時肯定不會產生衝突;
  • 但若修改的是同一個文件上的不同行中的內容,合併時也不會產生衝突;
  • 若修改的是同一個文件上同一行上的不同列,在合併的時候也不會產生衝突;
  • 只有兩個分支修改的是同一個文件同一行中同列數據的時候,在合併時纔會產生衝突。

Git保存的不是文件的變化或者差異,而是一系列不同時刻的 快照

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章