我有一个“新鲜的”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
的文件权限必须有其他事情发生,但这显然是影响最大的事情。
也许聚光灯试图索引文件。也许为你的代码目录禁用聚光灯。检查Activity Monitor并查看正在运行的进程。
我使用不同的文件系统创建一个分区。与在其他文件系统上执行类似操作相比,HFT +对我来说一直很迟钝。
尝试运行Prune命令它将摆脱掉松散的对象
git远程修剪原产地
git status必须每次查看存储库中的每个文件。您可以告诉它停止查看您没有使用的树木
git update-index --assume-unchanged <trees to skip>
从联机帮助页:
指定这些标志时,不会更新为路径记录的对象名称。相反,这些选项设置和取消设置路径的“假定未更改”位。当“假定未更改”位打开时,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
performance”)关于最后一点,请参阅由commit a33fc72撰写的Jeff Hostetler (jeffhostetler
)(2017年4月14日)。
(Junio C Hamano -- gitster
--于commit cdfe138合并,2017年4月24日)
read-cache
:force_verify_index_checksum
教git跳过
verify_hdr()
中索引文件末尾的SHA1-1校验和验证,qzxswpoi从read_index()
调用,除非设置了“force_verify_index_checksum
”全局变量。教
fsck
强制进行此验证。校验和验证用于检测磁盘损坏,对于小型项目,计算SHA-1所需的时间并不重要,但对于巨大的存储库,此计算会为每个命令增加大量时间。
Git 2.14通过更好地考虑“untracked cache”来改善git状态的性能,如果stat
数据没有改变,使用mtime
结构的stat
字段,它允许Git跳过读取未跟踪目录。
有关未跟踪缓存的更多信息,请参阅Documentation/technical/index-format.txt
。
请参阅commit edf3b90撰写的David Turner (dturner-tw
)(2017年5月8日)。
(Junio C Hamano -- gitster
--于2017年5月30日在commit fa0624f合并)
当“
git checkout
”,“git merge
”等操纵内核索引时,索引扩展中的各种信息将从原始状态中丢弃,因为通常不会保持它们保持最新状态。与主索引上的操作同步。现在,在这些操作中复制未跟踪的缓存扩展,这将加速“git status”(只要缓存被正确无效)。
更一般地说,使用Git 2.14.x / 2.15写入缓存也会更快
参见commit ce012de,commit b50386c,commit 3921a0b,Kevin Willford (``)(2017年8月21日)。
(由Junio C Hamano -- gitster
--合并于commit 030faf2,2017年8月27日)
在编写每个索引条目时,我们过去花费的时间超过必要的周期来分配和释放内存。 这已经过优化。
当索引超过一百万个条目且小回购没有性能下降时,[那]将节省3-7%。
更新2017年12月:Git 2.16(2018年第一季度)将为git log
提出一个额外的增强功能,因为迭代松散目标文件的代码已经过优化。
请参阅commit 163ee5e撰写的Derrick Stolee (derrickstolee
)(2017年12月4日)。
(Junio C Hamano -- gitster
--合并于commit 97e1f85,2017年12月13日)
sha1_file
:使用strbuf_add()
而不是strbuf_addf()
在
strbuf_addf()
中枚举松散物体时,用strbuf_add()
替换使用for_each_file_in_obj_subdir()
。由于我们在使用路径之前已经检查了字符串的长度和十六进制值,因此我们可以通过使用较低级别的方法来防止额外的计算。
for_each_file_in_obj_subdir()
的一个消费者是缩写代码。 OID(object identifiers)缩写使用缓存的松散对象列表(每个对象子目录)来快速重复查询,但是当存在许多松散对象时,存在显着的缓存加载时间。大多数存储库在重新打包之前没有很多松散的对象,但在GVFS的情况下(参见“Announcing GVFS (Git Virtual File System)”),存储库可以增长到拥有数百万个松散的物体。 在一个支持GVFS的回购中,Git For Windows对大约250万个松散对象进行了“git log”性能分析,显示12%的CPU时间花费在
strbuf_addf()
上。向
p4211-line-log.sh
添加一个新的性能测试,该测试对此缓存加载更敏感。 通过限制为1000次提交,我们更接近于将历史记录读入寻呼机时的用户等待时间。对于具有两个~512 MB包文件和~572K松散对象的Linux存储库副本,运行'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
:请参阅this answer。
更新:Git 2.20(Q8 2018)添加了Index Entry Offset Table (IEOT),它允许git status
更快地加载索引。
参见commit 77ff112,commit 3255089,commit abb4bb8,commit c780b9c,commit 3b1d9e0,commit 371ed0d,Ben Peart (benpeart
)(2018年10月10日)。
参见commit 252d079撰写的Nguyễn Thái Ngọc Duy (pclouds
)(2018年9月26日)。
(由Junio C Hamano -- gitster
--合并于commit e27bfaa,2018年10月19日)
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=<n>
环境变量设置为大于0的值来覆盖此设置。
Git 2.21(2019年第一季度)引入了一项新的改进,更新了松散的对象缓存,用于优化已更新的存在查找。
参见commit 8be88db(2019年1月7日)和commit 4cea1ce,commit d4e19e5,commit 0000d65(2019年1月6日)。
(由René Scharfe (rscharfe
)合并于Junio C Hamano -- gitster
--,2019年1月18日)
commit eb8638a:每个子目录使用一个
object-store
进行松散缓存根据需要,松散对象缓存一次填充一个子目录。 它存储在
oid_array
中,必须在每次添加操作后使用。 因此,在查询各种对象时,部分填充的阵列最多需要使用255次,这比排序一次要多100倍。每个子目录使用一个
oid_array
。 这确保了条目必须只进行一次排序。 它还避免了每个缓存查找的八个二进制搜索步骤作为小额奖励。缓存用于对日志占位符
oid_array
,%h
和%t
进行冲突检查,我们可以看到更改将它们加速到存储库中。每个子目录100个对象:
%p
一个长期解决方案是增加git以在内部缓存文件系统状态。
Karsten Blees已经为msysgit做了这样的事情,它大大提高了Windows的性能。在我的实验中,他的更改花费了我在Win7机器上运行的“git status”从25秒到1-2秒的时间。
卡斯滕的变化:$ 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%
一般来说我的mac可以使用git,但是如果有很多松散的对象,那么它会变得非常慢。似乎hfs在单个目录中有很多文件并不是很好。
https://groups.google.com/forum/#!topic/msysgit/fL_jykUmUNE/discussion
其次是
git repack -ad
将制作单个包文件并删除遗留的任何松散对象。运行这些可能需要一些时间。
您可以尝试将git gc --prune=now
开关传递给--aggressive
,看看是否有帮助:
git gc
此外,如果您有历史记录中不需要的东西(例如,旧的二进制文件),您可以使用# this will take a while ...
git gc --aggressive
删除旧的提交和/或文件。
对于它的价值,我最近发现我的主人和开发分支之间的qazxsw poi命令之间存在很大的差异。
简而言之,我将问题追溯到项目根目录中的单个280MB文件。这是一次数据库转储的意外签入,因此可以删除它。
这是之前和之后:
git filter-branch
我在商店里有105,000个对象,但似乎大文件比许多小文件更具威胁性。
你也可以试试git status
也许你使用病毒扫描程序?我在Windows和Linux上测试了一些大项目 - 它真快!
我不认为你需要在克隆的回购中做一个git gc(它应该是干净的)。
你的硬盘好吗?每秒IOPS和R / W?也许它已经损坏了?