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

Ste*_*fan 330 git git-filter-branch git-commit git-rewrite-history

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

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

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

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

nat*_*ado 410

出于所有实际目的,您首先要担心的是改变您的密码!从您的问题中不清楚您的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
Run Code Online (Sandbox Code Playgroud)

请记住,一旦您将此代码推送到像GitHub这样的远程存储库并且其他人已经克隆了该远程存储库,您现在处于重写历史记录的情况.当其他人尝试在此之后下拉您的最新更改时,他们会收到一条消息,指示无法应用更改,因为它不是快进.

要解决这个问题,他们必须删除现有的存储库并重新克隆它,或者按照git-rebase联机帮助页中的"从上游重新恢复"中的说明进行操作.


在将来,如果您不小心使用敏感信息提交了一些更改,但推送到远程存储库之前注意到了这一点,则可以使用一些更简单的修复程序.如果您上次提交是添加敏感信息的那个,您只需删除敏感信息,然后运行:

  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
Run Code Online (Sandbox Code Playgroud)

这将使用您所做的任何新更改修改先前的提交,包括使用a完成的整个文件删除git rebase --interactive.如果更改在历史记录中进一步返回但仍未推送到远程存储库,则可以执行交互式rebase:

git commit -a --amend
Run Code Online (Sandbox Code Playgroud)

这将打开一个编辑器,其中包含您自上次使用远程存储库的共同祖先以来所做的提交.在表示具有敏感信息的提交的任何行上将"选择"更改为"编辑",然后保存并退出.Git将会介绍这些变化,并将您留在可以:

