1. 程式人生 > >分散式版本控制系統Git------分支管理與合併(merge與rebase)

分散式版本控制系統Git------分支管理與合併(merge與rebase)

零、需要使用到的命令:

       git branch                                  檢視當前分支。        git branch <name>                    建立一個名為<name>的分支。        git checkout <name>                切換到名字為<name>的分支。        git checkout -b <nama>             建立一個名為<name>的分支並且切換到此分支(等於git branch <name>命令 + git checkout <name>命令)。
       git merge <name>                     把一個名為<name>的分支合併到當前分支。        git branch -d <name>                刪除一個名為dev的分支。        git merge   <分支名>                 把<分支名>合併到當前分支        git rebase   <分支名>                把<分支名>合併到當前分支(與merge不同)        git fetch<主機名> <分支名>
      將版本庫中的內容取回本地
git pull <遠端主機名> <遠端分支名>:<本地分支名>                        將版本庫中的內容取回本地並和<本地分支名>合併(merge合併方式)。        git pull --rebase<遠端主機名> <遠端分支名>:<本地分支名>         將版本庫中的內容取回本地並和<本地分支  名>合併(rebase合併方式)。         git stash                                        備份當前工作區的內容至git棧,再從最近的一次commit提交覆蓋到當前工  作區。
       git stash list                                 顯示當前git棧所有的備份        git stash pop                                從git棧中恢復一次內容至工作區,預設是恢復最近的一次        git stash clear                               清空git棧。

一、簡單介紹一下分支的基本操作。

        先看看分支建立  ->  切換  ->  提交  ->  合併  ->  刪除的基本套路吧。         使用上面的幾個命令可以實現最基礎的分支操作。         1.建立分支 git branch name         2.檢視當前所有分支 git branch         當前有兩個分支,分別是master和gzl         3.切換分支 git checkout name         git提示當前已經切換到分支gzl         4.在分支上修改檔案或者新增一個新的檔案,在分支上進行一個commit。         5.回到master分支 git checkout master         這個時候的開啟master分支的test.txt檔案看看         發現test.txt檔案回到了沒有更改的之前的內容。這是因為我們修改是在gzl分支的,而不是master分支。可以將分支看成一個個平行空間,你在其中修改並不會影響到其他分支的內容。         6.合併gzl分支的內容到master分支 git merge gzl         這裡採用的Fast-forward合併方式,即快速合併。也就是說,只是把master指向了gzl分支。         7.刪除gzl分支  git branch -d gzl         再用git branch 命令檢視,發現只剩下了master分支了。         Fast forward模式:如果順著一個分支走下去可以達到另外一個分支的話,那麼git合併的時候,就只要簡單的把master指標往後移。因為這種單線的操作不需要合併不同的分支,所以不會產生分歧,所以稱為Fast forward模式。         普通模式:在一個commit節點發生分支,有兩個不同的分支,如果想要合併這兩個分支,這個時候不能室友Fast forward模式。往往需要手動修改產生衝突的檔案,然後在進行一次commit。

二、合併分支的兩種方式

前面使用的是git的merge合併方式,分支還有一種合併方式叫做rebase衍合。             rebase衍合與merge合併最終的結果其實是一樣的,但是執行的過程卻是不相同的。

            merge方式(合併):

                         看看官方文件裡面的示例圖,master分支合併experiment分支,將會產生一個新的C5快照,而且只要你不刪除experiment分支它就會一直存在。C5分支就像C4和C3兩根繩子連在一起樣子,這樣C5既有了C4的內容,也有了C3的內容

            rebase方式(衍合):

            rebase流程

       (以下圖是已經rebase之後的結果圖):

                1.首先切換到C4所在的experiment分支。                 2.從C4開始向前找,直到找到和master分支最近的一個相同commit快照,C4和C4之前的所有commit快照生成patch檔案                 3.強制轉化到master分支,從C2開始,將上面生成的patch檔案,從C2開始往下一個一個打上patch檔案                 4.最後生成新的C4‘commit快照,它之前所在的分支experiment也隨著它的改變指向了master的上游。最後可以使用Fast forward方式讓master分支和experiment保持一致。            注意: rabase在第三步之中會發生衝突。 在這種情況,Git會停止rebase並會讓你去解決 衝突;在解決完衝突後,用"git-add"命令去更新這些內容的索引(index), 然後,你無需執行 git-commit,只要執行: git rebase--continue             這樣git會繼續應用(apply)餘下的補丁。             在任何時候,你可以用--abort引數來終止rebase的行動,並且"mywork" 分支會回到rebase開始前的狀態。 git rebase--abort             

                rebase的優勢和劣勢

        可以看到當使用rebase方式的時候,產生了C4'快照,這個快照和merge方式得到的快照是一樣的。可是不一樣的地方還有有的。                 1.experiment分支從獨立的分支,到和master分支相同的上游去了。                 2.C4快照消失了。         乍一看沒什麼,可是仔細想想,如果你在C4修改了一次重要的操作,可是使用rebase方式合併之後,你的C4卻丟失,那麼會造成不可忽略的影響。         通過檢視文件,rebase方式有優勢也有劣勢:

優勢:

        採用rebase方式合併的快照,在主分支上看起來就像是一條平行線一樣整潔乾淨,讓人一目瞭然,這樣管理人員就不需要花費時間去整理分                                                                                              分支了。                

