はじめに
先日、git-filter-repoでファイルの履歴を削除しました。
git-filter-repoの使い方メモ(Windows11) - Miraxto Blog
しかし、削除したいファイルの中に制御文字が入ったファイル名のファイルがあり、そのファイルの履歴は削除できませんでした。
今回は制御文字がファイル名に入っている場合にgit-filter-repoで履歴を削除した方法をまとめます。
WARNING当記事は個人的なメモであり、内容の正確性について十分に確認できていません。ご了承の上、参考程度にご覧ください。
記事の内容は履歴を削除するものであり、一度行うともとに戻すことができない危険な操作が含まれています。実行する場合は自己責任でお願いします。
また、git-filter-repoを使用する際は以下の公式のドキュメントを参照してください。
前提
IMPORTANT
- Windows11
- Anaconda上のPythonを使用(Anaconda Promptを使用します)
- git-filter-repoはAnacondaにインストールしてあります(
conda install conda-forge::git-filter-repo
)
今回はAnaconda上のPythonを使用しているためAnaconda Promptを使用していますが、Anaconda Promptの部分はコマンドプロンプトで実行しても問題ないと思われます。
作業準備
現在作業をしているディレクトリとは関係のないディレクトリに移動して対象リポジトリを新しくクローンします。
例:C://develop/exampleで作業している場合はC://develop/に移動してクローン
cd ..git clone [作業対象リポジトリのURL]
上の作業により現在のディレクトリの下に[リポジトリ名]が作成されます。
例:C://develop/[リポジトリ名]/
cd [リポジトリ名]
ファイル名とバイト列を確認
Git Bashで以下のコマンドを実行します。
NOTEコミットIDは
git log
を実行することで削除したいファイルが含まれるコミットのIDを確認できます。
Git logの使い方(公式ドキュメント)
指定したコミットIDのコミットのすべてのファイル一覧(ファイル名 → バイト列)をbyte-dump.txt
(ファイル名は任意)というファイルに出力します。バイト列を表示しているのは目に見えない制御文字を確認するためです。
git ls-tree -r [コミットID] --name-only | while IFS= read -r path; do printf '%s → ' "$path" echo -n "$path" | xxd -g1 -p echo; done > byte-dump.txt
例として以下のようなディレクトリ構造とします。
example.txt
example/
└── example2.md
上のコマンドを実行すると以下のような形式でファイルに出力されます。バイト列は16進数で表示されています。
左側:ファイル名、右側:ファイル名の16進数で表したもの
example.txt → 6578616d706c652e747874example/example2.md → 6578616d706c65322e6d64
制御文字が含まれているか確認する際には以下のようなサイトで16進数のバイト列を文字列に変換して確認することができます。
16進数バイナリ文字列変換 日本語変換 Online - DenCode
削除するファイルのリストを作成
↑の手順で表示されたファイル名(ファイルパスも含めて)を制御文字を含むバイト列に変換して、delete-list-escaped.txt
(ファイル名は任意)というファイルに出力します。
1回目は>
、2回目以降は>>
で追記します。
printf '[ファイル名1]' > delete-list-escaped.txt#追記する場合printf '[ファイル名2]' >> delete-list-escaped.txt
作成したファイルリストを表示して確認する。
xxd -g1 delete-list-escaped.txt
履歴からファイル履歴を削除
Anaconda Promptで以下のコマンドを実行して、履歴から制御文字が入ったファイル名のファイルを削除します。(git-filter-repoの実行)
git-filter-repo --invert-paths --paths-from-file delete-list-escaped.txt --force
リモートリポジトリに反映する
git-filter-repoを実行するとローカルリポジトリに紐づけたリモートリポジトリの情報が消えるため、再度リモートリポジトリを設定します。
git remote add origin [リモートリポジトリのURL]
強制的にプッシュしてリモートリポジトリにローカルリポジトリの内容を反映します。
git push --force --mirror origin