Git——分支——合併與變基

1、合併

  合併的流程如下:假定將other分支合併到master分支上。

  第一步,執行git merge other, Git會自動根據獲取當前分支,並判斷是否符合合併的條件。

  第二步,基於基點(base commit), 計算other分支與master分支上每個文件的差異,並嘗試合併,若合併成功,無衝突,此時無需人工介入,Git自動創建一個合併提交(Merge commit),合併完成。

  第三步,若有衝突,把文件標誌爲”unmerged”狀態,人工介入,解決衝突,手動創建一個提交,合併結束。

  第四步,第三步的另一種方案,當發現衝突之後,撤銷合併操作,合併撤銷。

1.1  前提條件

  A merge must occur within a single repository

合併的分支處於同一個版本庫。

  before you begin a merge, it’s best to tidy up your working directory. During a normal merge, Git creates new versions of files and place them in your working directory when it is finished. furthermore, Git also uses the index to store temporary and intermediate versions of files during the operation

  在合併之前,工作目錄必須是乾淨的。

1.2  有衝突

  若發生衝突,合併中斷,需要人工介入,執行git status,可以查看衝突的文件列表。

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   Hello.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	result.txt

no changes added to commit (use "git add" and/or "git commit -a")

  顯示Hello.txt文件存在衝突,點擊查看衝突的內容。

<<<<<<< HEAD
Line under master
=======
Line under other
>>>>>>> other

  橫線之上,master分支上的Hello.txt與基準點(base commit)的比較。橫線之下,other分支上的Hello.txt與基準點(base commit)的比較。

1.2.1 解決衝突

  逐個解決衝突的文件,只有三種策略。

  第一種,完全刪除掉當前分支的內容。accept theirs。

  第二種,完全刪除合併分支的內容。accept ours。

  第三種,前兩種的mix。

  在實踐中,需要遵循不覆蓋別人代碼的原則,所以accept ours很少使用,mix也很少使用。

  1.2.2  回滾

  回滾,本質就是清空當前工作目錄中的修改。若發生衝突,合併操作中斷,不會自動創建合併提交(merge commit)。

  當執行合併時,

  當前分支的HEAD臨時保存在ORGI_HEAD。

  被合併的分支HEAD臨時保存在MERGE_HEAD。

  執行git merge –-quit,退出合併操作, abort的合併可以重新啓動,退出之後只能重新開始。

  執行git reset –hard ORGI_HEAD, 回滾到最近的一次commit。

1.3  無衝突

  無衝突情況下,Git自動創建merge commit,日誌信息爲merge branch xx into XX,例如將other合併到master,顯示爲merge branch other into master。

  命令窗口會打印合並的策略,

  1.3.1 already up-to-date

  when all the commits from the other branch (its HEAD) are already present in your target branch, even if it has advanced on its own, the target branch is said to be already up-to-date

  當master分支與other分支的差集爲空時,或者表述爲other分支中所有的提交都在master集合中。此時other分支合併到master分支,採用already up to date。

  它沒有任何操作,因爲它們已經合併過了。

  

  1.3.2 fast-forward

  A fast-forward merge happens when your branch HEAD is already fully present and represented in the other branch. This is the inverse of the Already up-to-date case

  fast-forward是快進到最近一次提交, 當master分支合併到other分支時,other分支的HEAD會指向master分支的最近一次提交。

  例如將master合併到other分支上時,只是將other分支的HEAD指向master的最近一次提交。

  

  1.3.3 resolve

  the resolve strategy operates on only two branches, locating the common ancestor as the merge basis and performing a direct three-way merge by applying the change from the merge base to the tip of the other branch HEAD onto the current branch

  默認的方式,比較兩個分支的不同文件,嘗試合併,若無衝突,會自動創建合併提交(merge commit)

  1.3.4 recursive

  兩個以上的分支進行合併時,採用的策略。假設A, B, C三個分支進行合併,根據merge命令中參數的順序,先合併A, B,然後將二者的合併結果與C進行合併,類似於數據庫中的join操作。

  1.3.5  octopus

  The octopus strategy is specifically designed to merge together more than two branches simultaneously. Conceptually, it is fairly simple, internally, it calls the recursive merge strategy multiple times, once for each branch you are merging, However, this strategy cannot handle a merge that requires any form of conflict resolution that would necessitate user interaction. In such a case, you are forced to do a series of normal merges, resolving the conflicts one step at a time.

  多線程,異步執行,例如A, B,C,D,異步執行A與B合併,C與D合併,然後再將二者的結果進行合併。

