標籤:git 專案管理 merge merge request branch
上一篇講了remote相關,讓大家基本瞭解了一下遠端庫與本地庫之間的聯絡。目前我認為還剩下的容易造成理解混亂的是merge命令以及merge動作的應用情境,下面詳述。
首先先給大家解釋merge本身的一些內容,再結合一些情境幫大家從混亂的理解中找到思路,進而完全理解Merge Request的意思並掌握這項技能。
merge譯成中文是合并,顧名思義,git merge命令時用來合并的,而合并的對象就是branch(分支)。下面我舉個簡單的應用情境(只在本地Repository中)來說明:本地庫中有兩個分支testBranch1和testBranch2。目前兩個分支中的檔案內容相同,都只有一個fileA.txt檔案,而且fileA.txt的內容只有一行文字:HelloWorld!
如果你目前處於testBranch1,並且修改了fileA.txt檔案在第二行增加了一句:Hello!
此時你的fileA.txt形如:
HelloWorld!
Hello!
不僅如此,你還建立了另一個空檔案fileB.txt,並且把所有的修改commit進來。
然後checkout到testBranch2上,此時testBranch2上應該只有一個fileA.txt檔案而且內容只有一行HelloWorld! 此時你又修改了fileA.txt在第二行增加了一句HaHa! ,並且把所有的修改都commit進來。
此時你的fileA.txt形如:
HelloWorld!
HaHa!
現在可以想象,testBranch1和testBranch2兩個分支分別管理著兩套不同版本的內容了。前者有兩個檔案,後者只有一個檔案,而且名字相同的檔案內容也有所差別。好了git merge命令馬上要出場了,下面請特別注意小編介紹的兩個情境:
情境1:
git checkout testBranch1 (即切換到testBranch1分支上),執行git merge testBranch2命令。這樣代表:站在testBranch1分支上,把testBranch2分支上的內容融合到testBranch1分支上來。
這樣git會嘗試把testBranch2中的內容與testBranch1融合,而這樣是不會改變testBranch2分支上的內容的,只會改變testBranch1上的內容。所以此後testBranch1上有兩個檔案(fileA.txt和fileB.txt),而testBranch2上依然只有1個檔案(filtA.txt)
情境2:
git checkout testBranch2 (即切換到testBranch2分支上),執行git merge testBranch1 命令。這樣代表站在testBranch2分支上,把testBranch1分支上的內容融合到testBranch2分支上來。
這樣git會嘗試把testBranch1中的內容與testBranch2融合,而這樣是不會改變testBranch1分支上的內容的,只會改變testBranch2上的內容。所以此後testBranch1上有兩個檔案(fileA.txt和fileB.txt),而testBranch2上也有了2個檔案(fileA.txt和fileB.txt)
情境1和情境2在整體上的變化大家明白以後應該就能理解merge命令的含義了吧?下面說一下另一個細節
相信大家注意到,如果第一個分支的fileA.txt和第二個分支的fileA.txt進行融合的話,是有可能產生歧義的。前者的第二行希望是Hello!,後者的第二行希望是HaHa! 那麼最終結果到底聽誰的呢?這種情況下Git就“有可能產生衝突”。那麼在merge 過程中產生衝突是怎樣的效果呢?此時你的fileA.txt可能會呈現類似以下的中間狀態(此時以情境1的情況為例):
HelloWorld!
>>>>>>>>>
Hello!
=========
Haha!
<<<<<<<<<
類似這樣的狀態代表Git說:我糊塗了。就需要我們人工來解決這樣的衝突。此時我們可以開啟fileA.txt檔案,發現內容可能如上所示。解決時我們會想:Hello!是我在操作testBranch1時想加的話,HaHa!是我在操作testBranch2是想加的話。兩個我都想儲存下來,那稍微編輯一下就想搞成如下形式:
HelloWorld!
Hello!
HaHa!
這樣解決衝突(即人為編輯)完成後我們儲存並關閉檔案。
注意!此時我們仍然處於merge的“過程中”,要想完成merge必須告訴Git:剛才衝突的檔案就按照我剛才儲存的這樣解決! 怎麼告訴Git呢?就是git add fileA.txt然後git commit -m "解決fileA檔案的衝突問題" 兩個命令。說白了就是再把最新的fileA.txt檔案加入Git的管理。
這些都做完之後,我們就已經渡過了merge過程回家包餃子了。
這裡需要理解一個Git的底層原理,這裡稱其為原理111:在將testBranch2分支merge到testBranch1分支中時,我們像上面那樣解決fileA.txt檔案的衝突。這樣Git就“知道了”上面這個衝突的解決辦法,即用形如:
HelloWorld!
Hello!
HaHa!
的內容來替換衝突檔案中的內容(因為這是剛才主人決定的)。那麼如果此後再將testBranch1分支merge到testBranch2分支中時,我們就不必要再手動解決衝突了,因為Git已經知道該怎麼做了。
這個原理會在後面的remote中得到應用,所以希望讀者在此能夠理解到位。
好了分割線=====================================================================================================================
下面就來講解一下什麼是Merge Request以及怎麼進行合理的Merge Request
舉一個比較簡單的情境:
你們公司的伺服器是Stash,上面有個正在開發的項目:ComRepository。這個項目有三個分支:master,worker1,worker2。那麼如果把這個項目clone下來之後,本地也會有三個分支:master, worker1, worker2。現在心裡要清楚哦,如小編第一篇文章所說,你所知道的是有6個分支的哦,伺服器上3個,你本地3個。而對於公司來說,他們不在乎每個員工本地的分支是怎樣,他們只在乎伺服器上的master分支是否運轉正常。因為伺服器上的master分支有可能就是公司發表項目時用的分支,所以這個分支上的代碼至關重要!
此時公司要求你就在worker1分支上開發吧!那麼你的開發流程是什麼呢?總之最終目的是要讓伺服器上的master分支有你開發好的代碼。
為了方便,後面依然把本地分支帶上尾碼(L),如worker1(L)。
一種思路:
在worker1(L)分支上開發,然後checkout到master(L)上,將worker1(L)分支merge到master(L)上來,然後將master(L)的新代碼push到伺服器的master上去。
這種思路是不該推薦的,如果我是老大,我是不會給你分配master分支的push許可權的。因為這樣太危險了,master分支是公司至關重要的分支,豈能讓你說push就push?這樣會讓公司的master上的代碼時刻處於危險之中。
第二種思路:
就是Merge Request的思路。我們每個開發人員都沒有master分支的push許可權,但是有pull許可權。即只能看,不能寫。但是我們有其它分支(如worker1和worker2)的pull和push許可權,反正這兩個分支也不是太重要的分支,開發人員愛怎麼糟蹋怎麼糟蹋。
那麼怎麼才能讓伺服器上的master分支得到更新呢?就是在伺服器上進行merge動作,即將伺服器上的worker1或者worker2分支上的內容merge到master分支上。這個過程就是Merge Request!所以伺服器上的merge動作不是靠你本地git merge命令來完成的,因為你只能操作你本地的分支,伺服器上的分支你八竿子打不著,怎麼可能輕易去“命令它”?所以這個merge動作基本上是在你們伺服器的網頁上進行的。比如:你在公司伺服器的網站上,發起一個Merge Request,請求把伺服器上的worker1分支merge到master分支上去,請求發起要添加一些審核人物,譬如你的老闆你的同事。當他們接收到這個Merge Request並同意後,可能會有個“同意”之類的按鈕,點擊之後就會在伺服器上把worker1分支merge到master中。這樣做就有效地保護了master分支的安全性。
伺服器上的worker1分支的更新就是靠你在本地worker1(L)上更新後push上去的。所以簡單的流程就是你早上來上班了,在worker1(L)分支上開發了一天,然後把工作內容都push到伺服器的worker1分支上去,再發起一個Merge Request請求把伺服器上的worker1分支merge到master上去,然後下班。
分割線==========================================================================================================================
以上就是結合remote和branch來講解的Merge Request。讀者瞭解之後,可以學習一下下面的非常重要的內容:
試想一下:如果你請求worker1往master上merge,我請求worker2也往master上merge。那麼久而久之,我們有可能都改了同一個檔案,就可能會產生衝突。那樣的話master分支上豈不是亂七八糟了?那麼怎麼才能讓master上的分支一直正確,不產生衝突呢?
下面我先說下流程:比如你是在worker1(L)分支上的開發人員,做完了一天的工作,先不要提Merge Request,而是先checkout到master(L)上,pull一下,把伺服器上master的代碼拉下來,是本地的master(L)是最新的master代碼,然後checkout回worker1(L)分支,將master(L)分支merge到worker1(L)上,這時候就有可能發生衝突了,因為可能在你下班之前,worker2分支的同事已經提交了代碼並且更新了master,而你們恰巧修改了同一個檔案。這時候衝突了不要緊,因為衝突是發生在你本地的,你只要在本地把衝突解決了,然後push到worker1分支上去,再提Merge Request,就不會使伺服器上的master產生代碼衝突了。
原因相信聰明的你已經明白,就是上面提到的原理111 。因為你在本地解決衝突的時候,Git就已經知道產生衝突以後該怎麼做了,而你又把這些指令碼push到了伺服器的worker1分支上,那麼伺服器的worker1分支在往master分支合并的時候自然就知道該怎麼做了。怎麼樣,Git強大吧?
順便再建議一下,當你早上來上班時,盡量也checkout到master(L),pull一下,再checkout回worker1(L),把master(L)分支的內容merge過來,完成之後再進行開發。這樣就是盡量保持在昨晚之後的最新的代碼上進行開發,以減少產生衝突的可能性嘛~
好了太晚了,今天就先講到這裡吧~這幾天還在持續忙碌中,所以更新會比較慢,見諒~
Git使用入門,使用原理解讀及如何在GitLab、GitHub或者Stash上管理項目(三)