1、典型合併
繼續上面的前一篇文章的示例:
我需要繼續開發dev
分支上的功能。
需求:
- 繼續修改
dev.txt
文件。 - 修改
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 會使用兩個分支的末端提交的快照(C5
和 C6
)以及這兩個分支的公共祖先(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保存的不是文件的變化或者差異,而是一系列不同時刻的 快照 。