1. 程式人生 > >git rebase總結及git使用規範

git rebase總結及git使用規範

一、git規範

  場景一:如果程式碼commit到本地庫了,但是commit之前忘記pull了,遠端程式碼也已更新,此時不能使用pull直接拉取遠端程式碼(分支會產生merge的記錄):

    解決方法:commit之後,使用git fetch,拉取遠端程式碼到快取區,然後使用git rebase origin/dev,此時會產生衝突,解決衝突後即可提交,這樣分支不會產生merge的記錄

  場景二:commit提交之前先使用pull總是沒問題的,但如果pull不下來,是因為程式碼和遠端程式碼衝突了,此時有兩種解決辦法:

    1.使用git stash 儲存本地修改的程式碼到快取區,此時程式碼會還原為沒修改之前的,此時在使用git pull拉取程式碼,然後使用git stash pop恢復快取區的程式碼,此時解決衝突即可提交

    2.先commit提交原生代碼到本地庫,這時候不要直接pull(分支會產生merge的記錄),先使用git fetch,拉取遠端程式碼到快取區,然後使用git rebase origin/dev,此時會產生衝突,解決衝突後即可提交,這樣分支不會產生merge的記錄

  場景三:dev程式碼修改後,test分支需要同步更新修改:

    解決方法:dev修改後push程式碼,切換到test分支,pull保證與遠端程式碼一致,此時不能merge dev,而是使用git rebase dev(或者git rebase origin/dev),此時會把dev的程式碼都更新到本地test分支,然後在push到遠端test分支,這樣分支不會產生merge的記錄

  場景四:取消merging狀態

    git reset --hard HEAD (or sha_1)

  場景五:多人同時開發一個分支:

    1、git pull

        如果pull不下來,說明原生代碼和遠端分支有衝突,程式碼更新不了

    2、git commit -m "xxx"
        將原生代碼新增到本地緩衝區

      git commit -a -m "xxx"
    3、git stash
        如果本地有不需要提交的程式碼,git stash把你的修改儲存起來,恢復到和你沒修改之前一致
    4、git fetch


        更新遠端程式碼到本地暫存區
    5、git rebase
        把本地暫存區的程式碼更新到工作區
    6、有衝突的話把衝突解決
    7、git status
      git add . 將解決完衝突的檔案新增提交
    8、git rebase --continue
    9、git push origin dev 提交遠端分支
    10、git stash pop 恢復不需要提交的檔案

 

 

二、rebase總結

  1. 如果新參與一個專案,首先需要本地clone遠端倉庫。之後會有一個master(若不特殊說明,均指代本地master)和遠端的master(以下稱為remote/master)是關聯的,即remote/master是本地master的up-stream。


    從遠端倉庫進行克隆
  2. 做開發時,要新建一個分支,如dev1,作為你的開發分支。開發完新特性後,將工作區(work tree)的修改提交至暫存區(index),然後commit,此時會在dev1分支上生成一個新的commit單號。


    提交你的修改
  3. 切換回master分支,然後使用pull或者fetch+merge命令與remote/master同步一下(此時可能會有來自其他開發者的提交),再合併(merge)dev1分支的,如果有衝突,則解決衝突。最後推送程式碼到遠端倉庫。


    更新本地主分支
    合併dev1分支,推送 合併dev1分支,推送

    這是我剛開始實習時,常用的一個開發,推送程式碼的流程。久而久之,我發現了幾個問題:

  • 在master分支上解決衝突,可能會有些風險。比如一不注意,衝突沒有正確解決,導致本地修改與別人的修改混在一起,本來穩定的與遠端保持同步的master分支被你改混亂了,且沒有其他的備份了。

  • 在master分支上merge開發分支,如果master分支上有dev1沒有的commit單號,則會產生一個攜帶merge資訊的提交單。這個commit你也要推送到遠端。企業開發一般會有一個評審分支,主管會對commit單號進行review,然後submit合併進remote/master分支中。merge資訊的提交單也會讓reviewer做一次review,然而沒什麼必要的。

  • 一個人提交時,會有一個merge commit,那麼10個人提交,就會有10個merge commit,此時分支樹看起來會很混亂。零零散散的merge commit資訊穿插在你的特性commit之間。

因此,我考慮使用另外一種本地分支管理策略,來改善這樣的問題。

 

使用rebase命令。

先簡要說下rebase命令的作用。

比如在dev1分支上,你提交了2個單,c1和c2。然後你在dev1分支上將master分支rebase到當前分支git rebase master。此時,如果master分支已經與remote/master做了同步,更新了2個來自其他人的提交,c3和c4。

  場景描述
rebase會做如下操作:

 

  1. 把dev1分支上的c1和c2“拆”下來,並臨時儲存成c1'和c2'。git裡將其稱為patch
  2. 將master分支上更新的提交c3和c4合併進dev1分支上。


    rebase操作,拆分提交 rebase操作,拆分提交
  3. 將c1'和c2',再按順序接在c3和c4的提交後面,如果沒有衝突,則rebase成功。此時c1'和c2'雖然和c1和c2的修改完全一樣,但卻已經不是原來的提交了,commit id已經變化了。
      連線patch
    此時dev1分支包含master分支的所有commit,並且超前了兩個commit。如果你現在切換至master分支,並執行git merge dev1操作,由於沒有不同於dev1的提交,merge操作就不會產生merge commit了。此時推送程式碼,也只會有兩個commit。同時,master分支樹筆直前進,分支很清晰地展示一個個提交。並且,上述的更新和提交程式碼的過程,是在dev1分支上修改衝突的,相對來說會比在master分支上修改更安全,如果不小心改混了,也能通過切換回master分支來找到穩定程式碼。
      在master分支上合併dev1分支
    基於上述內容,可以使用如下流程來提交程式碼:

 

  1. 在dev1分支上進行開發,然後commit提交,在dev1分支上生成一個提交單。
  2. 切換到master分支,與remote/master分支同步。
  3. 切換回dev1分支,將master分支rebase到dev1分支上,如果有衝突,修改衝突。rebase操作的衝突修改與merge不一樣,修改完衝突後,儲存進index,然後直接git rebase --continue即可,不同再多做一次提交。
  4. 切換回master分支,合併dev1分支,此時合併會非常順暢。然後push。

rebase的風險

之前提到,rebase會將當前分支的新提交拆下來,儲存成patch,然後合併進其他分支新的commit,最後將patch接進當前分支。這是rebase對多條分支的操作。對於單條分支,rebase還能夠合併多個commit單號,將多個提交合併成一個提交。

git rebase -i [commit id]命令能夠合併(整改)commit id之前的所有commit單。加上-i選項能夠提供一個互動介面,分階段修改commit資訊並rebase。

但這裡就會出現一個問題:如果你合併多個單號時,一不小心合併多了,將別人的提交也合併了,此時你本地的commit history和遠端倉庫的commit history不一樣了,無論你如何push,都無法推送你的程式碼了。如果你並不記得rebase之前的HEAD指向的commit的commit ID的話,git reflog都救不了你。

tips: 你可以push時帶上-f引數,強制覆蓋遠端commit history,你這樣做估計會被打,因為覆蓋之後,團隊的其他人的本地commit history就與遠端的不一樣了,都無法推送了。

因此,請保證僅僅對自己私有的提交單進行rebase操作,對於已經合併進遠端倉庫的歷史提交單,不要使用rebase操作合併commit單。