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 <team1@gmail.com>
Date:   Fri Jun 4 23:39:24 2021 +0800

    team1 update file3

commit 157fe9c1104064c68f8b8b6dee92c60d0a9bc1bf
Author: team1 <team1@gmail.com>
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 <remote@kov.com>
Date:   Fri Jun 4 22:24:34 2021 +0800

    init commit

team2三次提交:

hackun$ git log
commit 0250a1956079ff91454e5251028a292dd941365b (HEAD -> feature1.0-2)
Author: team2 <team2@gmail.com>
Date:   Fri Jun 4 23:39:52 2021 +0800

    team2 add file4

commit 9d3f9edbef2eb8e6f5d392827a64f1c444754a2a
Author: team2 <team2@gmail.com>
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 <remote@kov.com>
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 <remote@kov.com>
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 <remote@kov.com>
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

posted @ 2021-06-17 19:22  ElfCafe  阅读(325)  评论(0编辑  收藏  举报