

サブディレクトリの切り出しはgit filter-repoが本命、filter-branchは非推奨
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
モノレポの中の一部フォルダだけを、履歴を保ったまま別リポジトリに切り出したかった。git filter-branchでやろうとしていたが、公式マニュアルに非推奨と明記されていた。今は git filter-repo が推奨ツールになっている。
結論
- サブディレクトリの切り出しは
git filter-repo --subdirectory-filter <folder>でやる git filter-branch --subdirectory-filterも同じことができるが、公式に非推奨扱い- 元のfilter-branchのコマンドも参考として残しておく
git filter-repoでの切り出し
インストールはPython製なのでpipかHomebrewで入る。
pip install git-filter-repo# またはbrew install git-filter-repoサブディレクトリを新しいルートとして切り出す場合。
git filter-repo --subdirectory-filter <folder>filter-branchと違って、デフォルトで「フレッシュなclone上でしか実行できない」安全策が入っている。既存の作業リポジトリでそのまま実行すると弾かれるので、別途cloneしてから作業するのが前提になっている。
タグも維持したい場合はプレフィックスを付けて残せる。
git filter-repo --subdirectory-filter <folder> --tag-rename '':'my-module-'元のfilter-branchでのやり方(参考)
filter-repo登場以前はこう書いていた。今でも動くには動くが、公式ドキュメントで非推奨と書かれている。
git filter-branch --prune-empty --subdirectory-filter <folder> HEAD--subdirectory-filter で指定フォルダを新しいルートとして扱うよう全コミットのツリーを書き換える。--prune-empty はフィルタ後に差分がなくなったコミットを削除するオプションだが、公式マニュアルに「稀に消し損なうバグがある」と書かれている。HEAD は現在のブランチだけが対象で、他のブランチやタグも書き換えたいなら --all が要る。
実行後の後片付けを忘れると容量が減らない。
rm -rf .git/refs/original/git reflog expire --expire=now --allgit gc --prune=nowあと履歴のSHAが全部変わるので、共同作業者がいる場合は全員再cloneが必要になる。filter-repoでもこの点は変わらない。