$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

あるレポジトリを別のレポジトリのサブディレクトリへ履歴付きで移動する

あるレポジトリのサブディレクトリ配下を別のレポジトリへ履歴付きで移行する - $shibayu36->blog; の逆バージョン。

あるレポジトリでずっと開発していたが、やっぱりモノレポの中に入れたいとなって、履歴付きでモノレポの特定のサブディレクトリ配下に移動したい時があった。たとえば https://github.com/shibayu36/go_todo_app の履歴をすべて https://github.com/shibayu36/go-playground のgo_todo_appディレクトリに移したいみたいなケースだ。この時コミット履歴としてはgo-playgroundのgo_todo_app/配下で初めから開発していたかのように移したい。

この解決策として Gitのサブツリーのマージについて - GitHub Docs にあるように、サブツリーマージという方法も取れる。しかしこちらは履歴的にはレポジトリルートで開発した後にgit mvでサブディレクトリに移したような履歴になってしまう。これだとgit logなどで変更を追いかけづらい。

そこで今回もgit filter-repoを使って移動する。作戦としては

  • go_todo_appレポジトリ側で、go_todo_app/ディレクトリで開発しているような履歴に変更する
  • go-playgroundレポジトリのremoteとしてgo_todo_appレポジトリを追加し、mergeコミットを作ってサブディレクトリ配下で開発していたような履歴を作る

ではやってみよう。まずはgit-filter-repoを入れておく。

brew install git-filter-repo

続いて、go_todo_appレポジトリ側で、go_todo_app/ディレクトリで開発しているような履歴に変更する。git filter-repoの--to-subdirectory-filterを使うと簡単にできる。

git clone git@github.com:shibayu36/go_todo_app.git
cd go_todo_app
git filter-repo --to-subdirectory-filter go_todo_app
cd ..

さらにgo-playgroundへgo_todo_appレポジトリの履歴をマージする。

git clone git@github.com:shibayu36/go-playground.git
cd go-playground
git remote add go_todo_app ../go_todo_app # localのディレクトリをremoteとして追加
git fetch go_todo_app main
# --allow-unrelated-historiesを使うことで別の履歴をマージできる
# --no-ffを使ってマージコミットを確実に作る
git merge --allow-unrelated-histories --no-ff go_todo_app/main
git push origin main

これで完了。go-playgroundレポジトリの履歴は こちらのようになり、さらにhttps://github.com/shibayu36/go-playground/commits/main/go_todo_appを見るとgo_todo_app/サブディレクトリ配下で初めから開発していたような履歴になっている。