1001 文字
5 分
git-filter-repoで制御文字が入ったファイル名のファイル履歴を削除する

はじめに#

先日、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 Bash
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進数で表したもの

byte-dump.txt
example.txt → 6578616d706c652e747874
example/example2.md → 6578616d706c65322e6d64

制御文字が含まれているか確認する際には以下のようなサイトで16進数のバイト列を文字列に変換して確認することができます。
16進数バイナリ文字列変換 日本語変換 Online - DenCode

削除するファイルのリストを作成#

↑の手順で表示されたファイル名(ファイルパスも含めて)を制御文字を含むバイト列に変換して、delete-list-escaped.txt(ファイル名は任意)というファイルに出力します。 1回目は>、2回目以降は>>で追記します。

Terminal window
printf '[ファイル名1]' > delete-list-escaped.txt
#追記する場合
printf '[ファイル名2]' >> delete-list-escaped.txt

作成したファイルリストを表示して確認する。

Terminal window
xxd -g1 delete-list-escaped.txt

履歴からファイル履歴を削除#

Anaconda Promptで以下のコマンドを実行して、履歴から制御文字が入ったファイル名のファイルを削除します。(git-filter-repoの実行)

Anaconda Prompt
git-filter-repo --invert-paths --paths-from-file delete-list-escaped.txt --force

リモートリポジトリに反映する#

git-filter-repoを実行するとローカルリポジトリに紐づけたリモートリポジトリの情報が消えるため、再度リモートリポジトリを設定します。

Terminal window
git remote add origin [リモートリポジトリのURL]

強制的にプッシュしてリモートリポジトリにローカルリポジトリの内容を反映します。

Terminal window
git push --force --mirror origin

参考リンク#