prettierを使って過去のコミットをすべてフォーマットする
困ったことに
古い古い自社ライブラリのお話です。はじめのコードはインデントが4で作成されていました。後から入ってきた私はJavaScriptのファイルのインデントは2と聞かされておりましたので、IDEの設定で2にしておいたのです。
古いライブラリなので改修の頻度は少ないですが、新規の機能を作成しました。新しく作成されたファイルはインデントが2で書かれました。気づかないレビュー者。見かねてEslintを入れてくれました。EditorConfigも入れてくれました。EslintとEditorConfigでインデントが食い違っています。2なのか4なのか、混乱するIDE。私は悲しみました。
eslint --fix
で直るよ!
直ります!しかし、こんな話が上がりました。
Aさん > git annotate
で見れるのが、全てフォーマット修正のコミットになるのがつらいかも...
私 > 確かに!!
古いライブラリで実装を理解している人間も少ないため、修正についてはコミットを追う必要がありました。私もデグレードが起きないように行単位でコミットを追っていました。
歴史を変えるしかない...
事前準備
グローバルにprettier
をインストールしておいてください。
$ yarn global add prettier
本題
git annotate
を変更しないためには、過去に存在する全てのコミットに対して、フォーマットを行った状態で再度コミットするという必要があります。
そこで、git filter-branch
を使用します。このコマンドで調べると、「コミットしてしまった秘密鍵を削除する」「コミットのEmail, Authorを変更する」という内容が多く出てきます。歴史を変えるための最強のコマンドです。
# 現状のブランチの全てのコミット
$ git filter-branch -f --tree-filter 'prettier --no-config --print-width=120 --write "src/**/**.js" || echo "Error"' --
# 全てのブランチの全てのコミット
$ git filter-branch -f --tree-filter 'prettier --no-config --print-width=120 --write "src/**/**.js" || echo "Error"' -- --all
# 特定のブランチの特定のコミットからコミットまで
# コミット間の指定が面倒なので、ブランチを作成して指定している
$ git filter-branch -f --tree-filter 'prettier --no-config --print-width=120 --write "src/**/**.js" || echo "Error" from_branch..to_branch
これらのコマンドによって全てのコミットのインデントが2に修正されているはずです。
一つ問題点
インデント以外もフォーマットされるので、正直何が起こるか予測が難しいかも。
特定のルールのみ修正するのであれば、Eslintで行うのがいいかもしれないです。
$ git filter-branch -f --tree-filter 'eslint --fix --no-eslintrc --rule "indent: [\"error\", 2]" --parser-options "ecxaVersion: 2017" --env "es6" "src/**/**.js" || echo "Error"' --
コミットの数分だけ実行するので、実行速度がprettierよりも遅いのが懸念点ではあります。
最後に
規模のでかいリポジトリであれば、Eslintの実行に時間がかかるでしょう。filter-branchを使用した後はブランチの取り直し、面倒であればgit clone
を行う必要があります。
元も子もないですが、コミットのログを気にしないのであれば、普通にフォーマットしてコミットしてあげればいいと思います。
Discussion