劣勢:

        就像上張圖那樣,採用rebase方式合併之後,以前的分支的快照都會消失。引用文件的概括的一句話------

                Do not rebase commits that exist outside your repository.         為什麼會這樣,文件上的例子很生動,我大概翻譯一下:         如果你rebase一個檔案,放棄了目前的修改,然後建立了一個新的看起來相同可是內容卻不同的 快照一 。如果你將這個快照放到網上或者其他地方,別人pull下了它,然後按照這個為基準進行工作。這個時候你又重寫了它並且使用了git rebase方法把它上傳到了網上稱為  快照二,你的同事將會被這個新的快照搞得頭昏眼花。因為他們是基於你第一次快照來進行開發的,可是你使用rebase命令之後,你的快照一將會消失,那麼你同事做的事情就會白費。         那麼如果你面臨這樣的情況,改怎麼辦呢?別擔心,還是有機會挽回損失的。         如果你面臨這樣的困難,那麼你所面臨的第一個挑戰就是分辨出哪些是你寫的,哪些是你同事寫的。         原來commit 物件除了SHA-1計算校驗之外,Git還基於你引進的補丁計算了一種校驗碼,叫做“patch-id”。         如果你從你同事那裡拉下重改的程式碼是基於最新的一次提交,Git也能也能夠成功的解決而且申請它回到一個新的分支上。         使用git rebase teamone/master命令。                 1.找到唯一工作在分支上的commit快照。                 2.找到沒有合併的commit快照。
3.找到沒有被改寫的commit快照加入目標分支。
4.應用這些commit快照在master分支和teamone分支。
        但是它只工作在舊commit快照C4和新快照C4’有著差不多的補丁,否則衍合就不能夠分辨C4'是C4的複製快照。這樣的話就會新增一個新的C4 ''的補丁檔案(這將會導致衍合失敗,而且這樣的話會導致一些不可預料的變化)。         你也可以用git pull --rebase命令來代替平常的git pull命令                 最後附上git文件裡面的最後一段,關於什麼時候使用rebase和merge

 三、git pull 和 git pull --rebase

        先說說git pull命令。         git push是把本地檔案上傳至遠端庫的命令。那麼自然而然就有把遠端庫的檔案拉下來放到本地工作區的命令,這個命令就是git fetch命令。git fetch所做的只是把遠端庫的檔案獲取到本地。
git pull = git fetch + git merge。
如果後面加上--rebase引數。git pull --rebase命令
        表示把你的本地當前分支裡的每個提交(commit)取消掉,並且把它們臨時 儲存為補丁(patch)(這些補丁放到".git/rebase"目錄中),然後把本地當前分支更新 為最新的"origin"分支,最後把儲存的這些補丁應用到本地當前分支上。         其實git pull --rebase = git fetch  + git rebase。         瀏覽了一些部落格,發現大多數博主都有個提醒的地方:儘量少使用git pull或者git pull --rebase命令,多使用git fetch命令 + git pull命令或者git fetch命令 + git rebase命令。因為逐步執行可以保證檔案的安全性。直接git pull會隱藏一些細節,或許這些細節就是你所需要的。         而到底是使用git pull還是使用git pull --rebase,其實也就是面臨是選擇git merge還是git rebase合併一樣的情景。git merge可以儲存所有的commit記錄方便之後的使用,而git rebase是為了有一條清晰明朗的主線,避免無謂的commit。存在即為合理,兩種不同的方式各有優點,就看實際情況到底如何使用了。

四、無大腦的簡單問題測試

        問題一:git merge 分支的時候,合併衝突。

情景再現:在分支修改了某個檔案之後,回到master分支想要將兩個分支合併。因為某個檔案內容不一樣,出現了         git告訴你合併失敗因為有一個未合併的檔案。這個時候應該在工作區開啟檔案,手動修改,在使用add,commit命令,最後使用git merge命令最後才能成功的合併。         盜取廖雪峰老師的圖來解釋一下應該會更清楚點:                 1.你修改了兩個不同分支相同的檔案,這個檔案在不同分支內容是不同的,不能使用快速合併了。
                2.這個時候你手動修改了這個檔案,使用git merge命令發現出現下面的提示。
        解決方法:手動修改未合併的檔案,再次add,commit。合併之後相當於多了一次提交。改變圖如下:
        結論:如果merge的時候使用的是Fast forward模式,git只是將mater的分支移到另外一個分支上。如果沒有使用Fast forward模式(普通模式),Git會產生一個新的commit。Fast forward模式合併之後是沒有分支記錄的,普通模式是用分支記錄的。

        問題二:git pull的時候合併衝突

        你工作做到一半,突然有個bug要放下手上的活兒去解決bug。可是直接pull會丟失你這幾天的辛辛苦苦工作。下面幾個步驟搞定。
1.git add *        把所有值錢工作的檔案放入暫存區。
2.git  stash        將檔案放入git棧備份
3.git pull origin 將遠端庫程式碼拉下來(避免衝突了)
4.git stash pop  將git棧的備份檔案拿出來
5.git merge        合併檔案
以上是我的一些總結,如果有什麼錯誤的地方歡迎大家指正!