git rebase -i origin/master
Run Code Online (Sandbox Code Playgroud)

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

  • 只需添加一位 - 在Windows上,你应该使用双引号(")而不是单引号. (17认同)
  • 完美的家伙,这是一个很好的答案.你救了我的一天. (4认同)
  • 有这个工作.我迷失了翻译.我在这里使用了链接而不是命令.此外,Windows命令最终需要双引号,如ripper234提到,完整路径为MigDus建议,并且不包括链接粘贴为新换行指示符的"\"字符.最终命令看起来像:git filter-branch --force --index-filter"git rm --cached --ignore-unmatch src\[Project]\[File].[ext]" - prune-empty - tag-name-filter cat - --all (4认同)
  • 您的`filter-branch`代码与您链接到的github页面之间似乎存在一些实质性差异.例如他们的第3行`--proune-empty --tag-name-filter cat - --all`.解决方案有变化还是我遗漏了什么? (3认同)
  • 这个解决方案看起来相当不错,但是如果我在初始提交`&lt;introduction-revision-sha1&gt; .. HEAD`中引入了要删除的文件,则无法使用。它仅从第二次提交开始删除文件。(如何将初始提交包含在提交范围内?)保存方法在此处指出:https://help.github.com/articles/removing-sensitive-data-from-a-repository/`git filter -branch --force --index-filter \'git rm –cached –ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA'\ --prune-empty --tag-name-filter cat --全部 (2认同)
  • 此命令不会删除所有分支中的文件,也不会删除标签。[官方github帮助](https://help.github.com/articles/removing-sensitive-data-from-a-repository)完美运行 (2认同)

Rob*_*ley 86

更改密码是一个好主意,但是对于从repo的历史中删除密码的过程,我推荐使用BFG Repo-Cleaner,这是一种更快,更简单的替代方法,git-filter-branch专门用于从Git repos中删除私有数据.

创建一个private.txt文件,列出要删除的密码等(每行一个条目),然后运行以下命令:

$ java -jar bfg.jar  --replace-text private.txt  my-repo.git
Run Code Online (Sandbox Code Playgroud)

将扫描您的仓库历史记录中阈值大小(默认为1MB)的所有文件,并且任何匹配的字符串(不在您的最新提交中)将替换为字符串"***REMOVED***".然后,您可以使用git gc清除死数据:

$ git gc --prune=now --aggressive
Run Code Online (Sandbox Code Playgroud)

BFG通常比运行速度快10-50倍,git-filter-branch并且可以简化这些选项并围绕这两种常见用例进行定制:

  • 删除疯狂的大文件
  • 删除密码,凭据和其他私人数据

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

  • 这是一个很大的胜利.经过几次尝试,我能够使用它来彻底剥离包含来自私人仓库的敏感信息的提交,并用修改后的历史记录强制更新远程仓库.一方面需要注意的是,您必须确保您的仓​​库(HEAD)的提示本身是干净的,没有敏感数据,因为此提交被视为"受保护",并且不会被此工具修改.如果不是,只需手动清理/替换和`git commit`.否则,在开发人员的工具箱中为新工具+1 (6认同)
  • @Henridv根据我最近的评论,假设您的应用程序当前位于分支的顶端或头部(即最新提交),它不应该像您预期的那样破坏您的应用程序。该工具将明确报告您的最后一次提交“这些是您受保护的提交,因此它们的内容不会被更改”,同时遍历和修改您的其余提交历史记录。但是,如果您需要回滚,那么您只需要在刚刚回滚的提交中搜索“***REMOVED***”即可。 (2认同)
  • BFG +1(如果您安装了 Java 或者不介意安装它)。一个问题是 BFG 拒绝删除包含在 HEAD 中的文件。因此,最好先进行提交,删除所需的文件,然后再运行 BFG。之后您可以恢复上次提交,现在它不会改变任何事情。 (2认同)
  • 缺少“git Push --force” (2认同)

Jas*_*aat 19

我推荐大卫安德希尔的这个剧本,对我来说就像一个魅力.

除了natacado的filter-branch之外,它还添加了这些命令来清理它留下的混乱:

rm -rf .git/refs/original/
git reflog expire --all
git gc --aggressive --prune
Run Code Online (Sandbox Code Playgroud)

完整的脚本(所有归功于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
Run Code Online (Sandbox Code Playgroud)

如果更改为以下内容,最后两个命令可能会更好:

git reflog expire --expire=now --all && \
git gc --aggressive --prune=now
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您对 expire 和 prune 的使用是不正确的,如果您未指定日期,则默认为所有超过 2 周的 prune 提交。你想要的是所有提交,所以这样做:`git gc --aggressive --prune=now` (2认同)

Cir*_*四事件 17

如果您已经推送到GitHub,即使您在一秒钟之后强制将其推出,数据也会受到影响,原因是:

为了测试这一点,我创建了一个回购: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
Run Code Online (Sandbox Code Playgroud)

但是,如果删除存储库,则提交甚至会立即从API中消失并提供4​​04,例如https://api.github.com/repos/cirosantilli/test-dangling-delete/commits/8c08448b5fbf0f891696819f3b2b2d653f7a3824即使您重新创建另一个具有相同名称的存储库.

所以我建议的行动方针是:

  • 更改您的凭据

  • 如果这还不够(例如裸照片):

    • 删除存储库
    • 联系支持


los*_*her 9

要明确:接受的答案是正确的.先试试吧.但是,对于某些用例,它可能会不必要地复杂化,特别是如果您遇到令人讨厌的错误,例如"致命错误:错误的修订 - 出现空白",或者真的不关心您的回购历史.

另一种选择是:

  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仓库的问题.如果这是不可接受的,您将不得不使用替代方法.

称之为核选项.


ver*_*o71 7

这是我在windows中的解决方案

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

git push --force

确保路径正确,否则它将无法正常工作

我希望它有所帮助


Shi*_*wal 7

使用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
Run Code Online (Sandbox Code Playgroud)


nac*_*ker 6

您可以使用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的贡献者,这使我可以将它们放在一起

  • 此答案中的链接似乎不再有效。 (3认同)

Erc*_*can 5

在我的 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
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

103230 次

最近记录:

5 年,12 月 前