我有一个"新鲜的"git-svn repo(11.13 GB),其中有超过100,000个对象.
我已经做好了
git fsck git gc
在初步结账后的回购.
然后我试着去做
git status
执行git状态所需的时间是2m25.578s和2m53.901s
我通过发出命令测试了git status
time git status
5次,所有时间都在上面列出的两次之间.
我在Mac OS X上执行此操作,本地而非通过VM.
它不应该花这么长时间.
有任何想法吗?救命?
谢谢.
编辑
我有一个同事坐在我旁边,有一个类似的盒子.减少RAM并使用jfs文件系统运行Debian.他的git状态在同一个回购中运行.3(它也是一个git-svn checkout).
另外,我最近在这个文件夹上更改了我的文件权限(到777),它大大缩短了时间(为什么,我没有线索).我现在可以在3到6秒之间完成任务.这是可以控制的,但仍然很痛苦.
它归结为我现在能看到的几件物品.
git gc --aggressive
打开文件权限 777
必须有其他事情发生,但这显然是影响最大的事情.
git status必须每次查看存储库中的每个文件.您可以告诉它停止查看您没有使用的树木
git update-index --assume-unchanged
资源
从联机帮助页:
指定这些标志时,不会更新为路径记录的对象名称.相反,这些选项设置和取消设置路径的"假定未更改"位.当"假定未更改"位打开时,git停止检查工作树文件是否有可能的修改,因此您需要手动取消设置该位以在更改工作树文件时告诉git.当在具有非常慢的lstat(2)系统调用(例如cifs)的文件系统上处理大项目时,这有时是有用的.
此选项还可以用作粗略的文件级机制,以忽略跟踪文件中未提交的更改(类似于.gitignore对未跟踪文件的更改).如果需要在索引中修改此文件,例如在提交中合并时,Git将失败(优雅); 因此,如果上游更改了假定未跟踪文件,则需要手动处理该情况.
git中的许多操作依赖于您的文件系统以实现高效的lstat(2)实现,因此可以便宜地检查工作树文件的st_mtime信息,以查看文件内容是否已从索引文件中记录的版本更改.不幸的是,一些文件系统的效率低下lstat(2).如果您的文件系统是其中之一,则可以将"假设未更改"位设置为未更改的路径,以使git不执行此检查.请注意,在路径上设置此位并不意味着git将检查文件的内容以查看它是否已更改 - 它使git省略任何检查并假设它未更改.当您对工作树文件进行更改时,必须通过在修改它们之前或之后删除"假定未更改"位来明确告诉git.
...
要设置"假定未更改"位,请使用--assume-unchanged选项.要取消设置,请使用--no-assume-unchanged.
该命令查看core.ignorestat配置变量.如果这是真的,使用git update-index路径更新路径...并使用更新索引和工作树的其他git命令更新路径(例如git apply --index,git checkout-index -u和git read-tree -u )自动标记为"假设不变".注意,如果git update-index --refresh发现工作树文件与索引匹配,则不设置"假定未更改"位(如果要将它们标记为"假定未更改",请使用git update-index --really-refresh).
现在,很明显,如果您可以方便地忽略回购的某些部分,此解决方案才会起作用.我在一个类似规模的项目上工作,肯定有大树,我不需要定期检查.git-status的语义使其成为一般的O(n)问题(文件数量为n).您需要特定于域的优化才能做得更好.
请注意,如果您使用拼接模式,即如果您通过合并而不是rebase从上游集成更改,则此解决方案变得不太方便,因为从上游合并的--assume-unchanged对象的更改将变为合并冲突.您可以使用基础工作流程来避免此问题.
git status
应该在Git 2.13(2017年第二季度)中更快,因为:
关于字符串优化数组的优化(参见" 提高git status
性能的方法 ")
更好的"读缓存"管理.
关于最后一点,请参阅Jeff Hostetler()提交a33fc72(2017年4月14日).(由Junio C Hamano合并- -在提交cdfe138,2017年4月24日)jeffhostetler
gitster
read-cache
:force_verify_index_checksum
教导git跳过在
verify_hdr()
调用索引文件末尾的SHA1-1校验和的验证,read_index()
除非设置了"force_verify_index_checksum
"全局变量.教会
fsck
强制进行此验证.校验和验证用于检测磁盘损坏,对于小型项目,计算SHA-1所需的时间并不重要,但对于巨大的存储库,此计算会为每个命令增加大量时间.
Git 2.14通过更好地考虑" 未跟踪的缓存 "来改善git状态性能,这允许Git stat
使用结构的mtime
字段跳过读取未跟踪的目录(如果他们的数据没有改变)stat
.
有关Documentation/technical/index-format.txt
未跟踪缓存的更多信息,请参阅.
请参阅David Turner()提交的edf3b90(2017年5月8日).(由Junio C Hamano合并- -在fa0624f,2017年5月30日)dturner-tw
gitster
当"
git checkout
","git merge
"等操纵核心内索引时,索引扩展中的各种信息将从原始状态中丢弃,因为通常情况下它们不会保持最新并且在 -与主索引上的操作同步.现在,在这些操作中复制未跟踪的缓存扩展,这将加速"git status"(只要缓存被正确无效).
更一般地说,使用Git 2.14.x/2.15写入缓存也会更快
请参阅提交ce012de,提交b50386c,提交3921a0b(2017年8月21日)作者:Kevin Willford(``).
(由Junio C gitster
Hamano合并- -在提交030faf2,2017年8月27日)
在编写每个索引条目时,我们过去花费的时间超过必要的周期来分配和释放内存.
这已经过优化.当索引超过一百万个条目且小回购没有性能下降时,[那]将节省3-7%.
2017年12月更新:Git 2.16(2018年第一季度)将提出一个额外的增强功能,这一次git log
,因为迭代松散的目标文件的代码刚刚得到优化.
见Derrick Stolee()提交163ee5e(2017年12月4日).(由Junio C Hamano合并- -在97e1f85承诺中,2017年12月13日)derrickstolee
gitster
sha1_file
:用strbuf_add()
而不是strbuf_addf()
在枚举松散对象时替换使用
strbuf_addf()
with .由于我们在使用路径之前已经检查了字符串的长度和十六进制值,因此我们可以通过使用较低级别的方法来防止额外的计算.strbuf_add()
for_each_file_in_obj_subdir()
一个消费者
for_each_file_in_obj_subdir()
是缩写代码.OID(对象标识符)缩写使用缓存对象的缓存列表(每个对象子目录)来快速重复查询,但是当存在许多松散对象时,存在显着的缓存加载时间.大多数存储库在重新打包之前没有很多松散的对象,但在GVFS情况下(参见" 宣布GVFS(Git虚拟文件系统) "),存储库可以增长到拥有数百万个松散对象.在一个支持GVFS的repo上使用~250万个松散对象
分析Git For Windows中的 'git log'性能,显示占用了12%的CPU时间strbuf_addf()
.添加一个新的性能测试
p4211-line-log.sh
,对此缓存加载更敏感.
通过限制为1000次提交,我们更接近于将历史记录读入寻呼机时的用户等待时间.对于具有两个~512 MB包文件和~572K松散对象的Linux repo的副本,运行'git log --oneline --parents --raw -1000'具有以下性能:
HEAD~1 HEAD ---------------------------------------- 7.70(7.15+0.54) 7.44(7.09+0.29) -3.4%
更新2018年3月:Git 2.17将进一步改进git status
:看到这个答案.
更新:Git 2.20(Q8 2018)添加了索引条目偏移表(IEOT),允许git status
更快地加载索引.
请参阅Ben Peart()提交77ff112,提交3255089,提交abb4bb8,提交c780b9c,提交3b1d9e0,提交371ed0d(2018年10月10日).
见提交252d079通过(2018年9月26日)阮泰玉维战().(由Junio C Hamano合并- -在提交e27bfaa,2018年10月19日)benpeart
pclouds
gitster
read-cache:在工作线程上加载缓存条目
此补丁通过利用索引条目偏移表(IEOT)来并行地分割多个线程中的缓存条目的加载和转换,从而有助于解决加载索引的CPU成本问题.
我曾经
p0002-read-cache.sh
生成一些性能数据:Test w/100,000 files reduced the time by 32.24% Test w/1,000,000 files reduced the time by -4.77%请注意,在1,000,000个文件的情况下,多线程缓存条目解析不会产生性能提升.这是因为在此repo中解析索引扩展的成本远远超过加载缓存条目的成本.
这允许:
config
:添加新的index.threads
配置设置添加对新
index.threads
配置设置的支持,该设置将用于控制线程代码do_read_index()
.
值为0将告诉索引代码自动确定要使用的正确线程数.
值为1将使代码单线程化.大于1的值将设置要使用的最大线程数.
出于测试目的,可以通过将
GIT_TEST_INDEX_THREADS=
环境变量设置为大于0的值来覆盖此设置 .
Git 2.21(2019年第一季度)引入了一项新的改进,更新了松散的对象缓存,用于优化已更新的存在查找.
见提交8be88db(2019年1月7日),并提交4cea1ce,提交d4e19e5,提交0000d65(2019年1月6日),由勒内Scharfe( )rscharfe
.
(由Junio C gitster
Hamano合并- -在提交eb8638a,2019年1月18日)
object-store
:oid_array
每个子目录使用一个松散缓存根据需要,松散对象缓存一次填充一个子目录.
它存储在一个中oid_array
,必须在每次添加操作后使用.
因此,在查询各种对象时,部分填充的阵列最多需要使用255次,这比排序一次要多100倍.
oid_array
每个子目录使用一个.
这确保了条目必须只进行一次排序.
它还避免了每个缓存查找的八个二进制搜索步骤作为小额奖励.缓存用于碰撞检查日志占位符
%h
,%t
并且%p
,我们可以看到的变化加快了他们在大约一库 每个子目录100个对象:
$ 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%
一个长期解决方案是增加git以在内部缓存文件系统状态.
Karsten Blees已经为msysgit做了这样的事情,它大大提高了Windows的性能.在我的实验中,他的更改花费了我在Win7机器上运行的"git status"从25秒到1-2秒的时间.
Karsten的变化:https://github.com/msysgit/git/pull/94
讨论缓存方法:https://groups.google.com/forum/#!topic / msysgit/fL_jykUmUNE/discussion