乐趣区

关于git:利用gitfilterrepo无缝迁移git项目

背景

正所谓天下大事合久必分,分久必合。理论工作中的我的项目也相似,有的我的项目越来越大,或者有时候须要把没有前后端拆散的我的项目代码拆分到两个仓库里,就波及到对已有 git 我的项目的迁徙操作。

如果只是简略的把代码拆开并不难,能够抉择间接下载 git 我的项目源代码压缩包,拆分后 push 到新建的 git 仓库里就能够了。

然而事实世界往往没有那么简略,比方正在进行的开发分支还没有合并,或者咱们想保留提交记录和分支关系。如此种种原因导致无奈简略粗犷地把源代码扔到一个新建的 git 仓库里,还波及对 git 记录进行必要的裁剪。

本文就介绍一个好用的工具来进行无损的 git 仓库迁徙。

实在案例

在理论工作中,咱们有一个我的项目,其我的项目目录构造很简略,是一个既含有前端代码,也含有服务端代码的仓库,如下所示:

server/
   foo.c
   bar.c
webapp/
   app.tsx
   components/
           index.tsx
zebra.jpg

咱们心愿将前端和服务端代码拆分成两个独立的 git 仓库,然而因为开发同学还有正在开发的性能分支没有合并,因而咱们心愿可能同时迁徙代码和 git 提交历史以及分支。最终心愿失去的后果是:

git repo A: ./server/

git repo B: ./webapp/

git-filter-branch 命令

通过查看 git 文档,首先思考应用 git filter-branch 命令来进行迁徙。简略来说该命令能够用来操作目录树,同时批改历史提交记录。

在我还没来得及齐全了解这个命令之前,就看到文档中有这样一段warning

git filter-branch has a plethora of pitfalls that can produce non-obvious manglings of the intended history rewrite (and can leave you with little time to investigate such problems since it has such abysmal performance). These safety and performance issues cannot be backward compatibly fixed and as such, its use is not recommended. Please use an alternative history filtering tool such as git filter-repo. If you still need to use git filter-branch, please carefully read SAFETY (and PERFORMANCE) to learn about the land mines of filter-branch, and then vigilantly avoid as many of the hazards listed there as reasonably possible.

这里提到了 filter-branch 命令因为有可能产生芜杂的提交历史,以及惨不忍睹的执行效率,所以最终举荐了一个第三方工具 git filter-repo。接下来,就该明天的配角退场了。

git-filter-repo

github 首页上,对于 git-filter-repo 有这样的形容

git-filter-repo能够胜任很多须要批改提交历史的场景,尽管它与 git-filter-branch 命令性能有些许重合,但摒弃了 git-filter-branch 那令人抓狂的执行效率。

在性能方面,git-filter-repo的人机交互设计让其面对简略的批改更加熟能生巧,同时依然能够像简单的 git-filter-branch 命令一样实现庞杂的工作。

接下来咱们思考如何利用这个弱小的工具来进行 git 我的项目的迁徙。

首先,须要定义胜利迁徙的规范:

  • 删减 server 目录,仅保留 webapp 目录,并让 webapp 成为新的根目录
  • 推向新的 git 仓库
  • 确认在新的 git 仓库中依然保留所有与 webapp 相干的分支
  • 确认迁徙之后保留的分支历史记录应该与老仓库的历史记录统一

相干命令简介

查看 git-filter-repo 的文档能够看到有不少简略的示例,很侥幸有一些例子正好能够解决咱们的问题。

git-filter-repo的命令选项 (flag) 次要用来操作目录树,依据操作的目录树主动判断须要批改的 git 提交历史信息。

比方咱们须要保留 webapp 目录,删除 server 目录,那么仅需执行:

git filter-repo --path 'webapp/'

这样仓库中的目录构造就会变为:

webapp/
   app.tsx
   components/
           index.tsx

能够看到,曾经没有 server 文件夹了。

再比方如果咱们心愿删除.DS_Store 文件以及其提交历史:

git filter-repo --invert-paths --path '.DS_Store'

当然通常咱们须要删除根目录下所有.DS_Store 文件及其历史,那么能够加上 --use-base-name 选项,示意匹配文件名,而不是匹配残缺门路:

git filter-repo --invert-paths --path '.DS_Store' --use-base-name

其中 --path 选项后跟须要操作的门路或者文件名,--invert-paths选项字面意思是反向,因而该标记示意的是删除操作。

以上都是删除某些文件或者保留某些文件的操作,其目录构造依然会保留原始仓库的构造,但咱们须要的是仅保留 webapp 目录下的所有文件,并将其中的内容挪动到根目录下。针对这种场景 git-filter-repo 提供了一个叫做 --subdirectory-filter 的选项,接下来就进行实际操作。

实际操作

git-filter-repo须要在一个洁净的,刚刚 clone 下来的仓库中进行操作,否则会提醒操作并进行操作

接下来再看一下老的仓库目录构造

server/
   foo.c
   bar.c
webapp/
   app.tsx
   components/
           index.tsx
zebra.jpg

仅保留 webapp 目录下的内容,并让其成为新的根目录,执行如下命令:

git filter-repo --subdirectory-filter webapp/

执行后果的目录构造如下所示:

app.tsx
components/
    index.tsx

至此,目录构造曾经如愿实现,为了确认迁徙的历史记录也是残缺的,执行

git branch # 察看是否所有须要保留的分支依然存在
git log #察看分支的提交记录是否正确

如果确认本地仓库的迁徙后果正确,再执行命令将以后本地仓库推向迁徙的目标仓库即可:

git remote add <new-origin> git://somehost/some-project.git # 增加新的近程仓库
git push <new-origin> --all # 向新的仓库推送本地所有分支

至此咱们的 git 我的项目迁徙就实现了,不仅将代码迁徙到新的仓库,也同时将提交历史带去了新的仓库。这样一来,对于开发同学来说迁徙齐全是无痛的,只是切换了新的 git 地址,而开发过程齐全不会中断。

结语

在 git 我的项目须要迁徙的场景中,日常工作中兴许第一反馈就是让开发同学们放下手中的工作,全副推向一个指定用于迁徙的分支,而后以这个分支为准,下载源代码,再将其推送到新的仓库中。

这种操作形式尽管简略,然而对于开发同学来说,却会造成很多麻烦。

比方新仓库的代码不仅含有本人未开发实现的代码,也含有其他人未实现的代码,很有可能在迁徙实现之后我的项目都跑不起来。

而除此以外,如果新仓库的代码有一个须要很快就上线的性能,或者紧急修复,面对一个百废待兴的新仓库,如何整顿出一个能够上线的代码版本,又是一件十分头大的事件。

git-filter-branch能够帮忙咱们批改目录树和提交历史,然而执行效率和凌乱的提交历史显得太过于繁琐。

git-filter-repo工具提供了弱小的工具集,良好的用户应用界面,以及高效率的解决机制,在目前的确是解决仓库迁徙的最优抉择。

本文仅仅是解说了 git-filter-repo 的一种利用场景,其官网文档上有更多的应用场景,能够依据更多的条件来过滤和操作文件和提交历史。

更多的精彩还请移步官网文档:

git filter-repo github

git filter-repo 文档

退出移动版