簡體   English   中英

從 Git 歷史記錄中刪除敏感文件及其提交

[英]Remove sensitive files and their commits from Git history

我想在 GitHub 上放置一個 Git 項目,但它包含某些帶有敏感數據的文件(用戶名和密碼,如 capistrano 的 /config/deploy.rb)。

我知道我可以將這些文件名添加到.gitignore ,但這不會刪除它們在 Git 中的歷史記錄。

我也不想通過刪除 /.git 目錄重新開始。

有沒有辦法刪除 Git 歷史記錄中特定文件的所有痕跡?

出於所有實際目的,您應該擔心的第一件事是更改您的密碼! 從您的問題中不清楚您的 git 存儲庫是完全本地的還是其他地方是否有遠程存儲庫; 如果它是遠程的並且不受其他人的保護,那么您就會遇到問題。 如果有人在您修復此問題之前克隆了該存儲庫,他們將在其本地計算機上擁有您密碼的副本,並且您無法強制他們更新到您的“已修復”版本,因為它已從歷史記錄中消失。 您可以做的唯一安全的事情是將您的密碼更改為您使用過的任何其他地方。


有了這個,這里是如何解決它。 GitHub 在 FAQ 中准確地回答了這個問題

Windows 用戶注意事項:在此命令中使用雙引號 (") 而不是單引號

git filter-branch --index-filter \
'git update-index --remove PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' <introduction-revision-sha1>..HEAD
git push --force --verbose --dry-run
git push --force

2019 年更新:

這是常見問題解答中的當前代碼:

  git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" \
  --prune-empty --tag-name-filter cat -- --all
  git push --force --verbose --dry-run
  git push --force

請記住,一旦您將此代碼推送到 GitHub 等遠程存儲庫並且其他人克隆了該遠程存儲庫,您現在就處於重寫歷史記錄的情況。 當其他人在此之后嘗試下拉您的最新更改時,他們會收到一條消息,指示無法應用更改,因為它不是快進。

要解決此問題,他們必須刪除現有存儲庫並重新克隆它,或者按照git-rebase 聯機幫助頁中“從上游重新數據庫恢復”下的說明進行操作。

提示:執行git rebase --interactive


將來,如果您不小心提交了一些帶有敏感信息的更改,但您推送到遠程存儲庫之前注意到了,那么有一些更簡單的修復方法。 如果你最后一次提交是添加敏感信息,你可以簡單地刪除敏感信息,然后運行:

git commit -a --amend

這將使用您所做的任何新更改來修改之前的提交,包括使用git rm完成的整個文件刪除。 如果更改進一步追溯到歷史但仍未推送到遠程存儲庫,您可以執行交互式 rebase:

git rebase -i origin/master

這將打開一個編輯器,其中包含自您與遠程存儲庫的最后一個共同祖先以來所做的提交。 在任何代表帶有敏感信息的提交的行上將“pick”更改為“edit”,然后保存並退出。 Git 將完成更改,並將您留在一個地方,您可以:

$EDITOR file-to-fix
git commit -a --amend
git rebase --continue

對於帶有敏感信息的每個更改。 最終,您將返回到您的分支,並且您可以安全地推送新的更改。

更改密碼是一個好主意,但是對於從存儲庫歷史記錄中刪除密碼的過程,我建議使用BFG Repo-Cleaner ,它是git-filter-branch的更快、更簡單的替代方案,明確設計用於從 Git 存儲庫中刪除私有數據。

創建一個private.txt文件,列出您要刪除的密碼等(每行一個條目),然后運行以下命令:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git

將掃描存儲庫歷史記錄中低於閾值大小(默認為 1MB)的所有文件,並且任何匹配的字符串(不在您的最新提交中)將替換為字符串“***REMOVED***”。 然后您可以使用git gc清除死數據:

$ git gc --prune=now --aggressive

BFG 通常比運行git-filter-branch快 10-50 倍,並且選項圍繞這兩個常見用例進行了簡化和定制:

  • 刪除瘋狂的大文件
  • 刪除密碼、憑據和其他私人數據

完全披露:我是 BFG Repo-Cleaner 的作者。

如果你推送到 GitHub,強制推送是不夠的,刪除倉庫或聯系支持

即使您在之后強推一秒鍾,也不夠,如下所述。

唯一有效的行動方案是:

  • 是什么泄露了像密碼這樣的可變憑證?

    • 是的:立即修改您的密碼,並考慮使用更多的 OAuth 和 API 密鑰!

    • 不(裸照):

      • 您是否關心存儲庫中的所有問題是否都被破壞了?

        • 否:刪除存儲庫

        • 是的:

          • 聯系支持
          • 如果泄漏對您來說非常重要,以至於您願意讓存儲庫停機以減少泄漏的可能性,請在等待 GitHub 支持回復您的同時將其設為私有

強推一秒鍾是不夠的,因為:

但是,如果您刪除存儲庫而不是強制推送,則即使從 API 中提交也會立即消失並給出 404,例如https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a382即使您重新創建另一個具有相同名稱的存儲庫。

為了測試這一點,我創建了一個 repo: https : //github.com/cirosantilli/test-dangling並做了:

git init
git remote add origin git@github.com:cirosantilli/test-dangling.git

touch a
git add .
git commit -m 0
git push

touch b
git add .
git commit -m 1
git push

touch c
git rm b
git add .
git commit --amend --no-edit
git push -f

另請參閱: 如何從 GitHub 中刪除懸空提交?

現在正式推薦git filter-repo超過git filter-branch

這在 Git 2.5 本身的git filter-branch頁中提到。

使用 git filter repo,您​​可以刪除某些文件: 從 git/GitHub 的歷史記錄中刪除文件夾及其內容

pip install git-filter-repo
git filter-repo --path path/to/remove1 --path path/to/remove2 --invert-paths

這會自動刪除空提交。

或者您可以將某些字符串替換為如何替換整個 Git 歷史記錄中的字符串?

git filter-repo --replace-text <(echo 'my_password==>xxxxxxxx')

我推薦大衛安德希爾的這個劇本,對我來說就像一個魅力。

除了 natacado 的過濾器分支之外,它還添加了這些命令來清理它留下的混亂:

rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune

完整劇本(全部歸功於大衛安德希爾)

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter \
"git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch
# otherwise leaves behind for a long time
rm -rf .git/refs/original/ && \
git reflog expire --all && \
git gc --aggressive --prune

如果更改為以下最后兩個命令可能會更好地工作:

git reflog expire --expire=now --all && \
git gc --aggressive --prune=now

您可以使用git forget-blob

用法非常簡單git forget-blob file-to-forget 你可以在這里獲得更多信息

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

它將從您的歷史記錄、引用日志、標簽等中的所有提交中消失

我不時遇到同樣的問題,每次我必須回到這篇文章和其他文章時,這就是我自動化流程的原因。

感謝 Stack Overflow 的貢獻者,讓我把它們放在一起

這是我在 Windows 中的解決方案

git filter-branch --tree-filter "rm -f 'filedir/filename'" HEAD

git push --force

確保路徑正確,否則將無法工作

我希望它有幫助

使用過濾器分支

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch *file_path_relative_to_git_repo*' --prune-empty --tag-name-filter cat -- --all

git push origin *branch_name* -f

需要明確的是:接受的答案是正確的。 先試試。 但是,對於某些用例,它可能會不必要地復雜,特別是如果您遇到令人討厭的錯誤,例如“致命:錯誤修訂 --prune-empty”,或者真的不關心您的倉庫的歷史記錄。

另一種選擇是:

  1. cd 到項目的基本分支
  2. 刪除敏感代碼/文件
  3. rm -rf .git/ # 從代碼中刪除所有 git 信息
  4. 轉到 github 並刪除您的存儲庫
  5. 按照本指南,像往常一樣將代碼推送到新的存儲庫 - https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/

這當然會從你的 github 倉庫和你的本地 git 倉庫中刪除所有提交歷史分支和問題。 如果這是不可接受的,您將不得不使用替代方法。

稱之為核選項。

迄今為止,我不得不這樣做了幾次。 請注意,這一次僅適用於 1 個文件。

  1. 獲取修改文件的所有提交的列表。 底部的將是第一次提交:

    git log --pretty=oneline --branches -- pathToFile

  2. 要從歷史記錄中刪除文件,請使用第一個提交 sha1 和上一個命令中的文件路徑,並將它們填充到此命令中:

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <path-to-file>' -- <sha1-where-the-file-was-first-added>..

在我的 android 項目中,我將admob_keys.xml作為單獨的 xml 文件放在app/src/main/res/values/文件夾中。 為了刪除這個敏感文件,我使用了下面的腳本並且工作得很好。

git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch  app/src/main/res/values/admob_keys.xml' \
--prune-empty --tag-name-filter cat -- --all

所以,它看起來像這樣:

git rm --cached /config/deploy.rb
echo /config/deploy.rb >> .gitignore

從 git 中刪除跟蹤文件的緩存並將該文件添加到.gitignore列表

解決方案1:

使用 git filter-branch命令

例子:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch *file_relative_path*' --prune-empty --tag-name-filter cat -- --all

上面使用的術語是:

  • --prune-empty :如果您只想修剪變為空的提交,那么您甚至不需要指定此標志。 如果您想修剪在您的存儲庫中開始為空的提交,那么您需要始終指定 --prune-empty。
  • --tag-name-filter <command> :如果您只是指定--tag-name-filter cat ,那么正確的翻譯是不指定額外的標志。 filter-branch要求的事實是它被延遲的證據; 它應該是自動處理的。 (如果你使用'cat'以外的東西,即你真的在重命名標簽,那么有一個--tag-rename選項。)
  • -- --all :這是另一個證據,表明filter-branch在讓用戶指定本來應該是默認值的東西方面受到了阻礙。 扔掉它。
  • --index-filter <command> :這是用於重寫索引的過濾器。 它類似於樹過濾器,但不檢查樹,這使得它更快。 大多數人幾乎總是使用它來根據文件名修剪或保留文件,在這種情況下,您想使用各種 --path* 選項,如果指定修剪路徑而不是保留路徑,請使用--invert-paths

解決方案2(推薦方法):

使用 git filter-repo命令

git filter-repo現在被 git 項目推薦,而不是 git filter-branch因為filter-branch非常慢(比它應該慢多個數量級)。

例子:

git filter-repo --path *file_relative_path* --invert-paths

這里的(唯一)術語是:

  • --invert-paths :從指定的--path-{match,glob,regex}選項反轉文件選擇,即僅 select 文件與這些選項都不匹配。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM