たとえばRailsでscaffoldをやり直すときに、これまでは変更ファイルをgit checkout -- .
で元に戻していました(正確にはシェルスクリプトとして~/bin/に置いて使っていました)。なおrails destroy scaffold
だとたまに消しそびれることもあったのであまり使ってませんでした。
この場合、既存のファイルのunstagedな変更は取り消されますが、scaffoldなどで追加されたuntrackedなファイルやディレクトリは削除されないので、いちいち手動で消していました(git clean -i
でインタラクティブに削除する習慣がなかったのでした)。
scaffoldしては消しを繰り返すうちにこの作業がだんだん面倒になってきて、たまたま見かけたgit clean -fdx
で一発削除を試みました。
すると何ということでしょう、.gitignoreで避けておいたもの(.envファイルやnode_modules/フォルダなど)まで綺麗サッパリ消えてしまいました😇。やっちまった...幸いプロジェクトディレクトリを複製してあったので復旧はできましたが。
参考: git cleanで.gitignore対象のファイルが消えてしまう話
解決方法
- 「unstagedの変更ファイル」を元に戻す
- 「untrackedの追加ファイル」「untrackedの追加ディレクトリ」を削除する
- .gitignoreで避けているファイルを誤って削除する心配がない
以上を満たす方法がないかと思って探してみると、下の2つを満たす方法がStack Overflowにありましたので、これをgit checkout -- .
と併用することにしました。
参考: How to preserve all ignored files in git clean -fd? - Stack Overflow
# unstagedの変更ファイルを元に戻す
git checkout -- .
# 「untrackedの追加ファイル」「untrackedの追加ディレクトリ」を安全に削除する
git ls-files -z -o --exclude-standard | xargs -0 rm -rf
上のシェルスクリプトを~/bin/に置きました。私のように作っては消しが多い人にはありがたいです😋。もう少し込み入った状況であれば、git clean -i
で慎重にやることにします。
おまけ
上の解決方法は微妙にトリッキーでした。
-z
: 出力を\0
で区切って1行にまとめる-o
: untrackedファイルを出力する--exclude-standard
: 除外の指定(.gitignore、.git/info/excludeなど)を有効にする
xargs
の-0
というオプションが気になって調べたところ、NUL文字(\0
)をデリミタとみなす指定でした。
git ls-files -z -o --exclude-standard > test.txt
して中身を見ると、白い?
で区切られています。
いつもお世話になっているUnicode code converterにかけてみると、\0
であることがわかります。