GIT合併

本節指令
git merge
git reset --hard ORIG_HEAD
git merge --no-ff
git tag
git tag -a -m

合久必分、分久必合。GIT在做分支控管時也是分分合合,這個單元就來講解怎麼做分支合併(merge)

一、分支合併

請先建立本單元的工作環境(分三次複製貼上):

mkdir merge1
cd merge1
git init
echo 1 > file1.txt
echo 1 > file2.txt
git add file1.txt
git commit -m "C1"
git add file2.txt
git commit -m "C2"
------------------------------
git checkout -b bug
echo 1 > file3.txt
git add .
git commit -m "C3"
echo 1 > file4.txt
git add .
git commit -m "C4"
------------------------------
git checkout master
echo 1 > file5.txt
git add .
git commit -m "C5"
echo 1 > file6.txt
git add .
git commit -m "C6"

master分支有以下檔案:

file1.txt、file2.txt、file5.txt、file6.txt

bug分支有以下檔案:

file1.txt、file2.txt、file3.txt、file4.txt

好啦!到目前為止,和上一節的檔案結構一樣,接著我要將bug合併到master分支上。

首先將分支切換到master:

git checkout master

接著將bug分支合併進來:

git merge bug

做完合併動作後,也代表bug分支的階段性任務完成,通常會將此分支刪除,執行:

git branch -d bug

因為bug分支已經合併過,用-d就能刪除,而不用-D

若不刪除分支,繼續留著也可以,就看你的決定了。

好啦!這樣就完成合併的動作了,來看一下分支圖:

這次的合併有幾個重點要看:

  • 首先合併後GIT會自動多了一個提交(commmit)的版本,並自動加上說明Merge branch bug
  • 雖然合併了,但只有master往前推進一個版本(d6789aa),而bug分支還是繼續停留在原本的C4提交(commit)版本上。
  • 在master分支查看資料夾檔案,一共有6個檔案:file1.txt~file6.txt
  • 在bug分支查看資料夾檔案,一共有4個檔案:file1.txt~file4.txt

要解釋為何兩個分支的檔案有如此變化,我們把它畫成跟上個單元一樣的水流圖,這樣瞭解了吧!

補充:若你也想讓bug分支包含C5C6提交的file5.txt和file6.txt

那就把master合併到bug分支裡就好啦,試看看吧!

結果如下:

二、回復合併

如果合併後,發現做錯了,想要反悔怎麼辦呢?

git checkout master
git log --oneline
git reset --hard [C6的commit ID]

看吧!瑞凡,我們回去了~~

有更簡單的方法,可以利用ORIG_HEAD別名直接回到上一版本

git reset --hard ORIG_HEAD

這裡reset指令中的--hard表示強制將工作目錄(WD)的檔案回復到前一版本。

若你想返回前一版本,又要保留目前工作目錄(WD)的檔案,可用--soft,通常比較少用。

三、快轉(Fast-Forward)合併

請先建立本單元的工作環境(分二次複製貼上):

mkdir merge2
cd merge2
git init
echo 1 > file1.txt
echo 1 > file2.txt
git add file1.txt
git commit -m "C1"
git add file2.txt
git commit -m "C2"
------------------------------
git checkout -b hotfix
echo 1 > file3.txt
git add .
git commit -m "C3"
echo 1 > file4.txt
git add .
git commit -m "C4"

在master分支有以下檔案:

file1.txt、file2.txt

在hotfix分支有以下檔案:

file1.txt~file4.txt

由於master在C2分出hotfix後,在hotfix繼續提交了C3C4版本,因此hotfix停在C4

而master在分出hotfix後,就沒有再作業提交,因此還停在C2

此時,如果要將C3C4版本做的變更合併至master裡,可下指令:

git checkout master
git merge hotfix

合併完後的命令提示及分支圖(請注意圖中Fast-Forward這個字):

你會發現,分支圖和之前有不同之處:

  • 並不像之前合併的樣子,有從旁分一個分支再合回來(長耳朵)
  • 也沒有在合併後,多一個提交(commit)

這種情形我們稱為快轉合併(Fast-Forward)。會產生快進的情形,就是要合併進來的hotfix分支,剛好在master分支的前面,並沒有額外分叉出去,此時只要將master分支的指標往前移動,就解決合併了,因此GIT做了Fast-Forward,省得麻煩還要再建commit

可是,如果想看到有長出耳朵的那種合併,怎麼做呢?

首先,我們復原剛才的合併,怎麼做還記得吧:

git reset --hard ORIG_HEAD

接著重做一次合併,但這次要加--no-ff指令

git merge --no-ff hotfix

完成後,就長出耳朵來了:

四、衝突

