说来惭愧,这篇是AI帮助我解决实际问题后,又生成的一篇博客,效率特别高。

在开发中,我们常会遇到一个项目变大、拆分或者整合的需求。如果你想将一个已有 Git 提交历史的小项目(例如:bbb/)合并到另一个新的 Git 仓库(例如 GitHub 上新建的仓库 aaa),并保留其所有提交历史记录,这篇博客将为你总结完整的操作流程和注意事项。

🧩 问题背景

我本地有一个项目叫 bbb/,它是一个完整的 Git 仓库,有自己的提交历史。但我后来希望将它作为子目录的形式迁入另一个新的仓库 aaa/ 中去,也就是想要实现结构如下:

aaa/
└── bbb/     # 原项目内容在这里,保留所有 commit 历史

但是直接复制粘贴代码会丢失原始提交历史记录;而直接合并 .git 会导致仓库结构错乱。


🧪 我遇到的问题

一开始,我使用了 git filter-repo 来把项目目录转换成子目录的历史,但目录嵌套出现了问题,执行完:

python -m git_filter_repo --to-subdirectory-filter bbb --force

之后,目录变成了:

bbb/bbb/your-files...

也就是说,子目录又包了一层自己的名字,导致整个目录嵌套了一层,不符合我的预期。


✅ 正确的操作流程

以下是正确的迁移流程,总结如下:


📁 假设目录结构如下

/your-path/
├── bbb/   # 原项目,有完整 Git 历史

🔨 步骤 1:在 GitHub 上创建新仓库 aaa

比如:

  • 仓库名:aaa

  • GitHub 地址:git@github.com:yourname/aaa.git


🧪 步骤 2:在 bbb 目录中运行 git filter-repo

需要安装 git filter-repo ,教程可查看附录。

这一步会把整个项目的 Git 历史“包裹进” bbb/ 子目录中:

cd bbb
python -m git_filter_repo --to-subdirectory-filter bbb --force

执行完后,项目结构会变成:

bbb/
└── bbb/
    └── your-original-code...

(此时你的代码被包进了 bbb/


🧼 步骤 3:整理目录结构(可选)

这里你需要把 bbb/bbb/ 中提交的数据拉回到 bbb/ 中。


🌐 步骤 4:推送到远程仓库(aaa)

  1. 初始化 GitHub 仓库(如果还没 init 的话):

    git remote add origin git@github.com:yourname/aaa.git

  2. 推送代码及其历史记录:

    git push -u origin main
    

如果你当前分支不是 main,请先切换:git checkout -b main


🎉 最终效果

在 GitHub 上打开 aaa 仓库,你将看到代码出现在 bbb/ 子目录中,且每一次提交都被完整保留。


📎 附录:如何安装 git_filter_repo

git_filter_repo 是一个替代 git filter-branch 的高效工具,用于重写 Git 历史。由于它不是 Git 默认安装的一部分,我们需要手动安装。

✅ 方法一:通过 pip 安装(推荐)

适合大多数开发者,只需要有 Python 环境即可。

pip install git-filter-repo

安装后,你可以通过以下方式使用:

python -m git_filter_repo --help

⚠️ 注意:如果你运行 git filter-repo 报错(如 “git: 'filter-repo' is not a git command”),说明你的环境变量中没有自动添加别名,建议直接使用:

python -m git_filter_repo ...


✅ 方法二:手动安装脚本并加入 Git 命令目录(进阶)

适合想直接使用 git filter-repo 命令的用户:

  1. 前往 GitHub 下载脚本:

    👉 https://github.com/newren/git-filter-repo

  2. 下载 git-filter-repo.py 文件,重命名为 git-filter-repo(无后缀)

  3. 将该文件放入 Git 的执行目录中,例如:

    C:\Program Files\Git\mingw64\libexec\git-core\

  4. 确保该目录在系统环境变量 PATH 中

完成后,即可直接使用任一命令:

git filter-repo ...
python -m git_filter_repo ... //或使用Python命令