Git Subtree合并共享同名目录的两个供应商项目问题
解决Git Subtree合并重叠目录时保留双方文件并维护提交历史的问题
问题背景
需要将两个持续迭代的供应商交付包(VendorDropA、VendorDropB)合并到同一个Git项目,两者的library/common目录包含不同文件,合并后需保留双方文件,且后续能同步各自的更新历史。之前直接使用subtree merge会导致一方文件被覆盖,尝试多种参数均无效。
核心解决方案
由于两个仓库的library/common路径相同但文件无冲突,直接subtree merge会触发Git的版本替换逻辑。我们可以通过临时重命名其中一个仓库的common目录再拆分,让Git识别为独立的文件来源,合并后再恢复到目标路径,同时保留提交历史。
分步操作
1. 初始化主项目并关联远程仓库
git clone https://git/project/VendorDropTest.git cd VendorDropTest # 添加两个供应商仓库作为远程源 git remote add -f VendorDropA https://git/project/VendorDropA.git git remote add -f VendorDropB https://git/project/VendorDropB.git
2. 拆分VendorDropA的子树分支
直接按原路径拆分,因为它是第一个被合并的源:
# 拆分VendorDropA的library/common到分支VendorACommon git subtree split --prefix library/common --remote VendorDropA --branch VendorACommon # 拆分VendorDropA的library/libA到分支VendorALib git subtree split --prefix library/libA --remote VendorDropA --branch VendorALib
3. 临时处理VendorDropB的common目录并拆分
通过临时分支重命名目录,避免与VendorDropA的路径冲突:
# 拉取VendorDropB最新代码到临时分支 git checkout -b temp-b VendorDropB/main # 临时重命名library/common为library/common-b git mv library/common library/common-b git commit -m "temp: rename common to common-b for subtree split" # 拆分重命名后的目录到分支VendorBCommon git subtree split --prefix library/common-b --branch VendorBCommon # 回到主分支并清理临时分支 git checkout main git branch -D temp-b
4. 合并所有子树到主项目
# 合并VendorACommon到library/common git subtree add --prefix library/common VendorACommon --squash # 合并VendorBCommon到library/common(自动将common-b下的文件放到common目录) git subtree add --prefix library/common VendorBCommon --squash # 合并VendorALib到library/libA git subtree add --prefix library/libA VendorALib --squash # 拆分并合并VendorDropB的libB目录 git subtree split --prefix library/libB --remote VendorDropB --branch VendorBLib git subtree add --prefix library/libB VendorBLib --squash
后续同步更新方法
同步VendorDropA的更新
直接拉取对应子树的最新代码:
# 同步library/common git subtree pull --prefix library/common VendorDropA main --squash # 同步library/libA git subtree pull --prefix library/libA VendorDropA main --squash
同步VendorDropB的更新
需要重复临时重命名的步骤,确保拆分的分支包含最新变更:
# 更新临时分支并重新命名目录 git checkout -b temp-b VendorDropB/main git pull VendorDropB main git mv library/common library/common-b git commit -m "temp: rename common to common-b for subtree split" # 重新拆分到VendorBCommon分支(覆盖旧分支) git subtree split --prefix library/common-b --branch VendorBCommon --rejoin # 回到主分支并清理临时分支 git checkout main git branch -D temp-b # 同步到主项目的library/common git subtree pull --prefix library/common VendorBCommon --squash # 同步library/libB(直接拉取) git subtree pull --prefix library/libB VendorDropB main --squash
替代方案:修改VendorDropB的历史路径
如果允许修改VendorDropB的仓库历史,可以用git filter-repo永久将library/common重命名为library/common-b,之后直接按新路径拆分合并,无需每次同步都临时处理:
# 克隆VendorDropB的本地副本 git clone https://git/project/VendorDropB.git temp-vendorB cd temp-vendorB # 重命名历史中的library/common为library/common-b git filter-repo --path-rename library/common:library/common-b # 推送到新的远程仓库(或覆盖原仓库,需谨慎) git push origin main --force # 回到主项目,关联修改后的仓库并拆分 cd ../VendorDropTest git remote remove VendorDropB git remote add -f VendorDropB ../temp-vendorB git subtree split --prefix library/common-b --remote VendorDropB --branch VendorBCommon
内容的提问来源于stack exchange,提问作者Oscar
相关产品推荐
相关产品推荐

