Git多分支管理
Git多分支管理
問題背景
實際工作過程中如果既定版本號為1.0的釋出版本中包含兩個最新的產品特性,而這兩個特性分別由兩個小組並行開發,那麼兩個小組的特性分支開發完畢之後應該如何合併入1.0的釋出版本,不同merge引數帶來不盡相同的效果讓人容易混淆,這裡就專門對比一下常用引數的異同。
舉個例子
這裡我們假定有下面的情況:釋出版本號為1.0對應的分支名稱是release1.0,其下兩個特性分支名稱分別為feature1.0-1、feature1.0-2。初始狀態下release1.0、feature1.0-1、feature1.0-2均從master建立而來。feature1.0-1由team1開發,feature1.0-2由team2並行開發,其中team1、team2各有有三次提交,詳情如下。
commit 5f234c579c204e7a57de79380fd0412e234f37d8 (HEAD -> feature1.0-1, origin/feature1.0-1) Author: team1 <[email protected]> Date: Fri Jun 4 23:39:24 2021 +0800 team1 update file3 commit 157fe9c1104064c68f8b8b6dee92c60d0a9bc1bf Author: team1 <[email protected]> Date: Fri Jun 4 23:37:54 2021 +0800 team1 update file1 commit ae8352071aad40348ad287a4f1e7f27e6b37ad66 (origin/release1.0, origin/master, origin/feature1.0-2, origin/HEAD) Author: elfcafe <[email protected]> Date: Fri Jun 4 22:24:34 2021 +0800 init commit
team2三次提交:
hackun$ git log commit 0250a1956079ff91454e5251028a292dd941365b (HEAD -> feature1.0-2) Author: team2 <[email protected]> Date: Fri Jun 4 23:39:52 2021 +0800 team2 add file4 commit 9d3f9edbef2eb8e6f5d392827a64f1c444754a2a Author: team2 <[email protected]> Date: Fri Jun 4 23:38:53 2021 +0800 team2 upddte file2 commit ae8352071aad40348ad287a4f1e7f27e6b37ad66 (origin/release1.0, origin/master, origin/feature1.0-2, origin/feature1.0-1, origin/HEAD) Author: elfcafe <[email protected]> Date: Fri Jun 4 22:24:34 2021 +0800 init commit
這裡我們採用ff和no-ff兩種不同的merge引數進行合併來對比下merge不同的行為
ff模式
hackun$ git branch
* release1.0
hackun$ git log
commit ae8352071aad40348ad287a4f1e7f27e6b37ad66 (HEAD -> release1.0, origin/release1.0, origin/master, origin/HEAD)
Author: elfcafe <[email protected]>
Date: Fri Jun 4 22:24:34 2021 +0800
init commit
hackun$ git merge origin/feature1.0-1
Updating ae83520..5f234c5
Fast-forward
file1 | 1 +
file3 | 1 +
2 files changed, 2 insertions(+)
ff即fast-forward,作為git merge時候預設選項,merge執行提示中會顯示Fast-forward字樣,檢視執行過後的結果:
hackun$ git log --graph --decorate --pretty=oneline --abbrev-commit
* 5f234c5 (HEAD -> release1.0, origin/feature1.0-1) team1 update file3
* 157fe9c team1 update file1
* ae83520 (origin/release1.0, origin/master, origin/HEAD) init commit
此次合併只是把feature1.0-1中的兩次修改對映到了release1.0上,並沒有產生單獨的merge記錄
下面繼續合併feature1.0-2中的變更:
hackun$ git merge origin/feature1.0-2
......編輯提交資訊
Merge made by the 'recursive' strategy.
file2 | 1 +
file4 | 0
2 files changed, 1 insertion(+)
create mode 100644 file4
由於產生了獨立的merge提交,所以提交後的分支記錄如下:
hackun$ git log --graph --pretty=format:'%Cred%h%Creset %ad %s %C(yellow)%d%Creset %C(bold blue)<%an>%Creset' --date=short --date-order
* 99f5fab 2021-06-04 Merge remote-tracking branch 'origin/feature1.0-2' into release1.0 (HEAD -> release1.0) <elfcafe>
|\
| * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
* | 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| * 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
* | 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/release1.0, origin/master, origin/HEAD) <elfcafe>
no-ff模式
合併步驟大體都一致,不同的是我們在合併feature1.0-1、feature1.0-2時都使用了--no-ff引數
MacBookProEvo:release1.0_bak hackun$ git merge --no-ff origin/feature1.0-1
Merge made by the 'recursive' strategy.
file1 | 1 +
file3 | 1 +
2 files changed, 2 insertions(+)
MacBookProEvo:release1.0_bak hackun$ git merge --no-ff origin/feature1.0-2
Merge made by the 'recursive' strategy.
file2 | 1 +
file4 | 0
2 files changed, 1 insertion(+)
create mode 100644 file4
兩次merge的引數都指定了----no-ff,最後的效果如下:
MacBookProEvo:release1.0_bak hackun$ git log --graph --pretty=format:'%Cred%h%Creset %ad %s %C(yellow)%d%Creset %C(bold blue)<%an>%Creset' --date=short --date-order
* ed0543b 2021-06-05 Merge remote-tracking branch 'origin/feature1.0-2' into release1.0 (HEAD -> release1.0) <elfcafe>
|\
* \ 287a3c8 2021-06-04 Merge remote-tracking branch 'origin/feature1.0-1' into release1.0 <elfcafe>
|\ \
| | * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| * | 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| | * 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
| |/
|/|
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/release1.0, origin/master, origin/HEAD) <elfcafe>
這裡287a3c8作為feature1.0-1併入release1.0的節點,ed0543b代表feature1.0-2併入release1.0的節點,結構上非常清晰。
回退分支
回退分支主要針對release1.0而言,如果release1.0的兩次合併請求都採用了之前提到的(--no-ff方式)
尚未push
先看下都尚未push到remote的情況
這時候如果需要只保留feature1.0-1的分支特性(剔除team2開發feature1.0-2),那麼直接rest到HEADˆ,便輕鬆回退掉了feature1.0-2相關程式碼。
MacBookProEvo:release1.0_bak_orig hackun$ git reset HEAD^ --hard
HEAD is now at 287a3c8 Merge remote-tracking branch 'origin/feature1.0-1' into release1.0
hackun$ git log --graph --pretty=format:'%Cred%h%Creset %ad %s %C(yellow)%d%Creset %C(bold blue)<%an>%Creset' --date=short --date-order --all
* 287a3c8 2021-06-04 Merge remote-tracking branch 'origin/feature1.0-1' into release1.0 (HEAD -> release1.0) <elfcafe>
|\
| | * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| * | 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| | * 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
| |/
|/|
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/release1.0, origin/master, origin/HEAD) <elfcafe>
如果release1.0需要只保留feature1.0-2(剔除feature1.0-1),那麼是不是直接reset到HEADˆˆ就好了呢?我們來試試看:
hackun$ git reset HEAD^^ --hard
bogon:release1.0_noff hackun$ git lg
* 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| * 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
* | 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (HEAD -> release1.0, origin/release1.0, origin/master, origin/HEAD) <elfcafe>
可以看到release直接回退到了ae83520初始commit,team1和team2的提交都被無情退回了,顯然結果並不完全符合我們的預期。這時候我們需要重新合併一次team2的feature1.0-2分支。
hackun$ git merge -no-ff origin/feature1.0-2
error: did you mean `--no-ff` (with two dashes ?)
MacBookProEvo:release1.0_noff hackun$ git merge --no-ff origin/feature1.0-2
Merge made by the 'recursive' strategy.
file2 | 1 +
file4 | 0
2 files changed, 1 insertion(+)
create mode 100644 file4
hackun$ git lg
* 1bc9be6 2021-06-08 Merge remote-tracking branch 'origin/feature1.0-2' into release1.0 (HEAD -> release1.0) <elfcafe>
|\
| * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| | * 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| * | 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
|/ /
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/release1.0, origin/master, origin/HEAD) <elfcafe>
己經push
如果release1.0的兩次合併請求(--no-ff方式)已經push到了remote。
這時候如果需要只保留feature1.0-1的分支特性(剔除team2開發feature1.0-2)就需要revert對應的merge-c00569
MacBookProEvo:release1.0_noff hackun$ git show
commit c00569074fab8629823b3382411f9d2ddc231bc7 (HEAD -> release1.0, origin/release1.0)
Merge: 287a3c8 0250a19
Author: elfcafe <[email protected]>
Date: Mon Jun 7 16:42:44 2021 +0800
Merge remote-tracking branch 'origin/feature1.0-2' into release1.0
......
MacBookProEvo:release1.0_noff hackun$ git revert HEAD -m 1
[release1.0 f9ef0bb] Revert "Merge remote-tracking branch 'origin/feature1.0-2' into release1.0"
2 files changed, 1 deletion(-)
delete mode 100644 file4
MacBookProEvo:release1.0_noff hackun$ git lg
* f9ef0bb 2021-06-08 Revert "Merge remote-tracking branch 'origin/feature1.0-2' into release1.0" (HEAD -> release1.0) <elfcafe>
* c005690 2021-06-07 Merge remote-tracking branch 'origin/feature1.0-2' into release1.0 (origin/release1.0) <elfcafe>
|\
* \ 287a3c8 2021-06-04 Merge remote-tracking branch 'origin/feature1.0-1' into release1.0 <elfcafe>
|\ \
| | * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| * | 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| | * 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
| |/
|/|
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/master, origin/HEAD) <elfcafe>
對比當前版本與預期版本差異,no difference
hackun$ git diff HEAD 287a3c
如果需要只保留feature1.0-2的分支特性(剔除team1開發feature1.0-1)就需要revert對應的merge
hackun$ git revert 287a3c8 -m 1
[release1.0 4c0e9ae] Revert "Merge remote-tracking branch 'origin/feature1.0-1' into release1.0"
2 files changed, 2 deletions(-)
MacBookProEvo:release1.0_noff hackun$ git lg
* 4c0e9ae 2021-06-17 Revert "Merge remote-tracking branch 'origin/feature1.0-1' into release1.0" (HEAD -> release1.0) <elfcafe>
* c005690 2021-06-07 Merge remote-tracking branch 'origin/feature1.0-2' into release1.0 <elfcafe>
|\
* \ 287a3c8 2021-06-04 Merge remote-tracking branch 'origin/feature1.0-1' into release1.0 <elfcafe>
|\ \
| | * 0250a19 2021-06-04 team2 add file4 (origin/feature1.0-2) <team2>
| * | 5f234c5 2021-06-04 team1 update file3 (origin/feature1.0-1) <team1>
| | * 9d3f9ed 2021-06-04 team2 upddte file2 <team2>
| |/
|/|
| * 157fe9c 2021-06-04 team1 update file1 <team1>
|/
* ae83520 2021-06-04 init commit (origin/release1.0, origin/master, origin/HEAD) <elfcafe>
比較當前版本與預期版本差異 nodifference
hackun$ git diff 4c0e9ae 0250a19