本文へ移動
技術を、自社の仕事に。
判断と実行を助けるメディア

記事を検索

GitHubに秘密情報をpush force pushで消えない場所

目次 · 7項目

.env をうっかりコミットしてGitHubにpushした。気づいてすぐに履歴から消し、git push --force で上書きした。これで消えた、と考えるのは早すぎます。GitHubの公式ドキュメントは、履歴を書き換えてforce pushしただけでは、秘密情報を含むコミットが別の場所から見られる状態で残りうると説明しています。

GitHubのドキュメントの原稿(github/docsリポジトリ)では、2026年11月5日に、この話に関わる2つのページが更新されました。一つは、force pushで上書きした履歴をGitHub上で取り戻す手順。もう一つは、秘密情報を削除するときに、サポートがプルリクエストをどう扱うかの説明です。本記事では、この2つの原文と、検証用のリポジトリで git-filter-repo を動かした結果から、誤ってpushしたときの順番を整理します。

最初にやるのは、履歴の削除ではなく鍵の無効化

「Removing sensitive data from a repository(リポジトリから機密データを削除する)」のページは、まずこう書いています。削除したいものがパスワードやトークンなどの秘密情報なら、最初の一歩はその秘密情報の失効・ローテーションである。失効すればもうアクセスには使えず、それで問題が片づくこともある。履歴を書き換える手間をかける必要はないかもしれない、と。

さらに、GitHubのサポートは機密でないデータの削除は行わず、影響を受けた認証情報のローテーションでリスクを抑えられないと判断した場合にだけ削除を手伝う、とも明記されています。APIキーなら、まず発行元で無効にして新しいキーに替える。履歴の削除まで進むのは、個人情報や顧客のソースコードのように、無効化できないものが入っていた場合だと考えられます。

force pushしても残る3つの場所

同じページは、履歴を書き換えてforce pushしただけの場合、秘密情報を含むコミットが次の場所で見られる可能性がある、としています。

  1. リポジトリのクローンとフォーク
  2. GitHub上の、キャッシュされた表示(SHA-1のハッシュを直接指定して開く)
  3. そのコミットを参照しているプルリクエスト

2つ目を裏づけるのが、11月5日に書き換えられた「Troubleshooting commits」のページです。force pushで上書きされたブランチの履歴は、非公開のリポジトリでも、GitHub上で取り戻せる場合があると書かれています。リポジトリのアクティビティの画面でブランチを選び、「Force pushes」に絞り込み、上書きされる前のコミット(before)のSHAを https://github.com/OWNER/REPO/tree/BEFORE_SHA の形で開く。開ければ、そこから新しいブランチを作れる、という手順です。条件は「以前のコミットがまだGitHub上で開けること」です。

チームの作業を救う手順としてはありがたい一方で、秘密情報の側から見れば、force pushの直後でも、古いコミットがGitHub上で開ける状態が続く場合があるということです(復元用のブランチを作るには書き込み権限が必要、と原文にあります)。

フォークに秘密情報を含むコミットがあれば、そこからは見られる状態が続きます。フォークの持ち主に、秘密情報の削除かフォークそのものの削除を頼む必要があり、GitHubは持ち主の連絡先を提供できないと書かれています。ほかの人の手元のクローンからも、GitHub側で消すことはできません。

GitHubで秘密情報をpushしたときの順番。最初に鍵を失効させる。次にgit-filter-repoで履歴を書き換えてforce pushする。ここまででも、クローンやフォーク、SHAで開くキャッシュされた表示、プルリクエストの参照に残りうる。サポートにプルリクエストの削除または参照の解除、ガベージコレクション、キャッシュの削除を依頼し、共同作業者はmergeではなくrebaseで取り込む

履歴の書き換え:検証用のリポジトリでgit-filter-repoを試した

ドキュメントが案内する道具は git-filter-repo で、--sensitive-data-removal を使える2.47以上が必要です。ファイルを丸ごと消す場合のコマンドは次のとおりです(ファイル名だけでなく、リポジトリ内のパスを指定する)。

git-filter-repo --sensitive-data-removal --invert-paths --path PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA

