git-filter-repo
を使ってgitの履歴の書き換えを行った。
目的
うっかりローカルのパスの文字列をハードコードしたままpushしてしまったため、これをなかったことにしたいと思った。
少し具体的に述べると、/ukkari/path
を/some/path/to/foo
のように書き換えようと思った。
個人のリモートレポジトリにpushまでしていたので、これを修正することを最終目的としたい。
調査
書き換えツールについて、適当に調べると、git filter-branch
というものがあるそうだが、これは公式のツールであるにも関わらず、非推奨(ドキュメントページ)になっており、代わりに、git filter-repoを使ってほしいと書いてある。
どうやら公式のツールは効率的でないらしい。推奨された通り、git filter-repo
を使うことにする。
用意
git filter-repo
は1つのPythonファイルで提供されており、自分で/usr/local/binフォルダなどに配置してかまわないらしい。普通にPythonモジュールとしてインストールもできるし、パッケージマネージャでも提供されているようだ。
上記にもあるが下記のgithubレポジトリを参照:
使ったコマンド
--dry-run
を付けてテストするといい。ドキュメント通り、cloneしたてのものを使えば安心。
ちょっと迷走したが、最終的に履歴を書き換えるためのコマンドは以下:
# ==>の左側の内容にマッチする部分を==>の右側に書き換える。
git-filter-repo --replace-text <(echo '/ukkari/path==>/some/path/to/foo')
書き変わるのはスナップショットの部分で、--path
でファイル名を指定すると、そのファイル以外は消えてしまうようだった。--invert-paths
を付けると、反転できるようだが、今度は指定したファイルが消えてしまうと思う。(未実施)
remoteを再指定してpush
git filter-repo
で履歴の書き換えを行った時点でremoteorigin
などは消去(移動?)される。そのため、リモートレポジトリにプッシュするときは再びgit remote add origin URL
する必要がある。
そして、ハッシュが合わないので、git push -u -f origin main
でプッシュする必要がある。
ここまで行えば最終目的は達成できる。
他に使いそうなコマンド
# 特定のファイルをすべての履歴から削除
git-filter-repo --path filepath_to_be_deleted --invert-paths
--invert-paths
を付けないでおくと、--path
で指定したファイルだけ残してすべて消えるので注意。
フィルターして反転するイメージを持っていれば間違いにくいと思う。
globや正規表現も使えるようだ。やはり--invert-paths
には気をつけたい。
参考
参考: