今日やったこと

  • Gitで一度管理していたファイルを、履歴から完全に削除する方法を整理した
  • .gitignore に追加するだけでは、過去にコミット済みのファイルは消えないことを確認した
  • 現在の管理対象から外す操作と、過去の履歴から削除する操作の違いを確認した
  • 履歴を書き換える場合は、git filter-repo などの専用ツールを使うことを確認した
  • 履歴を書き換えたあとは、リモートリポジトリへ --force 付きで push する必要があることを確認した

学んだこと

Gitで管理していたファイルを削除するときは、目的によって操作が変わる。

現在のコミットからファイルを消したいだけであれば、通常の git rm を使えばよい。

git rm path/to/file
git commit -m "Remove file"

ただし、この方法では過去のコミット履歴にはファイルが残る。

たとえば、誤ってパスワード、APIキー、秘密鍵、大きすぎるバイナリファイルなどをコミットしてしまった場合は、現在のコミットから削除するだけでは不十分になる。

その場合は、履歴そのものを書き換えて、過去のコミットからも対象ファイルを削除する必要がある。

代表的には、git filter-repo を使う。

git filter-repo --path path/to/file --invert-paths

このコマンドは、指定したファイルを履歴全体から取り除くためのもの。

  • --path path/to/file
    • 履歴から削除したいファイルを指定する
  • --invert-paths
    • 指定したパス以外を残す、つまり指定したファイルを削除する

ディレクトリごと履歴から削除したい場合は、ディレクトリを指定する。

git filter-repo --path path/to/directory/ --invert-paths

履歴を書き換えたあとは、コミットIDが変わる。

そのため、リモートリポジトリに反映する場合は通常の git push ではなく、force push が必要になる。

git push origin main --force

タグも含めて履歴を書き換えた場合は、タグも force push する必要がある。

git push origin --tags --force

ただし、履歴の書き換えは影響が大きい操作なので、共有リポジトリで実行する場合は注意が必要。

すでに他の人が clone や pull している場合、その人のローカルリポジトリと履歴が食い違う。

そのため、実行前にチームへ共有し、必要であれば再 clone してもらう方が安全。

また、秘密情報を削除した場合でも、すでに外部に漏れている可能性は残る。

そのため、APIキーやパスワードを誤ってコミットした場合は、履歴から削除するだけでなく、キーの無効化や再発行も必要になる。

あいまいなこと

  • git filter-repogit filter-branch の違い
  • 履歴を書き換えたあと、他の作業者のローカルリポジトリをどう復旧するのがよいか

次にやること

  • git filter-repo のインストール方法を確認する
  • 履歴を書き換えたあとのチーム作業者向け手順を整理する
  • 誤って秘密情報をコミットしないための .gitignore や pre-commit の使い方を整理する