到目前為止,合併好像做的滿順利的。但如果兩個分支都改了同一個檔案,就會造成衝突(conflict),很多人因為怕衝突,而不趕開分支,其實,在發生檔案衝突時,只要選擇你要保留哪一個版本的檔案內容,再來合併就解決啦!

所以衝突(conflict)是要人為來解決的,GIT沒有辦法幫你決定要哪個版本啊~~

請先建立本單元的工作環境(分三次複製貼上):

mkdir merge3
cd merge3
git init
echo 1 > file1.txt
echo 1 > file2.txt
git add file1.txt
git commit -m "C1"
git add file2.txt
git commit -m "C2"
------------------------------
git checkout -b release
echo 大家好 > file1.txt
echo 1 > file3.txt
git add  --all
git commit -m "C3"
echo 1 > file4.txt
git add .
git commit -m "C4"
------------------------------
git checkout master
echo 我愛你 > file1.txt
echo 1 > file5.txt
git add  --all
git commit -m "C5"
echo 1 > file6.txt
git add .
git commit -m "C6"

這兩個分支都改了file1.txt,release分支改成大家好,而master分支改成我愛你,接著我們將release合併到master裡,看會花生省魔術:

git checkout master
git merge release

慘了!慘了!發生衝突(Conflict),怎麼辦~怎麼辦~

我們先來看一下檔案狀態:

git status

這裡多了一個檔案狀態,稱做未合併(Unmerged paths,簡單的說就是發生衝突(Conflict)啦!而且GIT會把file1.txt這個衝突檔案放在工作目錄(WD),讓你自己決定怎麼修改。

現在開啟sourceTree來解決衝突

有兩個選項可以選:

  • Resolve using 'Mine':以主分支內容為主
  • Resolve using 'Theirs':以副分支內容為主

所以如果選了Mine,就會套用master分支的我愛你

選了Theirs,就會套用release的大家好

選好後,執行git commit就完成了。

如果你還是不知道要選Mine或Theirs,可能要先和別人多多討論,再來處理衝突,此時
你可以用以下指令先取消這次的合併:

  git reset --hard HEAD

五、標籤

輕量級的標籤:

    git tag [標籤名稱]

含附註的標籤:

git tag -a [標籤名稱] -m "註解"

六、分支圖反解

又到了看圖說故事時間啦!這個單元多了分支合併,準備好挑戰了嗎?Let's go...

【Ex-304 分支圖練習】

【Ex-305 分支圖練習】

【Ex-306 分支圖練習】

【Ex-307 分支圖練習】

【Ex-308 分支圖練習】

七、Git Flow練習

實際上開發程式時,分支到底要怎麼規畫啊?Vincent Driessen提出了一套Git Flow開發流程A successful Git branching model

在sourceTree也有這項功能可以直接套用:

實際上我們只要懂得此流程,自己手動建分支也能達到同樣目的喔!以下條列出這些分支的特性及用途:

master:正式上線分支,合併(merge)最好要有專人負責。

develop:開發分支,提交(commit)、合併(merge)最好要有專人負責。

hotfix: 緊急修補分支,由master分支出來,可合併至master和develop,用途是解決正式版上線的bug。

feature:功能分支,由develop分支出來,可合併至develop,用途是開發新功能。

release:釋出版本分支,由develop分支出來,可合併至master和develop。用途是開發下一版本,也就是開發完成準備釋出時要建立。此分支只會針對該版本bug做修改及commit而已,但請不要在release繼續開子分支。

接下來,我們來分階段做好了,這樣比較單純些…

1、master上線分支、develop開發分支、feature功能分支

【Ex-309 Git Flow綀習】

feature流程:
git checkout -b feature develop →
git add →
git commit -m →
git checkout develop →
git merge feature (要不要耳朵隨便你) →
git branch -d feature (要不要砍隨便你)

※圖中並沒有將develop合併回merge,實務上是要的

做好的分支圖大概如下:

2、master上線分支、develop開發分支、feature功能分支、release釋出版分支

【Ex-310 Git Flow綀習】

release流程:
git checkout -b release develop →
git add →
git commit -m →
git checkout master →
git merge release →
git checkout develop →
git merge release (要不要耳朵隨便你) →
git branch -d release (要不要砍隨便你)

3、master上線分支、develop開發分支、feature功能分支、release釋出版分支、hotfix緊急修補分支

【Ex-311 Git Flow綀習】

hotfix流程:
git checkout -b hotfix master →
git add →
git commit -m →
git checkout master →
git merge hotfix (要不要耳朵隨便你) →
git checkout develop →
git merge hotfix (要不要耳朵隨便你) →
git branch -d hotfix →

results matching ""

    No results matching ""