我想将一个Git项目放到GitHub上,但它包含某些包含敏感数据的文件(用户名和密码,例如capistrano的/config/deploy.rb)。
我知道可以将这些文件名添加到.gitignore中,但这并不会从Git中删除它们的历史记录。
我也不想通过删除/.git目录来重新开始。
有没有一种方法可以删除您Git历史记录中特定文件的所有痕迹?
我想将一个Git项目放到GitHub上,但它包含某些包含敏感数据的文件(用户名和密码,例如capistrano的/config/deploy.rb)。
我知道可以将这些文件名添加到.gitignore中,但这并不会从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 --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
对于每个包含敏感信息的更改,请最终返回到您的分支,然后可以安全地推送新更改。
filter-branch
代码和你链接到的Github页面上的代码似乎有一些实质性的差异,例如,他们第三行的代码是--prune-empty --tag-name-filter cat -- --all
。这个解决方案是否已更改或者我漏掉了什么? - geotheory<introduction-revision-sha1>..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 -- --all
- white_geckogit 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目录的相对路径,没有前导斜杠。 - toddmogit-filter-branch
相比。创建一个名为private.txt
的文件,并列出您想要删除的密码等内容(每行一个条目),然后运行以下命令:
$ java -jar bfg.jar --replace-text private.txt my-repo.git
您的存储库历史记录中所有大小低于阈值大小(默认为1MB)的文件都将被扫描,任何匹配的字符串(不在您的最新提交中的字符串)都将被替换为字符串"***REMOVED***"。然后,您可以使用git gc
清除死数据:
$ git gc --prune=now --aggressive
BFG Repo-Cleaner通常比运行git-filter-branch
快10-50倍,并且选项已简化并针对这两种常见用例进行了定制:
完整声明:我是BFG Repo-Cleaner的作者。
git commit
。否则,这是开发人员工具箱中的新工具 +1 :) - Matt Borjagit push --force
丢失了。 - Gino Panegit 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')
GitHub会长时间保留悬挂的提交。
然而,如果您联系他们,GitHub工作人员确实有权删除这些悬挂的提交。
我亲身经历了这一点,当我将所有GitHub提交电子邮件上传到一个repo时,他们要求我将其删除,所以我这样做了,他们进行了gc
。然而,包含这些数据的拉取请求必须被删除:由于此原因,该repo数据在初始下架后仍然可以访问一年。
可以通过以下方式查看悬挂的提交:
然后,获取该提交的源代码的一种便捷方法是使用下载zip方法,该方法可以接受任何引用,例如:https://github.com/cirosantilli/myrepo/archive/SHA.zip
可以通过以下两种方式获取缺失的SHAs:
type": "PushEvent"
列出API事件。例如我的:https://api.github.com/users/cirosantilli/events/public(Wayback machine)有像http://ghtorrent.org/和https://www.githubarchive.org/这样的爬虫定期收集GitHub数据并将其存储在其他地方。
我找不到它们是否会抓取实际提交差异,这很不可能,因为数据太多了,但从技术上讲是可能的,NSA和朋友们可能有过滤器仅存档与人或提交相关的东西。
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 --replace-text <(echo 'my_password==>xxxxxxxx')
,虽然它确实起作用了,但是它也使得所有的提交看起来像是今天发生的。有没有一种方法可以在更改历史记录中的文件时保留提交日期? - devordemgit-filter-repo
。 - devordem你可以使用git forget-blob
命令。
使用非常简单:git forget-blob file-to-forget
。你可以在这里获取更多信息。
它将从历史记录、reflog、标签等所有提交中消失。
我也经常遇到同样的问题,每次都要回到这篇文章和其他文章,所以我自动化了这个过程。
感谢 Stack Overflow 的贡献者们让我能够组织这篇文章。
我推荐使用 David Underhill 的这个脚本,对我来说非常好用。
它与 natacado 的 filter-branch 命令一起使用,可以清理 filter-branch 留下的混乱:
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
git gc --aggressive --prune=now
。 - Adam Parkin以下是关于Windows下的解决方案:
git filter-branch --tree-filter "rm -f 'filedir/filename'" HEAD
git push --force
请确保路径正确,否则此方法将无法生效。
希望对您有所帮助。
使用 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
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 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>..