从 Git 历史记录中删除敏感文件及其提交

发布于 2024-07-19 07:27:52 字数 255 浏览 12 评论 0原文

我想在 GitHub 上放置一个 Git 项目,但它包含某些包含敏感数据的文件(用户名和密码,例如 capistrano 的 /config/deploy.rb)。

我知道我可以将这些文件名添加到 .gitignore 中,但这不会删除它们在 Git 中的历史记录。

我也不想通过删除 /.git 目录重新开始。

有没有办法删除 Git 历史记录中特定文件的所有痕迹?

I would like to put a Git project on GitHub but it contains certain files with sensitive data (usernames and passwords, like /config/deploy.rb for capistrano).

I know I can add these filenames to .gitignore, but this would not remove their history within Git.

I also don't want to start over again by deleting the /.git directory.

Is there a way to remove all traces of a particular file in your Git history?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

万劫不复 2024-07-26 07:27:52

出于所有实际目的,您应该担心的第一事情是更改您的密码!从您的问题中不清楚您的 git 存储库是否完全是本地的,或者您是否有一个其他地方的远程存储库还没有; 如果它是远程的并且不受其他人的保护,那么您就会遇到问题。 如果有人在您修复此问题之前克隆了该存储库,他们将在本地计算机上拥有您的密码副本,并且您无法强迫他们更新到您的“固定”版本,使其从历史记录中消失。 您可以做的唯一安全的事情就是将您使用过的密码更改为其他密码。


解决这个问题后,以下是解决方法。 GitHub 作为常见问题解答准确回答了该问题

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 。 如果更改在历史记录中更早,但仍未推送到远程存储库,您可以执行交互式变基:

git rebase -i origin/master

这将打开一个编辑器,其中包含自您与远程存储库的最后一个共同祖先以来所做的提交。 在表示包含敏感信息的提交的任何行上将“pick”更改为“edit”,然后保存并退出。 Git 将遍历这些更改,并让您处于可以执行以下操作的位置:

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

对于包含敏感信息的每个更改。 最终,您将回到您的分支,并且可以安全地推送新的更改。

For all practical purposes, the first thing you should be worried about is CHANGING YOUR PASSWORDS! It's not clear from your question whether your git repository is entirely local or whether you have a remote repository elsewhere yet; if it is remote and not secured from others you have a problem. If anyone has cloned that repository before you fix this, they'll have a copy of your passwords on their local machine, and there's no way you can force them to update to your "fixed" version with it gone from history. The only safe thing you can do is change your password to something else everywhere you've used it.


With that out of the way, here's how to fix it. GitHub answered exactly that question as an FAQ:

Note for Windows users: use double quotes (") instead of singles in this command

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

Update 2019:

This is the current code from the FAQ:

  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

Keep in mind that once you've pushed this code to a remote repository like GitHub and others have cloned that remote repository, you're now in a situation where you're rewriting history. When others try pull down your latest changes after this, they'll get a message indicating that the changes can't be applied because it's not a fast-forward.

To fix this, they'll have to either delete their existing repository and re-clone it, or follow the instructions under "RECOVERING FROM UPSTREAM REBASE" in the git-rebase manpage.

Tip: Execute git rebase --interactive


In the future, if you accidentally commit some changes with sensitive information but you notice before pushing to a remote repository, there are some easier fixes. If you last commit is the one to add the sensitive information, you can simply remove the sensitive information, then run:

git commit -a --amend

That will amend the previous commit with any new changes you've made, including entire file removals done with a git rm. If the changes are further back in history but still not pushed to a remote repository, you can do an interactive rebase:

git rebase -i origin/master

That opens an editor with the commits you've made since your last common ancestor with the remote repository. Change "pick" to "edit" on any lines representing a commit with sensitive information, and save and quit. Git will walk through the changes, and leave you at a spot where you can:

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

For each change with sensitive information. Eventually, you'll end up back on your branch, and you can safely push the new changes.

记忆消瘦 2024-07-26 07:27:52

更改密码是个好主意,但对于从存储库历史记录中删除密码的过程,我建议 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 的作者。

Changing your passwords is a good idea, but for the process of removing password's from your repo's history, I recommend the BFG Repo-Cleaner, a faster, simpler alternative to git-filter-branch explicitly designed for removing private data from Git repos.

Create a private.txt file listing the passwords, etc, that you want to remove (one entry per line) and then run this command:

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

All files under a threshold size (1MB by default) in your repo's history will be scanned, and any matching string (that isn't in your latest commit) will be replaced with the string "***REMOVED***". You can then use git gc to clean away the dead data:

