我想把一个Git项目放在GitHub上,但它包含某些具有敏感数据的文件(用户名和密码,如/config/deploy。卡皮斯特拉诺的Rb)。

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

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

是否有一种方法可以删除Git历史记录中特定文件的所有痕迹?


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.


有了这些,下面是如何解决它的方法。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年更新:

这是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

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

为了解决这个问题,他们必须删除现有的存储库并重新克隆它,或者遵循git-rebase手册中“从UPSTREAM REBASE中恢复”的说明。

提示:执行git rebase—交互式


将来,如果您不小心提交了一些涉及敏感信息的更改,但在推送到远程存储库之前注意到了这些更改,有一些更容易的修复方法。如果上次提交是添加敏感信息的提交,您可以简单地删除敏感信息,然后运行:

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

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


我推荐大卫·安德希尔的这个剧本,对我来说很有魅力。

它在natacado的filter分支中添加了这些命令来清理它留下的混乱:

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

更改密码是一个好主意,但对于从回购历史记录中删除密码的过程,我推荐BFG回购- 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倍,并且选项是围绕以下两个常见用例进行简化和定制的:

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

完全披露:我是好心眼巨人回收清理器的作者。


它看起来是这样的:

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

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


明确一点:公认的答案是正确的。先试试。然而,对于某些用例来说,这可能是不必要的复杂,特别是当你遇到诸如'fatal: bad revision -prune-empty'之类的讨厌错误时,或者真的不关心你的回购历史。

另一种选择是:

CD到项目的基本分支 删除敏感代码/文件 rm -rf .git/ #删除所有git信息 你的代码 去github并删除你的存储库 按照本指南将您的代码推送到一个新的存储库,就像您通常会做的那样 https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/

当然,这将删除所有提交历史分支,以及来自你的github回购和本地git回购的问题。如果这是不可接受的,你将不得不使用另一种方法。

我们可以称之为“核选项”。


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

在git 2.5本身的git filter-branch的手册中提到了这一点。

从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密钥! 不(裸照): 您是否关心存储库中的所有问题都被nuked? No:删除存储库 是的: 联络支持 如果泄漏对你来说非常重要,以至于你愿意让一些存储库停机以降低泄漏的可能性,那么在你等待GitHub支持回复你的时候,将其设置为私有

一秒钟后的推力是不够的,因为:

GitHub keeps dangling commits for a long time. GitHub staff does have the power to delete such dangling commits if you contact them however. I experienced this first hand when I uploaded all GitHub commit emails to a repo they asked me to take it down, so I did, and they did a gc. Pull requests that contain the data have to be deleted however: that repo data remained accessible up to one year after initial takedown due to this. Dangling commits can be seen either through: the commit web UI: https://github.com/cirosantilli/test-dangling/commit/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Wayback machine) the API: https://api.github.com/repos/cirosantilli/test-dangling/commits/53df36c09f092bbb59f2faa34eba15cd89ef8e83 (Wayback machine) One convenient way to get the source at that commit then is to use the download zip method, which can accept any reference, e.g.: https://github.com/cirosantilli/myrepo/archive/SHA.zip It is possible to fetch the missing SHAs either by: listing API events with type": "PushEvent". E.g. mine: https://api.github.com/users/cirosantilli/events/public (Wayback machine) more conveniently sometimes, by looking at the SHAs of pull requests that attempted to remove the content There are scrappers like http://ghtorrent.org/ and https://www.githubarchive.org/ that regularly pool GitHub data and store it elsewhere. I could not find if they scrape the actual commit diff, and that is unlikely because there would be too much data, but it is technically possible, and the NSA and friends likely have filters to archive only stuff linked to people or commits of interest.

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

为了测试这一点,我创建了一个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删除悬空提交?


这是我在windows下的解决方案

git filter-branch——tree-filter "rm -f 'filedir/filename' Git push—force

确保路径正确 否则行不通

我希望这对你们有帮助


你可以使用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/

它将从历史记录、reflog、标签等所有提交中消失

我时不时地会遇到同样的问题,每次我都要回到这个帖子和其他帖子,这就是为什么我把这个过程自动化了。

感谢Stack Overflow的贡献者,是他们让我把这些放在一起


到目前为止,我已经做过几次了。注意,这一次只对一个文件有效。

获取修改文件的所有提交的列表。底部的将是第一个提交: git log——pretty=oneline——branches——pathToFile 要从历史记录中删除文件,请使用第一个提交sha1和之前命令中的文件路径,并将它们填充到这个命令中: Git filter-branch——index-filter ' Git rm——cached——ignore-unmatch <path-to-file>'——<sha1-where-the-file-was-first-added>..


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

在我的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

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

git过滤器-回购工具(在GitHub上查看源代码)。 BFG Repo-Cleaner工具(它是开源的-在GitHub上查看源代码)。

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

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

对于将来的考虑,为了防止类似的情况,请检查下面的For the future部分。


选项1

使用git filter-repo。在继续之前,请注意这一点

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

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

在继续之前,请确保其中一个已经安装了git filter-repo(请阅读此处如何安装它),并且其中一个已经安装了一个repo的本地副本(如果情况不是这样,请参阅此处如何克隆存储库)。

Open GitBash and access the repository. cd YOUR-REPOSITORY (Optional) Backup the .git/config file. 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. 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" Check if everything was removed from one's repository history, and that all branches are checked out. Only then move to the next step. 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


选项2

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

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

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

要替换密码.txt中列出的所有文本,只要它能在存储库的历史记录中找到,运行

bfg --replace-text passwords.txt

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

git push --force

额外的

使用上述选项之一后:

Contact GitHub Support. (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. 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


替代

如果该文件是在最近的提交中添加的,并且没有推送到GitHub.com,则可以删除该文件并修改提交:

打开git并访问存储库。 cd YOUR-REPOSITORY.l 要删除文件,输入git rm——cached: git rm——缓存GIANT_FILE #舞台我们的大文件删除,但把它留在磁盘上 使用——modify -CHEAD提交此更改: git commit——modify -CHEAD 使用您的更改修改之前的提交 #简单地做出一个新的提交是行不通的,正如你所需要的 #将该文件从未推送的历史记录中删除 推送一个人的提交到GitHub.com: git推 #推送我们重写的,更小的提交


为了未来

为防止敏感资料外泄,其他良好做法包括:

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.


注:

当一个强制执行时,它会重写存储库历史,从而从提交历史中删除敏感数据。这可能会覆盖其他人基于其工作的提交。 为了回答这个问题,有人使用了一些GitHub帖子的内容: 从存储库中删除敏感数据 关于GitHub上的大文件