質問: 適当なディレクトリを作り以下を走らせて複数のコミットをつくりました。 ``` git init touch readme.md echo "hoge" >> readme.md git add -A git commit -m "init" mkdir ignore_wasure touch ignore_wasure/file1 touch ignore_wasure/file2 git add -A && git commit -m"ignore_wasureを生成" touch file3 git add -A && git commit -m"コミット" echo "hogehogehoge" >> ignore_wasure/file2 git add -A && git commit -m"ignore_wasure内を編集" ``` その後、ignore_wasure/file2だけをインデックスから外すべく以下を実行しました。 ``` git filter-branch --force --index-filter 'git rm --cached -rf --ignore-unmatch ignore_wasure/file2' --prune-empty -- --all ``` するとindex-filterにて--cachedを指定しているにも関わらず処理完了後にはワーキングツリーからignore_wasure/file2が消滅してしまっていました。 この原因がなぜだかわかる方がいらっしゃったらご教示願いたいです。 (etc 目指していたのは、全てのコミットからignore_wasure/file2のインデックスが外されており、ワーキングツリーにはignore_wasure/file2が残っているという状態でした。)
回答: こんにちは。 https://teratail.com/questions/228663 にて回答依頼のためここに書き残します。 filter-branch はまともに使ったことがないコマンドなので実際にどのような処理が行われているのかは理解していませんが、--index-filter の場合はインデックスツリー上で改変操作を行った後、最後に改変の結果をワーキングディレクトリに反映しているように見えます。 インデックスツリー上の操作において git rm --cached は単なる rm と区別がつかないため、インデックス上で削除したファイルは最終的にワーキングからも削除される動作になっている気がします。 コマンドは変えずに、 `--index-filter` を `--tree-filter` に置き換えるだけで目的の結果が得られるのではないかと思います。 また、どうせ filter-branch をかけるのであれば、同時に .gitignore の内容も編集し、「最初から当該ファイルは ignore されていた」状態にしてしまうのも良いかと思います。 ``` 'git restore -s <最終形の.gitignoreを含むコミットのid> -WS .gitignore && git rm --cached -rf --ignore-unmatch ignore_wasure/file2' ``` 試す前にリポジトリのバックアップは忘れずにお願いします。 ところで、filter-branch でリポジトリから特定のファイルを削除するということは、「当該ファイルをバージョン管理の対象外にする」という意味であるため、ファイルを先にリポジトリの「外」にバックアップを取り、処理後に手でポン置きするだけでも意図した形に収まると思うのですが。 Git によるファイル操作は、管理されたファイルに対しては強い信頼性がありますが、管理されないファイルには全く関知しません。