$ git gc --prune=now --aggressive

The BFG is typically 10-50x faster than running git-filter-branch and the options are simplified and tailored around these two common use-cases:

  • Removing Crazy Big Files
  • Removing Passwords, Credentials & other Private data

Full disclosure: I'm the author of the BFG Repo-Cleaner.

不美如何 2024-07-26 07:27:52

git filter-repo 现在正式推荐超过 git filter-branch

这是在 git filter-branch 的联机帮助页中提到的Git 2.5 本身中的代码>。

使用 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')

如果你推送到 GitHub,强制推送还不够,请删除存储库或联系支持

即使你在一秒后强制推送,也是如此如下所述还不够。

唯一有效的行动方案是:

  • 是什么泄露了密码等可更改凭证?

    • 是:立即修改您的密码,并考虑使用更多 OAuth 和 API 密钥!

    • 没有(裸照):

      • 您关心存储库中的所有问题是否都被解决了吗?

稍后强制推送是不够的,因为:

但是,如果您删除存储库而不是仅仅强制推送,提交甚至会立即从 API 中消失并给出 404,例如 https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 即使您重新创建另一个同名的存储库,这也有效。

为了测试这一点,我创建了一个存储库: https://github.com/cirosantilli/test-dangling< /a> 并做了:

git init
git remote add origin [email protected]: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 is now officially recommended over git filter-branch

This is mentioned in the manpage of git filter-branch in Git 2.5 itself.

With git filter repo, you could either remove certain files with: Remove folder and its contents from git/GitHub's history

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

This automatically removes empty commits.

Or you can replace certain strings with: How to replace a string in whole Git history?

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

If you pushed to GitHub, force pushing is not enough, delete the repository or contact support

Even if you force push one second afterwards, it is not enough as explained below.

The only valid courses of action are:

  • is what leaked a changeable credential like a password?

    • yes: modify your passwords immediately, and consider using more OAuth and API keys!

    • no (naked pics):

      • do you care if all issues in the repository get nuked?

        • no: delete the repository

        • yes:

          • contact support
          • if the leak is very critical to you, to the point that you are willing to get some repository downtime to make it less likely to leak, make it private while you wait for GitHub support to reply to you

Force pushing a second later is not enough because:

If you delete the repository instead of just force pushing however, commits do disappear even from the API immediately and give 404, e.g. https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824 This works even if you recreate another repository with the same name.

To test this out, I have created a repo: https://github.com/cirosantilli/test-dangling and did:

git init
git remote add origin [email protected]: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

See also: How to remove a dangling commit from GitHub?

披肩女神 2024-07-26 07:27:52

我推荐 David 的这个脚本安德希尔(Underhill)对我来说就像一种魅力。

除了 natacado 的过滤器分支之外,它还添加了这些命令,以清理它留下的混乱:

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

完整脚本(全部归功于 David Underhill)

#!/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

I recommend this script by David Underhill, worked like a charm for me.

It adds these commands in addition natacado's filter-branch to clean up the mess it leaves behind:

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

Full script (all credit to David Underhill)

#!/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

The last two commands may work better if changed to the following:

git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
遗弃M 2024-07-26 07:27:52

您可以使用gitforget-blob

用法非常简单gitforget-blob file-to-forget。 您可以在此处获取更多信息:

它将从你的历史记录、引用日志、标签等中的所有提交中消失

我时不时地遇到同样的问题,每次我必须回到这篇文章和其他文章,这就是为什么我自动化了这个过程。

感谢 Stack Overflow 的贡献者,让我能够将这些内容整合在一起

You can use git forget-blob.

The usage is pretty simple git forget-blob file-to-forget. You can get more info here:

It will disappear from all the commits in your history, reflog, tags and so on

