diff --git a/blog/git-large-project-split.md b/blog/git-large-project-split.md new file mode 100644 index 0000000..32c72e7 --- /dev/null +++ b/blog/git-large-project-split.md @@ -0,0 +1,142 @@ +--- +slug: git-large-project-split +title: "Git 大工程拆分:保留历史提交记录的详细指南" +authors: lxy +tags: [ Git, 版本控制, 项目管理, 代码重构, DevOps ] +--- + +在项目迭代过程中,随着代码量与模块复杂度不断攀升,将一个大型 Git 工程拆分为多个独立工程,能让项目结构更清晰,便于团队协作与维护。关键是要保留完整的提交历史,这就需要借助 Git 的 `filter-branch` 工具来实现。 + +## 一、准备工作 + +### 使用 filter-branch +`git filter-branch` 是 Git 内置的强大工具,无需额外安装,可以直接使用。虽然相比 `filter-repo` 效率稍低,但功能完整且稳定可靠。 + +**验证可用性:** +```bash +git filter-branch --help +``` + +### 备份原仓库 +拆分前务必备份原仓库,防止操作失误导致数据丢失: +```bash +git clone --mirror 原仓库地址 备份仓库地址 +``` + +## 二、拆分示例 + +假设原仓库有两个独立模块,需拆分为: +- **工程 A**:只保留 `module-a/` 目录及相关历史 +- **工程 B**:只保留 `module-b/` 目录及相关历史 + +## 三、具体步骤 + +### 拆分工程 A + +#### 1. 克隆原仓库 +```bash +git clone 原仓库地址 工程A +cd 工程A +``` + +#### 2. 使用 filter-branch 保留指定目录 +```bash +git filter-branch --prune-empty --subdirectory-filter module-a master +``` + +**参数说明:** +- `--subdirectory-filter module-a`:将 `module-a` 目录作为新仓库的根目录 +- `--prune-empty`:删除空提交 +- `master`:指定要重写历史的分支 + +#### 3. 清理无关分支(可选) +```bash +# 查看所有分支 +git branch -a + +# 删除不需要的分支 +git branch -D 无关分支名 +git branch -dr origin/无关分支名 +``` + +#### 4. 提交到新仓库 +```bash +# 关联新仓库 +git remote add origin 工程A的新仓库地址 + +# 推送所有分支和标签 +git push -u origin --all +git push --tags +``` + +### 拆分工程 B + +按照相同步骤操作: +```bash +# 重新克隆原仓库 +git clone 原仓库地址 工程B +cd 工程B + +# 只保留 module-b 目录 +git filter-branch --prune-empty --subdirectory-filter module-b master + +# 关联工程 B 的远程仓库并推送 +git remote add origin 工程B的新仓库地址 +git push -u origin --all +git push --tags +``` + +## 四、重要说明 + +### 历史完整性 +`filter-branch` 会重写提交历史,只保留与指定目录相关的提交(包括修改、删除、重命名等操作),其他提交会被过滤,最终历史记录"干净"且相关。 + +### 处理大型仓库 +若仓库体积大(含大量大文件),可先清理超大文件: +```bash +# 使用 filter-branch 清理大文件 +git filter-branch --tree-filter 'rm -f large_file.zip' HEAD +``` + +### 高级用法 +`filter-branch` 提供了多种过滤方式: + +**按文件大小过滤:** +```bash +git filter-branch --tree-filter 'find . -size +10M -delete' HEAD +``` + +**按文件类型过滤:** +```bash +git filter-branch --tree-filter 'rm -rf *.log' HEAD +``` + +**保留多个目录:** +```bash +git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch module-c module-d' HEAD +``` + +## 五、高级用法 + +### 复杂目录结构拆分 +如果需要拆分更复杂的目录结构,可使用以下方法: + +**使用 tree-filter 进行复杂操作:** +```bash +# 只保留特定文件类型 +git filter-branch --tree-filter 'find . -name "*.js" -o -name "*.ts" | xargs rm -f' HEAD + +# 排除特定目录 +git filter-branch --tree-filter 'rm -rf temp/ build/ node_modules/' HEAD + +# 重命名目录结构 +git filter-branch --tree-filter 'mkdir -p new_structure && mv module-a/* new_structure/' HEAD +``` + +**使用 index-filter 提高性能:** +```bash +# 只保留指定目录(性能更好) +git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch module-b module-c' HEAD +``` + +通过以上步骤,两个新工程会分别保留原仓库中与自身模块相关的完整提交历史,且相互独立。这样既保持了代码的连续性,又实现了模块的独立管理。