はじめに
リモートリポジトリから機密データを削除する際に調べたことを備忘のためにまとめます。
- 参考にしたGitHubのヘルプページ:機密データをリポジトリから削除する
- Gitのドキュメント https://git-scm.com/book/ja/v2 を引いて、普段使わないコマンドで何をやっているか確認しながら進めました
前提
- Git version: 2.26.1
- トランクベース開発のため、masterブランチのみが作業対象でした(他のブランチも対象にする場合は未検証です)
- タグは使っていなかったので、タグ周りのコマンドは省略しています(→上のGitHubヘルプページが参考になると思います)
手順
- 手順確認用のブランチでリハーサルする
- 他のブランチで実行する
A.手元のローカルリポジトリでの作業
# 機密データが含まれているコミットを確認
$ git log -- ファイル名
# 機密データをリポジトリから削除(全ブランチの場合は--allを指定すると思われる)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch 機密データを含むファイルへのパス" \
--prune-empty
# 先のgit logコマンドで機密データを含むコミットがないことが確認できる
# 以下は2.他のブランチでの作業の中で実行
# リモートリポジトリのブランチを上書き(--all指定により全ブランチを上書き)
git push origin --force --all
B.他の開発者の手元のリポジトリでの作業
リモートリポジトリのブランチを上書きした後の作業。
ローカルにリモートリポジトリを強制的にpullする。
# 前提: カレントブランチはmaster
# リモートのmasterブランチをフェッチ
git fetch origin master
# ローカルリポジトリのインデックスと作業ディレクトリにある変更がなくなるので注意
git reset --hard origin/master
参考
コマンド調査事項メモ
git log
最後に紹介する git log のフィルタリング用オプションは、パスです。 ディレクトリ名あるいはファイル名を指定すると、それを変更したコミットのみが対象となります。 このオプションは常に最後に指定し、一般にダブルダッシュ (--) の後に記述します。
git filter-branch
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
-
--index-filter
とgit rm
の組合せはtree-filter
とrm
より速い -
--force
:refs/original/
で始まるrefがあったり、一時ディレクトリで開始したりすることを拒否しないようにする指定 -
--prune-empty
:filter-branchによりできる空のコミットを削除(枝刈り)する指定
git rm
-
--cached
:インデックスからのみアンステージし、削除する指定 -
--ignore-unmatch
:1つもファイルが一致しなかったとしてもステータスコード0(正常終了)で終了する指定 -
--dry-run
あり
git push
git fetch origin master
ローカルリポジトリのリモート追跡ブランチを更新。
リモート追跡ブランチは以下の記事が分かりやすかったです。
【Git】リモートからの取得とリモートへの反映で行っていること(fetch,pull,push)
git reset --hard
現在のブランチの内容を、リモート追跡ブランチ(ここではorigin/master
)と同じにしている。
7.7 Git のさまざまなツール - リセットコマンド詳説
--hard
は「HEAD が指し示すブランチを移動」し、「インデックスの内容を HEAD と同じに」し、「作業ディレクトリの内容をインデックスと同じにする」
→インデックスと作業ディレクトリの変更はなくなる
所感
filter-branch
コマンドで機密データを削除できました。
ただ、変更したmasterブランチのpullを開発者全員にお願いする必要がありました。
小さなチームでもこれは大変でした。
なので、filter-branch
コマンドは本当に最終手段で、機密データをpushしないようにする手段を整えていくのがよさそうです。
以上です。