Node.js项目,其中安装了一些npm软件包的文件夹
位于
node_modules
文件夹中将该文件夹添加到git存储库中,并将代码推送到github(当时并没有考虑npm部分)
意识到您实际上并不需要该文件夹代码的一部分
删除该文件夹,将其推送
在那种情况下,总git repo的大小约为6MB,而实际代码(除该文件夹以外的所有代码)只有300左右KB
现在我最后要寻找的是一种从git的历史记录中删除该软件包文件夹的详细信息的方法,因此,如果有人对其进行了克隆,则无需下载6mb的历史记录,截至上一次提交时,它们将获得的唯一实际文件为300KB。
我为此找到了可能的解决方案,并尝试了这两种方法
删除git存储库中的文件(历史记录)
http://help.github.com/remove-sensitive-data/
https://gist.github.com/1588371
Gist似乎在运行脚本后在哪里工作,它表明它删除了该文件夹,并表明修改了50个不同的提交。但这并没有让我推送该代码。当我尝试推送它时,它说
Branch up to date
,但显示对git status
修改了50次提交。其他两种方法也无济于事。现在,即使表明它摆脱了该文件夹的历史记录,当我在本地主机上检查该存储库的大小时,它仍然约为6MB。 (我还删除了
refs/original
文件夹,但是没有看到存储库大小的变化。)我想澄清的是,是否有一种方法可以消除不仅提交的问题历史(这是我认为唯一发生的事情),但是git仍在假设那些人想要回滚的那些文件。
可以说为此提供了一个解决方案,该解决方案已在我的localhost上应用,但无法复制到该GitHub存储库,是否可以克隆该存储库,回滚到第一个提交执行该技巧并将其推送(或者这意味着git将还有所有这些提交的历史吗?-又名6MB)。
我的最终目标是从根本上找到摆脱git中文件夹内容的最佳方法,从而使用户不必下载6MB的内容,而仍然可以进行其他提交从来没有碰过git历史记录中的modules文件夹。(
我该怎么做?
#1 楼
如果您要在此处复制粘贴代码:这是一个从历史记录中删除
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
git实际做什么: br />
第一行通过运行
--tree-filter
命令遍历与HEAD(当前分支)相同的树(rm -rf node_modules
)上的所有引用。该命令删除node_modules文件夹(-r
,不带-r
,rm
不会删除文件夹),而没有提示用户(-f
)。添加的--prune-empty
递归删除无用(不做任何更改)的提交。 第二行删除对该旧分支的引用。
其余命令相对简单。
评论
附带说明:我使用git count-objects -v检查文件是否实际上已删除,但是存储库的大小保持不变,直到再次克隆存储库为止。 Git保留了我认为的所有原始文件的副本。
– Davide Icardi
15年7月21日在9:39
如果使用的是非古旧的git,则应该读为--force-with-lease,而不是--force。
–Griwes
16-4-20在22:47
这些命令在Windows上均不起作用。或者至少不是Windows 10,请发布可进行“剪切和粘贴”的操作系统
–大卫
16年11月2日,19:48
对于Windows 10用户,这在Windows的Bash下效果很好(我使用过Ubuntu)
– Andrej Kyselica
17年8月13日在1:31
我用Windows Shell和git bash尝试了一下,但是没有用。第一条命令通过,第二条命令失败!
– Mohy Eldeen
17年11月9日在4:44
#2 楼
我发现其他答案中使用的--tree-filter
选项可能非常慢,尤其是在具有大量提交的较大存储库上。这是我使用
--index-filter
选项从git历史记录中完全删除目录的方法,更快: # 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
之前和之后的存储库大小:git count-objects -vH
评论
您能解释一下为什么这么快吗?
– knocte
2015年11月18日,下午3:46
@knocte:来自docs(git-scm.com/docs/git-filter-branch)。 “ --index-filter:...与树过滤器类似,但是不检出树,这使它快得多”
–李·尼瑟顿
15年11月18日在12:54
为什么这不是公认的答案?太彻底了。
–疯狂物理学家
15年12月18日在12:51
如果在Windows中执行此操作,则需要双引号而不是单引号。
–克里斯·莫尼斯(Kris Morness)
17年8月1日在20:45
将--quiet传递给上面的git rm至少使因子4加快了我的重写速度。
– ctusch
18 Mar 8 '18 at 11:04
#3 楼
除了上面流行的答案外,我还要为Windows系统添加一些注意事项。命令git filter-branch --tree-filter 'rm -rf node_modules' --prune-empty HEAD
无需任何修改即可完美运行!因此,切勿使用
Remove-Item
,del
或其他任何形式代替rm -rf
。评论
如果目录包含,则在Windows上将无法使用。 (点)的名称。
– Corneliu Serediuc
17年5月6日在11:31
我找到了解决方案。对rm命令使用双引号,例如:“ rm -rf node.modules”。
– Corneliu Serediuc
17年5月6日在11:39
#4 楼
看来,最新的解决方法是不要直接使用filter-branch
(至少git本身不再建议这样做),而将工作推迟到外部工具上进行。特别是,目前推荐使用git-filter-repo。该工具的作者提供了有关为什么直接使用filter-branch
会导致问题的争论。上面从历史记录中删除
dir
的大多数多行脚本可以重写为: git filter-repo --path dir --invert-paths
该工具显然比这更强大。您可以按作者,电子邮件,参考名称和更多内容(此处为完整手册页)应用过滤器。此外,它速度很快。安装很容易-它以多种格式分发。
评论
不错的工具!在Ubuntu 20.04上运行良好,您只能在pip3上安装git-filter-repo,因为它仅是stdlib且不会安装任何依赖项。在Ubuntu 18上它与发行版的git版本不兼容错误:需要一个git版本,其diff-tree命令具有--combined-all-paths选项,但是在docker run -ti ubuntu:20.04上运行它很容易
– Kubanczyk
20 May 27'9:29
它只是工作,简单而优雅!感谢您的推荐!
–汤姆汤姆(Tom Tang)
20年7月1日在22:01
你是对的!但是,如果您可以将答案与关于filter-repo的信息分开。.我的意思是,也许写所有关于filter-repo的信息来替换filter-branch,然后编写-------运算符,然后给出我们提供有关命令本身的更多信息-例如--invert-paths是什么。谢谢!
–baruchiro
20 Jul 7'4:23
重要提示:如果您的目录不在顶层,则必须提供其完整路径。目录/子目录
–stef
20-09-22在9:46
#5 楼
我发现最好,最准确的方法是下载bfg.jar文件:https://rtyley.github.io/bfg-repo-cleaner/
然后运行命令:
git clone --bare https://project/repository project-repository
cd project-repository
java -jar bfg.jar --delete-folders DIRECTORY_NAME
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push --mirror https://project/new-repository
如果要删除文件,请使用Delete-files选项:
java -jar bfg.jar --delete-files *.pyc
评论
非常简单:)如果要确保仅删除特定文件夹,这将有所帮助:stackoverflow.com/questions/21142986/…
– Emjay
17年8月25日在9:51
#6 楼
测试完命令后,只需在注释中添加命令(适用于复制粘贴解决方案)即可完成复制粘贴操作: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
此后,您可以删除“来自.gitignore的node_modules /“
评论
为什么要从.gitignore中删除node_modules?这样,他们可能会再次被意外犯下??
–亚当斯基
19 Mar 25 '19在15:20
它不会从gitignore中删除,而是添加到了gitignore中。提交消息显示为“ git history”,而不是“ gitignore” :)
– Danny Tuppeny
19年4月8日在8:07
但是评论说您可以从.gitignore中删除node_modules。
– Zavr
19-10-18在14:57
#7 楼
对于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
#8 楼
我在Windows上使用git从旧的C#项目中删除了bin和obj文件夹。小心git filter-branch --tree-filter "rm -rf bin" --prune-empty HEAD
它会删除git install文件夹中的usr / bin文件夹,从而破坏git安装的完整性。
评论
如果以下任何答案解决了您的问题,则也许您应该考虑接受一个作为您问题的答案。 meta.stackexchange.com/questions/5234/…最好的答案是:stackoverflow.com/a/32886427/5973334