I run into the same problem every now and then, and everytime I have to come back to this post and others, that's why I automated the process.

Credits to contributors from Stack Overflow that allowed me to put this together

放手` 2024-07-26 07:27:52

这是我在windows下的解决方案

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

git push --force

确保路径正确
否则它不会工作

我希望它有帮助

Here is my solution in windows

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

git push --force

make sure that the path is correct
otherwise it won't work

I hope it helps

眼泪淡了忧伤 2024-07-26 07:27:52

使用过滤分支

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

Use filter-branch:

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
梦途 2024-07-26 07:27:52

需要明确的是:接受的答案是正确的。 先试试吧。 然而,对于某些用例来说,它可能不必要地复杂,特别是如果您遇到令人讨厌的错误,例如“致命:错误的修订--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 存储库中的问题。 如果这是不可接受的,您将不得不使用替代方法。

称之为核选项。

To be clear: The accepted answer is correct. Try it first. However, it may be unnecessarily complex for some use cases, particularly if you encounter obnoxious errors such as 'fatal: bad revision --prune-empty', or really don't care about the history of your repo.

An alternative would be:

  1. cd to project's base branch
  2. Remove the sensitive code / file
  3. rm -rf .git/ # Remove all git info from
    your code
  4. Go to github and delete your repository
  5. Follow this guide to push your code to a new repository as you normally would -
    https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/

This will of course remove all commit history branches, and issues from both your github repo, and your local git repo. If this is unacceptable you will have to use an alternate approach.

Call this the nuclear option.

演出会有结束 2024-07-26 07:27:52

在我的 Android 项目中,我在 app/src/main/res/values/ 文件夹中将 admob_keys.xml 作为单独的 xml 文件。 为了删除这个敏感文件,我使用了下面的脚本并且工作得很好。

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

In my android project I had admob_keys.xml as separated xml file in app/src/main/res/values/ folder. To remove this sensitive file I used below script and worked perfectly.

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
不甘平庸 2024-07-26 07:27:52

迄今为止我已经这样做过几次了。 请注意,这一次仅适用于 1 个文件。

  1. 获取修改文件的所有提交的列表。 底部的将是第一个提交:

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

  2. 要从历史记录中删除文件,请使用第一个提交 sha1 和文件路径来自上一个命令,并将它们填充到此命令中:

    git filter-branch --index-filter 'git rm --cached --ignore-unmatch <文件路径>' --..

I've had to do this a few times to-date. Note that this only works on 1 file at a time.

  1. Get a list of all commits that modified a file. The one at the bottom will the the first commit:

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

  2. To remove the file from history use the first commit sha1 and the path to file from the previous command, and fill them into this command:

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

所谓喜欢 2024-07-26 07:27:52

考虑到 OP 使用 GitHub,如果将敏感数据提交到 Git 存储库,则可以使用前面的选项之一将其从历史记录中完全删除(请在下面阅读有关它们的更多信息):

  1. git 过滤器 - repo 工具(在 GitHub 上查看源代码)。

  2. BFG Repo-Cleaner 工具(它是开源的 - 在 GitHub 上查看源代码)。

在执行上述选项之一之后,还需要执行其他步骤。 检查下面的其他部分。

如果目标是删除最近未推送的提交中添加的文件,请阅读下面的替代部分。

为了将来考虑,为了防止类似情况发生,请检查下面的未来部分。


选项 1

使用 git filter-repo< /a>. 在继续之前,请注意

如果您在存储更改后运行 git filter-repo,您将无法使用其他存储命令检索您的更改。 在运行 git filter-repo 之前,我们建议取消存储您所做的任何更改。 要取消存储的最后一组更改,请运行 git stash show -p | git apply -R 。 有关更多信息,请参阅 Git 工具 - 存储和清理< /a>.


现在让我们从存储库的历史记录中删除一个文件并将其添加到 .gitignore (以防止再次重新提交)。

在继续之前,请确保已安装 git filter-repo (在此处阅读如何安装它),并且拥有存储库的本地副本(如果不是这种情况,在此处查看如何克隆存储库)。

  1. 打开 GitBash 并访问存储库。

    cd 您的存储库 
      
  2. (可选)备份 .git/config 文件。

  3. 运行

    git filter-repo --invert-paths --path 带有敏感数据的文件路径 
      

    PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA替换为要删除的文件的路径,而不仅仅是其文件名到:

    • 强制 Git 进行处理,但不检查每个分支和标签的完整历史记录。

    • 删除指定文件(以及由此生成的空提交)

    • 删除一些配置(例如存储在 .git/config 文件中的远程 URL)

    • 覆盖现有标签

  4. 将包含敏感数据的文件添加到.gitignore

    echo“您的文件与敏感数据”>>   .gitignore 
    
      git add .gitignore 
    
      git commit -m“将带有敏感数据的文件添加到.gitignore” 
      
  5. 检查是否已从存储库历史记录中删除所有内容,以及是否已签出所有分支。 然后才能进入下一步。

  6. 强制推送本地更改以覆盖 GitHub.com 上的存储库以及您推送的所有分支。 需要强制推送才能从提交历史记录中删除敏感数据。 请阅读本答案底部的第一个注释,了解更多详细信息。

    git push origin --force --all 
      

选项 2

使用 BFG Repo-Cleaner。 这比 git filter-branch 更快、更简单。

例如,要删除包含敏感数据的文件并保持最新提交不变,请运行

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

要替换 passwords.txt 中列出的所有文本(无论在存储库历史记录中是否存在),请运行

bfg --replace-text passwords.txt

在敏感数据被删除后删除后,必须强制将更改推送到 GitHub。

git push --force

其他

使用上述选项之一后:

  1. 联系GitHub 支持

  2. (如果与团队合作)告诉他们rebase,而不是合并他们根据旧的(受污染的)存储库历史创建的任何分支。 一次合并提交可能会重新引入一些或全部被污染的历史记录,而这些历史记录是人们刚刚费尽心思清除的。


  3. 经过一段时间后,您确信没有任何意外副作用,可以使用以下命令强制取消引用本地存储库中的所有对象并进行垃圾收集(使用 Git 1.8.5 或更高版本):

    git for-each-ref --format="delete %(refname)" refs/original | git for-each-ref --format="delete %(refname)" refs/original |   git update-ref --stdin 
    
      git reflog expire --expire=now --all 
    
      git gc --prune=现在 
      

替代方案

如果文件是使用最近的提交添加的,并且尚未推送到 GitHub.com,则可以删除该文件并修改提交:

  1. 打开 GitBash 并访问存储库。

    cd YOUR-REPOSITORY.l 
      
  2. 要删除文件,请输入git rm --cached

    git rm --cached GIANT_FILE 
      # 将我们的巨型文件暂存以进行删除,但将其保留在磁盘上 
      
  3. 使用 --amend -CHEAD 提交此更改:

    git commit --amend -CHEAD 
      # 使用您的更改修改之前的提交 
      # 根据您的需要,简单地进行新的提交是行不通的 
      # 也从未推送的历史记录中删除该文件 
      
  4. 将提交推送到 GitHub.com:

    <前><代码>git推送
    # 推送我们重写的、更小的提交


为了未来

为了防止敏感数据被泄露,其他良好做法包括:

  • 使用可视化程序提交更改。 有多种替代方案(例如 GitHub DesktopGitKraken, gitk, .. .)并且可以更容易地跟踪更改。

  • 避免使用包罗万象的命令git add .git commit -a。 相反,请使用 git add filename 和 git rm filename 单独暂存文件。

  • 使用 git add --interactive 单独检查和暂存每个​​文件中的更改。

  • 使用 git diff --cached 来查看已暂存提交的更改。 只要不使用 -a 标志,这就是 git commit 将产生的确切差异。

  • 在安全硬件(HSM 盒、硬件密钥 - 如 Yubikey / Solokey)中生成密钥,永远不会离开它。

  • x508 上对团队进行培训。


注释:

Considering that OP is using GitHub, if one commits sensitive data into a Git repo, one can remove it entirely from the history by using one of the previous options (read more about them below):

  1. The git filter-repo tool (view source on GitHub).

  2. The BFG Repo-Cleaner tool (it is open source - view source on GitHub).

After one of the previous options, there are additional steps to follow. Check the section Additional below.

If the goal is to remove a file that was added in the most recent unpushed commit, read the section Alternative below.

For future considerations, to prevent similar situations, check the For the Future section below.


Option 1

Using git filter-repo. Before moving forward, note that

If you run git filter-repo after stashing changes, you won't be able to retrieve your changes with other stash commands. Before running git filter-repo, we recommend unstashing any changes you've made. To unstash the last set of changes you've stashed, run git stash show -p | git apply -R. For more information, see Git Tools - Stashing and Cleaning.

Let us now remove one file from the history of one's repo and add it to .gitignore (to prevent re-committing it again).

Before moving forward, make sure that one has git filter-repo installed (read here how to install it), and that one has a local copy of one's repo (if that is not the case, see here how to clone a repository).

  1. Open GitBash and access the repository.

    cd YOUR-REPOSITORY
    
  2. (Optional) Backup the .git/config file.

  3. Run

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

    replace PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA with the path to the file you want to remove, not just its filename to:

    • Force Git to process, but not check out the entire history of every branch and tag.

    • Remove the specified file (as well as empty commits generated as a result)

    • Remove some configs (such as remote URL stored in the .git/config file)

    • Overwrite one's existing tags.

  4. Add the file with sensitive data to .gitignore

    echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
    
    git add .gitignore
    
    git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
    
  5. Check if everything was removed from one's repository history, and that all branches are checked out. Only then move to the next step.

  6. Force-push the local changes to overwrite your repository on GitHub.com, as well as all the branches you've pushed up. A force push is required to remove sensitive data from your commit history. Read the first note at the bottom of this answer for more details one this.

    git push origin --force --all
    

Option 2

Using BFG Repo-Cleaner. This is faster and simpler than git filter-branch.

For example, to remove one's file with sensitive data and leave your latest commit untouched, run

bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

To replace all text listed in passwords.txt wherever it can be found in your repository's history, run

bfg --replace-text passwords.txt

After the sensitive data is removed, one must force push one's changes to GitHub.

git push --force

Additional

After using one of the options above:

  1. Contact GitHub Support.

  2. (If working with a team) Tell them to rebase, not merge, any branches they created off of one's old (tainted) repository history. One merge commit could reintroduce some or all of the tainted history that one just went to the trouble of purging.

  3. After some time has passed and you're confident that one had no unintended side effects, one can force all objects in one's local repository to be dereferenced and garbage collected with the following commands (using Git 1.8.5 or newer):

    git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
    
    git reflog expire --expire=now --all
    
    git gc --prune=now
    

Alternative

If the file was added with the most recent commit, and one has not pushed to GitHub.com, one can delete the file and amend the commit:

  1. Open GitBash and access the repository.

    cd YOUR-REPOSITORY.l
    
  2. To remove the file, enter git rm --cached:

    git rm --cached GIANT_FILE
    # Stage our giant file for removal, but leave it on disk
    
  3. Commit this change using --amend -CHEAD:

    git commit --amend -CHEAD
    # Amend the previous commit with your change
    # Simply making a new commit won't work, as you need
    # to remove the file from the unpushed history as well
    
  4. Push one's commits to GitHub.com:

    git push
    # Push our rewritten, smaller commit
    

For the Future

In order to prevent sensitive data to be exposed, other good practices include:

  • Use a visual program to commit the changes. There are various alternatives (such as GitHub Desktop, GitKraken, gitk, ...) and it could be easier to track the changes.

  • Avoid the catch-all commands git add . and git commit -a. Instead, use git add filename and git rm filename to individually stage files.

  • Use git add --interactive to individually review and stage changes within each file.

  • Use git diff --cached to review the changes that one has staged for commit. This is the exact diff that git commit will produce as long as one doesn't use the -a flag.

  • Generate Secret Keys in secure hardware (HSM boxes, hardware keys - like Yubikey / Solokey), that never leaves it.

  • Train the team on x508.


Notes:

温折酒 2024-07-26 07:27:52

所以,它看起来像这样:

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

从 git 中删除跟踪文件的缓存并将该文件添加到 .gitignore 列表

So, It looks something like this:

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

Remove cache for tracked file from git and add that file to .gitignore list

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文