git仓库拆分/合并团队分支必须用git filter-repo做路径重写和提交筛选,否则提交哈希变更导致git blame断层、ci缓存失效、pr关联丢失;不能仅靠git branch或cherry-pick。

Git 仓库如何保留完整历史地拆分/合并团队分支
直接说结论:不能靠 git branch 或 git checkout 解决组织架构调整带来的代码归属变化;必须用 git filter-repo(或已弃用但仍在用的 git filter-branch)做路径重写 + 提交筛选,否则历史提交作者、时间、变更范围全丢失。
常见错误是把旧仓库 clone 下来,新建分支再手动 cherry-pick —— 这样所有提交哈希全部改变,git blame 断层,CI 构建缓存失效,PR 关联丢失。真正要保留历史,就得在提交层面操作。
-
git filter-repo是当前唯一推荐工具(比git filter-branch快 10 倍以上,且不执行 shell 注入风险) - 必须用
--mailmap映射旧团队成员邮箱到新组织域,否则git log --author查不到人 - 若原仓库含敏感文件(如密钥),必须同步加
--strip-blobs-bigger-than 10M或--invert-paths --path删除,否则迁移后仍存在泄露风险
按新团队边界提取子目录并重写历史提交路径
组织调整常伴随模块归属变更,比如前端组接管了原属后端的 webapp/ 目录,但该目录历史混在主仓里。这时不能只 git subtree split,它不重写 commit author 和 timestamp,也不清理无关路径的 blob。
正确做法是用 git filter-repo 按路径提取,并重写所有提交中的文件路径前缀:
git filter-repo \ --path webapp/ \ --path-rename webapp/:/ \ --mailmap .mailmap \ --force
注意点:
-
--path-rename的冒号左右不能有空格,否则报错invalid path rename spec - 如果目标目录在历史中曾被移动过(如从
src/web/改名到webapp/),需额外加--path src/web/并用--path-rename多次映射 - 执行后原仓库所有未匹配
--path的提交彻底消失,不可逆,务必先备份.git目录
多团队共管模块时如何避免分支命名冲突与推送权限混乱
调整后常出现“前端团队 push 到 main,后端团队也想 push 到 main”——这不是 Git 问题,是远程权限和分支保护规则没同步更新。
关键不是改分支名,而是用 Git 服务端策略控制:
- GitHub/GitLab 上关闭
main的直接 push 权限,强制走 PR;为各团队设置专属team-frontend/*、team-backend/*命名空间分支 - 在
.github/workflows/ci.yml或.gitlab-ci.yml中加判断:if: $CI_COMMIT_REF_NAME == 'main' || startsWith($CI_COMMIT_REF_NAME, 'team-'),避免 CI 在临时分支上浪费资源 - 禁止使用
git push --force-with-lease到共享长期分支;对main和release/*启用 branch protection rule + require linear history
迁移后如何让开发者无缝切换而不破坏本地工作区
最常被忽略的一环:开发者本地还有未合入的 feature 分支、stashed 修改、未提交暂存区。强行换仓库地址会导致 git status 显示大量 deleted/modified,甚至误删文件。
安全切换步骤:
- 让所有人先
git stash当前修改,git checkout main && git pull确保本地main与旧远端一致 - 管理员提供新仓库地址后,运行:
git remote set-url origin <new-url></new-url>,再git fetch --all - 若旧分支名在新仓中已重命名(如
dev→team-frontend/dev),用git branch -m dev team-frontend/dev重命名本地分支,再git branch --set-upstream-to=origin/team-frontend/dev
特别注意 git worktree 用户:每个 worktree 都要单独执行 set-url 和 fetch,不能只改主工作区。











