从git / GitHub的历史记录中删除文件夹及其内容

时间:2012-04-09 00:58:06

标签: git github rebase git-rebase

我正在使用我的GitHub帐户上的存储库,这是我偶然发现的一个问题。

  • Node.js项目,其中包含安装了几个npm软件包的文件夹
  • 这些包位于node_modules文件夹
  • 将该文件夹添加到git repository并将代码推送到github(当时没有想到npm部分)
  • 意识到您并不需​​要该文件夹成为代码的一部分
  • 删除该文件夹,将其推送

在那个例子中,总git repo的大小约为 6MB ,其中实际代码(除该文件夹之外的所有代码)仅在 300 KB 附近。

现在我正在寻找的是从git的历史中删除该包文件夹的细节的方法,所以如果有人克隆它,他们不必下载6mb的历史记录,其中唯一的实际文件他们将在最后一次提交时获得300KB。

我查找了可能的解决方案并尝试了这两种方法

Gist似乎在运行脚本之后起作用,它表明它摆脱了该文件夹,之后它显示了50个不同的提交被修改。但它没有让我推动那些代码。当我试图推送它时,它说Branch up to date但显示50个提交被修改为git status。其他两种方法也没有帮助。

现在即使它显示它摆脱了该文件夹的历史记录,当我在我的localhost上检查该repo的大小时,它仍然是大约6MB。 (我还删除了refs/original文件夹,但没有看到回购邮件大小的变化。)

我想要澄清的是,如果有一种方法可以摆脱提交历史(这是我认为发生的唯一事情),还有那些文件git保持假设想要回滚。

让我们说这是一个解决方案并且应用于我的本地主机但不能复制到该GitHub存储库,是否可以克隆该存储库,回滚到第一个提交执行技巧并推送它(或者是否意味着那个git还会有所有这些提交的历史吗? - 又名.6MB)。

我的最终目标是基本上找到从git中删除文件夹内容的最佳方法,这样用户就不必下载6MB的东西,而且还可能有其他提交从未触及过modules文件夹(这几乎就是所有这些)在git的历史中。

我该怎么做?

8 个答案:

答案 0 :(得分:448)

如果你在这里复制粘贴代码:

这是从历史记录

中删除node_modules的示例
git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force

答案 1 :(得分:184)

我发现其他答案中使用的2 is a number -2 is a number -2.6 is a number -2.c6 is not a number 2. is not a number 2.0 is a number 选项可能非常慢,尤其是在有大量提交的大型存储库中。

以下是我使用--tree-filter选项从git历史记录中完全删除目录的方法,该选项运行得更快:

--index-filter

您可以在# Make a fresh clone of YOUR_REPO git clone YOUR_REPO cd YOUR_REPO # Create tracking branches of all branches for remote in `git branch -r | grep -v /HEAD`; do git checkout --track $remote ; done # Remove DIRECTORY_NAME from all commits, then remove the refs to the old commits # (repeat these two commands for as many directories that you want to remove) git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch DIRECTORY_NAME/' --prune-empty --tag-name-filter cat -- --all git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d # Ensure all old refs are fully removed rm -Rf .git/logs .git/refs/original # Perform a garbage collection to remove commits with no refs git gc --prune=all --aggressive # Force push all branches to overwrite their history # (use with caution!) git push origin --all --force git push origin --tags --force 之前和之后检查存储库的大小:

gc

答案 2 :(得分:35)

除了流行的答案above之外,我还想为 Windows 系统添加一些注释。命令

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
  • 完美无需任何修改!因此,您不得使用Remove-Itemdel或其他任何内容,而不是rm -rf

  • 如果您需要指定文件或目录的路径,请使用斜杠,例如./path/to/node_modules

答案 3 :(得分:35)

最新的答案似乎是直接直接使用filter-branch(至少git本身不再推荐),并将该工作推迟到外部工具。特别是,目前建议使用git-filter-repo。该工具provides arguments的作者讲述了为什么直接使用filter-branch会导致问题。

上面用于从历史记录中删除dir的大多数多行脚本可以重写为:

git filter-repo --path dir --invert-paths

显然,该工具不仅功能强大。您可以按作者,电子邮件,refname和更多(full manpage here)应用过滤器。此外,它快速。安装很容易-它是distributed in a variety of formats

答案 4 :(得分:17)

我找到的最好和最准确的方法是下载bfg.jar文件: https://rtyley.github.io/bfg-repo-cleaner/

然后运行命令:

$(':button').on("click", function(){
// do other stuff
});

如果要删除文件,请改用delete-files选项:

git clone --bare https://project/repository project-repository
cd project-repository
java -jar bfg.jar --delete-folders DIRECTORY_NAME  # i.e. 'node_modules' in other examples
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror https://project/new-repository

答案 5 :(得分:5)

完成复制和粘贴配方,只需在测试后添加注释中的命令(用于复制粘贴解决方案):

git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
echo node_modules/ >> .gitignore
git add .gitignore
git commit -m 'Removing node_modules from git history'
git gc
git push origin master --force

在此之后,您可以删除行" node_modules /"来自.gitignore

答案 6 :(得分:3)

对于Windows用户,请注意使用"代替' 还添加了-f以强制命令是否已存在另一个备份。

git filter-branch -f --tree-filter "rm -rf FOLDERNAME" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo FOLDERNAME/ >> .gitignore
git add .gitignore
git commit -m "Removing FOLDERNAME from git history"
git gc
git push origin master --force

答案 7 :(得分:2)

我在Windows上使用git从旧的C#项目中删除了bin和obj文件夹。

小心
git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD

通过删除git install文件夹中的usr / bin文件夹来破坏git安装的完整性。