このコマンドを、検証用に作ったリポジトリで実行しました。GitHubではなく、裸のリポジトリに refs/pull/1/head などの参照を手で作り、プルリクエストの参照を模した環境です。鍵はダミーです。同じスクリプトを2つの環境で動かしました。一つはドラフトを書いたときの環境(Linux、git 2.43.0、git-filter-repo 2.47.0、コミットに自動で署名する設定)、もう一つは公開前の2026年11月11日に使ったmacOS 26.5.1の環境(git 2.49.0、git-filter-repo 2.47.0、署名なし)です。結果は次のとおりでした。

  • 実行すると、origin からすべての参照(+refs/*:refs/*)を取得したうえで書き換える、という通知が出た
  • 署名する設定の環境では、4件のコミットがすべて書き換わり、「First Changed Commit(s)」として最初のコミット(.env を含まない init)が表示された。git-filter-repo が署名を外したためと考えられる。ドキュメントの副作用の一覧にも、署名が無効になり、ツールが署名を取り除くと書かれている
  • 署名なしの環境では、書き換わったのは4件のうち3件で、「First Changed Commit(s)」は .env を加えたコミットだった
  • どちらの環境でも、書き換えたあと、.env を含むコミットは全参照で0件になった
  • 模したプルリクエストの参照は、.env 以降のコミットを指すものが新しいハッシュに変わった(署名する設定の環境では3つすべて、署名なしの環境では init を指す1つを除く2つ)

一つ注意が要る結果もありました。ドキュメントは、影響を受けるプルリクエストの数を次のコマンドで数えるよう案内しています。

grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs

2つの模擬環境のどちらでも、changed-refs に書かれたのは2つのブランチだけで、このコマンドの結果は 0 でした。プルリクエストを模した参照は実際には書き換わっていたにもかかわらずです。git-filter-repo 2.47.0のソースを読む限り、changed-refs の元になる参照の一覧は、origin からすべての参照を取得する前に記録されているように見えます(編集部の読みで、作者に確かめたものではありません)。GitHub上のリポジトリで同じになるかは確かめていません。ただ、サポートに伝える件数の確認として、書き換えの前に git ls-remote origin 'refs/pull/*/head' の結果を保存し、書き換えたあとの git for-each-ref 'refs/pull/*/head' と比べておくと、件数を二重に確かめられます。検証に使ったスクリプトと出力は、本記事の制作記録に残しています。

書き換えたあとは git push --force --mirror origin で上書きします。refs/pull/ で始まる参照はGitHub側で読み取り専用のため、pushに失敗するのは想定どおりです。それ以外が失敗する場合は、ブランチの保護を一時的に外す必要があります。

サポートへの依頼と、プルリクエストの扱い

GitHub上から完全に消すには、サポートへの依頼が必要です。伝える情報は、リポジトリの持ち主と名前、影響を受けるプルリクエストの数、git-filter-repo が出力した「First Changed Commit(s)」、LFSのオブジェクトが孤立した場合はその旨とファイルです。

プルリクエスト以外の参照をすべて片づけ、フォークにも参照が残っていない場合、サポートは次を行うとされています。

  • 影響を受けるプルリクエストの参照の解除、または削除
  • サーバーでのガベージコレクション
  • キャッシュされた表示の削除
  • LFSのオブジェクトが関わる場合は、その削除

11月5日の更新で、この1つ目に説明が加わりました。プルリクエストを丸ごと削除すると、会話・レビュー・差分がすべて消える。サポートは、プルリクエストの内部の参照だけを外す「dereferencing(参照の解除)」を提案することがあり、その場合は本文とコメントの履歴を残したまま、該当する過去の差分を見られなくできる。ただし、残した本文やコメントに引用された秘密情報は、参照の解除では消えない、という内容です。

レビューで「この行の鍵は消してください」とコメントに鍵を貼り付けていたら、参照を解除してもそのコメントは残ります。依頼の前に、プルリクエストのコメントに同じ値が書かれていないかを探しておくと、削除と参照の解除のどちらを頼むかを判断しやすくなります。

依頼のあとに、チームでやること

ドキュメントは、共同作業者に対して、古い履歴から作ったブランチはmergeではなくrebaseで取り込むよう求めています。一度のmergeで、消した履歴の一部または全部が戻りうるためです。書き換えの前のクローンを持つ人が git pull と git push を実行するだけで秘密情報が戻る、という再汚染の危険も、副作用の筆頭に挙げられています。

ここからは編集部の提案です。削除を始める前に、開いているプルリクエストをマージするか閉じておく(ドキュメントの推奨)。作業中は他の人のpushを止めてもらう。終わったら全員に再クローンを頼む。この3つを、作業の連絡と一緒に伝えておくと手戻りを減らせます。コードに鍵が入り込む経路の点検はソースコードのシークレット監査の記事で、CIのログに鍵が出た場合の検出はActionsのログのシークレットスキャンの記事で、Issueやプルリクエストに貼った画像やファイルの削除はGitHubの添付の記事で扱いました。

確認した範囲

2026年11月10日に、github/docsのコミット 453f91c(2026年11月5日、「Clarify pull request preservation during sensitive-data cleanup」)と 3521663(同日、「Update documentation for recovering history after force push」)の差分、確認時点(f309096、2026年11月9日)の「Removing sensitive data from a repository」「Troubleshooting commits」の原稿を確認しました。2026年11月11日に、docs.github.comの2つの公開ページが原稿と同じ内容であること、2つのページにその後の更新がないこと、git-filter-repoの最新のリリースが2.47.0のままであることを確認しました(資料調査)。git-filter-repo 2.47.0 は、模擬リポジトリ(GitHubのプルリクエストの参照を手で作ったもの)で、Linuxの環境(2026年11月10日)とmacOSの環境(2026年11月11日)で実行しました(実機検証)。GitHub上でのforce push、アクティビティの画面からの復元、サポートへの依頼は試していません。

鍵や顧客の情報がリポジトリに入ってしまったときの対応の段取りや、再発を防ぐ開発の仕組みづくりは、グリームハブの開発・AI・自動化のご相談で承っています。リポジトリの数や協力会社との体制によって手順が変わるため、お問い合わせからご相談ください。

参考資料

この記事を共有XFacebook
鈴木 翔

技術の可能性に魅了され、学生時代からプログラミングとデジタルアートの分野に深い関心を持つ

この記事のテーマを、自社の次の一歩へ

自社での進め方を、具体的に。

つくりたい仕組み、既存システム、運用の条件を整理し、実現に向けた次の一歩を考えます。

  • 実現したい仕組み
  • 既存環境との接続
  • 運用の条件
開発・運用の構想を相談する

構想段階からご相談いただけます。この記事の情報を相談フォームに引き継ぎます。

最新記事をメールで受け取る