Feature分支合并回滚后,子特性分支无法合并到Master的原因
Git合并后sub-feature分支变更缺失的原因解析
问题场景
- 存在2条特性分支:
feature-01、feature-02 - 存在1条子特性分支:
sub-feature-01 - 操作流程:
- 将
sub-feature-01合并到feature-01,随后回滚该合并操作 - 将
feature-01合并到master分支 - 将
sub-feature-01合并到feature-02 - 将
feature-02合并到master分支
- 将
- 结果:
master分支中未包含sub-feature-01的变更
提交历史可视化
* 985c298 (HEAD -> master) Merge branch 'feature-02' |\ | * 4f19fd8 (feature-02) Merge branch 'sub-feature-01' into feature-02 | |\ | * | d568a9f feature-02 commit 1 * | | 14a821c Merge branch 'feature-01' |\ \ \ | |/ / |/| | | * | 2ceae5b (feature-01) Revert "Merge branch 'sub-feature-01' into feature-01" | * | 1160f07 Merge branch 'sub-feature-01' into feature-01 | |\ \ | | |/ | | * 265d0e8 (sub-feature-01) Super-dooper feature | * | 79b5ad1 feature-01 commit 1 | |/ * | d8b0552 master commit 2 |/ * b013ef6 master commit 1 * 2d70803 initial commit
可复现脚本
# 1 - initial commit to master & commit to master git init echo "hi from master" > file-master.txt git add file-master.txt git commit -m "initial commit" echo "hi from master - part 2" >> file-master.txt git add file-master.txt git commit -m "master commit 1" # 2 - create super-dooper feature branch git checkout -b sub-feature-01 echo "this is the feature" > file-sub-feature.txt git add file-sub-feature.txt git commit -m "Super-dooper feature" # 2 - create feature-01, commit sth, merge super-dooper feature, and then revert it git checkout master git checkout -b feature-01 echo "hi from feature-01" > file-feature-01.txt git add file-feature-01.txt git commit -m "feature-01 commit 1" git merge --no-edit sub-feature-01 git revert --no-edit -m1 HEAD # 3 - master commit git checkout master echo "hi from master - part 3" >> file-master.txt git add file-master.txt git commit -m "master commit 2" # 4 - create feature-02, commit sth git checkout -b feature-02 echo "hi from feature-02" > file-feature-02.txt git add file-feature-02.txt git commit -m "feature-02 commit 1" # 5 - merge feature-01 to master git checkout master git merge --no-edit feature-01 # 6 - reapply merging sub-feature-01 to feature-02 git checkout feature-02 git merge --no-edit sub-feature-01 # 7 - merge feature-02 git checkout master git merge-base master feature-02 git merge --no-edit --stat feature-02 ls # I expected to see file-sub-feature.txt but it's not here !!! # git log --all --decorate --oneline --graph
核心原因:Git基于提交可达性判断变更是否已处理
Git的合并逻辑不关注文件内容的变更是否存在,只判断提交是否已经在目标分支的可达历史中:
- 当
sub-feature-01合并到feature-01后,sub-feature-01的提交(265d0e8)已被纳入feature-01的历史。后续的回滚操作(2ceae5b)只是生成了一个撤销变更的新提交,但原合并提交(1160f07)和sub-feature-01的提交仍然保留在历史里。 - 当
feature-01合并到master后,master的历史就已经包含了sub-feature-01的所有提交(从master的HEAD往上追溯,能找到265d0e8)。 - 合并
feature-02到master时,Git会先找到两者的共同祖先(d8b0552),对比从共同祖先到两边的差异。但因为sub-feature-01的提交已经在master的可达历史中,Git会判定这些变更“已经被处理过”——即使回滚操作撤销了内容,Git只认提交存在性,不会检查内容是否有效。因此合并时会跳过sub-feature-01的变更,不会将其重新引入master。
补充说明:回滚合并提交的特殊性
普通的git revert是撤销单个提交的变更,但回滚合并提交时,Git无法直接“取消合并”,只能生成一个反向的变更提交来抵消合并带来的修改。这种情况下,原被合并分支的提交仍然存在于主分支的历史中,后续其他分支再合并该子分支时,Git会认为这些提交已经被合并过,不会重复应用变更。
如果需要重新将sub-feature-01的变更引入master,不能通过合并的方式,而是需要用git cherry-pick将sub-feature-01的提交重新应用到master,或者基于最新的master重新创建sub-feature-01的变更提交。
内容的提问来源于stack exchange,提问作者mzakrze
相关产品推荐
相关产品推荐