1.4  指令

  git merge指令有兩種格式。

  第一種格式,git merge (--continue, --abort, --quit)控制合併的流程,abort與continue是一對,quit退出後,只能重新進行合併。

  第二種格式  

git merge [-n] 
[--stat] 
[--no-commit] [--squash] [--[no-]edit]
          [--no-verify] 
[-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
          [--[no-]allow-unrelated-histories]
          [--[no-]rerere-autoupdate] [-m <msg>] [-F <file>] [<commit>…]

  選項:

    n,stat:顯示合併的統計信息。

    no-commit:合併時不自動創建提交對象。

    squash:壓縮合並提交和當前提交爲一個提交。不會這麼幹,會混亂提交歷史。

    m,F,edit:提交的日誌信息,m從控制檯輸入,F從文件中獲取,edit開啓編輯器。

    s <strategy>:指定合併的策略。默認的策略即可。

    no-verify:不校驗合併提交的對象。

    S <keyid>:指定提交的簽名。

    allow-unrelated-histories:多個分支合併時,必須至少存在一個基準點。它的作用就是比較彼此的不同之處。這個選項慎用,因爲除補丁之外,添加這個選項說明大概率是錯誤的合併。

  示例:

         git merge other(當前分支爲master)

2、變基

  變基(rebase),改變分支的基準點,流程如下:

  第一步,計算變基分支與當前分支的提交差集。

  第二步,重新創建差集中的每一個提交對象。

  第三步,變更變基分支與當前分支的基準點爲HEAD(默認值,可以提供commit標識指定基準點)。

  個人理解,rebase會修改有向無環圖,實際中不使用。但是它的優點也非常明顯,可以使有向無環圖變的非常清晰。

  例如dev, master分支,互相merge多次之後,有向無環圖會存在很多交叉點,非常亂。

2.1  場景

  存在三種情形。

  第一種情形,假設master,dev分支存在直接的基準點

  

  此時變基的過程如下:

  1. 創建新的提交對象D’, E’
  2. 將dev分支與master分支的基準點由A變爲C。

  第二種情形,假設master,dev分支存在間接的基準點。

  

  此時的變基過程如下:

  1. 計算dev分支與master分支的差集,上圖中爲D,E,F,G
  2. 創建新的提交對象D’,E’,F’,G’。
  3. master, dev分支的基準點變爲C, some,dev分支的基準點消失。

  

  具體的影響有:F,G提交消失,取而代之的是F’,G’。 D, E提交沒有變,但是新創建了D’,E’提交,它們的變更集與D,E 是一樣的。提交的歷史結構圖也發生了改變。

  第三種情形,假設master,dev分支存在直接基準點,但是dev分支上存在子分支

  

  此時的變基過程如下:

  1. 創建新的提交對象D’,E’
  2. dev,master分支的基準點由A變爲C。
  3. dev,some分支的基準點消失,some,master分支基準點爲A。

  

  可以看到整個過程也是多出了兩個提交,D’, E’,而且是重複的。

2.2  指令

  git rebase有三種指令格式:

  第一種, git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch),控制rebase流程的,略。

  第二種格式:

git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase> | --keep-base] [<upstream> [<branch>]]

  選項:

    -i,interactive爲交互模式,它會打開編輯器,允許修改整個DRG。壓縮,排序,修改單個提交對象等等。

    --exec <cmd>:執行1到N組shell腳本指令。略。

    --onto <newbase>:指定基準點。若指定的是分支,則爲分支的最近一次提交。

    upstream, branch:遠程分支名稱或本地分支名稱。

  第三種格式與第二種格式是類似的。

2.3  交互模式

  略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章