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