Performance Git对于100000个对象来说速度非常慢。有办法吗?
我有一个“新鲜”的git svn repo(11.13 GB),其中包含超过100000个对象 我已经准备好了Performance Git对于100000个对象来说速度非常慢。有办法吗?,performance,git,git-svn,Performance,Git,Git Svn,我有一个“新鲜”的git svn repo(11.13 GB),其中包含超过100000个对象 我已经准备好了 git fsck git gc 首次结账后的回购协议 然后我试着做了一个测试 git status 执行git状态所需的时间介于2m25.578s和2m53.901s之间 我通过发出命令来测试git状态 time git status 5次,所有时间都在上面列出的两次之间 我在MacOSX上做这件事,在本地,而不是通过虚拟机 不可能花这么长时间 有什么想法吗?帮忙 谢谢 编辑 我
git fsck
git gc
首次结账后的回购协议
然后我试着做了一个测试
git status
执行git状态所需的时间介于2m25.578s和2m53.901s之间
我通过发出命令来测试git状态
time git status
5次,所有时间都在上面列出的两次之间
我在MacOSX上做这件事,在本地,而不是通过虚拟机
不可能花这么长时间
有什么想法吗?帮忙
谢谢
编辑
我有一个同事坐在我旁边,拿着一个类似的盒子。更少的RAM,使用jfs文件系统运行Debian。他的git状态在同一回购协议上运行.3(也是git svn签出)
另外,我最近更改了这个文件夹的文件权限(改为777),这大大缩短了时间(为什么,我不知道)。我现在可以在3到6秒之间的任何地方完成它。这是可以控制的,但仍然很痛苦。您可以尝试将
--aggressive
切换到git-gc
,看看这是否有帮助:
# this will take a while ...
git gc --aggressive
此外,如果您的历史记录中有不需要的内容(例如旧二进制文件),则可以使用git筛选器分支删除旧提交和/或文件。您也可以尝试可能spotlight正在尝试为文件编制索引。可能为您的代码目录禁用spotlight。检查活动监视器并查看正在运行的进程。我将使用不同的文件系统创建一个分区。与在其他文件系统上执行类似的操作相比,HFT+对我来说总是很慢。git status每次都必须查看存储库中的每个文件。你可以告诉它,不要再看那些你没有用过的树
git update-index --assume-unchanged <trees to skip>
git更新索引--假定未更改
从手册页:
如果指定了这些标志,则
为路径记录的对象名称
没有更新。相反,这些
选项设置和取消设置“假定”
路径的“未更改”位。当
“假定未更改”位为on,git
停止检查工作树文件
为可能的修改,所以你
需要手动取消位的设置,以告知
更改工作树时的git
文件这有时在以下情况下很有用:
在一个项目上处理一个大项目
具有非常慢的lstat(2)的文件系统
系统调用(例如cifs)
此选项也可以用作
要忽略的粗略文件级机制
跟踪文件中未提交的更改
(类似于.gitignore的作用
未跟踪的文件)。Git将失败
(优雅地)以防需要
在索引中修改此文件,例如。
在提交中合并时;因此,在
假设未跟踪的文件为
改变上游,你将需要
手动处理这种情况
git中的许多操作取决于您的
文件系统要有一个高效的
lstat(2)实施,以便
工作树的st_mtime信息
可以便宜地检查文件,看看是否
文件内容已从更改为
索引中记录的版本
文件不幸的是,有些文件系统
具有无效的lstat(2)。如果你的
文件系统就是其中之一,您可以设置
“假定未更改”位对您进行更改
未更改以使git无法
做这个检查。请注意,设置此
路径上的位并不意味着git将
检查文件的内容以查看
如果它发生了变化,它会使git
省略任何检查,并假定它已
没有改变。当您更改
工作树文件,你必须
通过以下方式显式地告诉git
删除“假定不变”位,
在修改之前或之后
他们
为了设置“假定不变”
位,使用--假定未更改选项。到
unset,使用--no假设未更改
该命令查看core.ignorestat
配置变量。这是什么时候
true,使用git更新路径
更新索引路径…并更新路径
使用其他更新的git命令
索引和工作树(例如git
apply--index,git签出索引-u,
和git read tree-u)是
自动标记为“假定”
不变”。注意,“假设
如果是git,则未设置“未更改”位
更新索引--刷新查找
工作树文件与索引匹配
(使用git更新索引--真正刷新
如果您想将它们标记为“假设”
不变”)
现在,很明显,只有当回购协议的某些部分可以方便地忽略时,这个解决方案才会起作用。我在一个类似规模的项目中工作,而且肯定有一些大树,我不需要定期检查。git状态的语义使得它通常是一个O(n)问题(n个文件)。您需要特定于域的优化才能做得更好
请注意,如果您使用缝合模式,也就是说,如果您通过“合并”而不是“重基”来集成来自上游的更改,则此解决方案将变得不太方便,因为对--ASSUE UNTABLE对象的更改从上游合并将成为合并冲突。您可以通过重定基准工作流来避免此问题。这归结为我现在可以看到的几个项目
git-gc——攻击性
777的文件权限
肯定还有其他事情在进行,但这显然是影响最大的事情。值得一提的是,我最近发现我的master和dev分支之间的
git status
命令之间存在很大差异
长话短说,我将问题追溯到项目根目录中的一个280MB文件。这是数据库转储的意外签入,因此可以删除它
以下是之前和之后的内容:
⚡ time git status
# On branch master
nothing to commit (working directory clean)
git status 1.35s user 0.25s system 98% cpu 1.615 total
⚡ rm savedev.sql
⚡ time git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: savedev.sql
#
no changes added to commit (use "git add" and/or "git commit -a")
git status 0.07s user 0.08s system 98% cpu 0.157 total
⚡ 时间git状态
#论分行行长
没有要提交的内容(工作目录清理)
git状态1.35s用户0.25s系统98%cpu总数1.615
⚡ rm savedev.sql
⚡ 时间git状态
#论分行行长
#未为提交而暂存的更改:
#(使用“git add/rm…”更新将提交的内容)
#(使用“git checkout-
git repack -ad
git gc --prune=now
HEAD~1 HEAD
----------------------------------------
7.70(7.15+0.54) 7.44(7.09+0.29) -3.4%
Test w/100,000 files reduced the time by 32.24%
Test w/1,000,000 files reduced the time by -4.77%
$ git count-objects
26733 objects, 68808 kilobytes
Test HEAD^ HEAD
--------------------------------------------------------------------
4205.1: log with %H 0.51(0.47+0.04) 0.51(0.49+0.02) +0.0%
4205.2: log with %h 0.84(0.82+0.02) 0.60(0.57+0.03) -28.6%
4205.3: log with %T 0.53(0.49+0.04) 0.52(0.48+0.03) -1.9%
4205.4: log with %t 0.84(0.80+0.04) 0.60(0.59+0.01) -28.6%
4205.5: log with %P 0.52(0.48+0.03) 0.51(0.50+0.01) -1.9%
4205.6: log with %p 0.85(0.78+0.06) 0.61(0.56+0.05) -28.2%
4205.7: log with %h-%h-%h 0.96(0.92+0.03) 0.69(0.64+0.04) -28.1%
Test HEAD^ HEAD
--------------------------------------------------------------------------------
5310.9: rev-list count with blob:none 1.67(1.62+0.05) 0.22(0.21+0.02) -86.8%
git init repo
cd repo
# make a pack with 2^24 objects
perl -e '
my $nr = 2**24;
for (my $i = 0; $i < $nr; $i++) {
print "blob\n";
print "data 4\n";
print pack("N", $i);
}
| git fast-import
# now make 256 copies of it; most of these objects will be duplicates,
# but oid_array doesn't de-dup until all values are read and it can
# sort the result.
cd .git/objects/pack/
pack=$(echo *.pack)
idx=$(echo *.idx)
for i in $(seq 0 255); do
# no need to waste disk space
ln "$pack" "pack-extra-$i.pack"
ln "$idx" "pack-extra-$i.idx"
done
# and now force an oid_array to store all of it
git cat-file --batch-all-objects --batch-check
fatal: size_t overflow: 32 * 18446744071562067968
git -c index.threads=1 commit --amend --allow-empty --no-edit
Benchmark #1: v2.30.0
Time (mean ± σ): 854.5 ms ± 18.2 ms
Range (min … max): 825.0 ms … 892.8 ms
Benchmark #2: Previous change
Time (mean ± σ): 833.2 ms ± 10.3 ms
Range (min … max): 815.8 ms … 849.7 ms
Benchmark #3: This change
Time (mean ± σ): 815.5 ms ± 18.1 ms
Range (min … max): 795.4 ms … 849.5 ms