对于100,000个对象,Git非常慢。任何修复?

时间:2010-07-22 22:10:51

标签: performance git git-svn

我有一个“新鲜的”git-svn仓库(11.13 GB),其中有超过100,000个物体。

我已经预成型了

git fsck
git gc

在初次结账后回购。

然后我尝试了

git status

执行git状态所需的时间是2m25.578s和2m53.901s

我通过发出命令

测试了git状态
time git status

5次,所有时间都在上面列出的两次之间进行。

我在Mac OS X上执行此操作,本地而非通过VM。

没有办法花这么长时间。

有什么想法吗?帮助

感谢。

修改

我有一个同事坐在我旁边,有一个类似的盒子。减少RAM并使用jfs文件系统运行Debian。他的 git status 在同一个仓库中以.3运行(它也是一个git-svn结账)。

另外,我最近在这个文件夹上更改了我的文件权限(到777),它大大缩短了时间(为什么,我没有线索)。我现在可以在3到6秒之间完成任务。这是可以控制的,但仍然很痛苦。

12 个答案:

答案 0 :(得分:28)

现在我可以看到一些项目。

  1. git gc --aggressive
  2. 777
  3. 开放文件权限

    还有其他事情要发生,但这显然是影响最大的事情。

答案 1 :(得分:17)

答案 2 :(得分:5)

一个长期解决方案是增加git以在内部缓存文件系统状态。

Karsten Blees已经为msysgit做了这样的事情,它大大提高了Windows的性能。在我的实验中,他的改变花了很多时间来获得#git status"在我的Win7机器上运行的25秒到1-2秒。

卡斯滕的变化:https://github.com/msysgit/git/pull/94

讨论缓存方法:https://groups.google.com/forum/#!topic/msysgit/fL_jykUmUNE/discussion

答案 3 :(得分:5)

git status应该在Git 2.13(2017年第二季度)中更快,因为:

关于最后一点,请commit a33fc72查看Jeff Hostetler (jeffhostetler)(2017年4月14日) Junio C Hamano -- gitster --于2017年4月24日commit cdfe138合并)

  

read-cacheforce_verify_index_checksum

     

教git在结束时跳过SHA1-1校验和的验证   verify_hdr()中的索引文件,从read_index()调用,除非" force_verify_index_checksum"全局变量已设置。

     

fsck强制进行此验证。

     

校验和验证用于检测磁盘损坏,对于小型项目,计算SHA-1所需的时间并不重要,但对于巨大的存储库,此计算会为每个命令增加大量时间。

Git 2.14通过更好地考虑" untracked cache "来改善git状态的表现,这允许Git跳过读取未跟踪目录{} {{ 1}}数据未使用stat结构的mtime字段进行更改。

有关未跟踪缓存的更多信息,请参阅Documentation/technical/index-format.txt

commit edf3b90David Turner (dturner-tw)(2017年5月8日) Junio C Hamano -- gitster --于2017年5月30日commit fa0624f合并)

  

当" stat"," git checkout"等操纵核心内部索引时,索引扩展中的各种信息都是从原始状态中丢弃,因为它们通常不是最新的并且与主索引上的操作同步。

     

现在可以在这些操作中复制未跟踪的缓存扩展,这将加快" git status" (只要缓存被正确无效)。

更一般地说,使用Git 2.14.x / 2.15

也可以更快地写入缓存

commit ce012decommit b50386ccommit 3921a0bKevin Willford (``)(2017年8月21日)。{
Junio C Hamano -- gitster --于2017年8月27日commit 030faf2合并)

  

我们过去花费超过必要的周期分配和释放   写入每个索引条目时的记忆。
  这已经过优化。

     当索引有超过一百万个条目且小回购没有性能下降时,

[那]将节省3-7%。

2017年12月更新:Git 2.16(2018年第一季度)将针对git merge提出额外的增强功能,因为迭代松散目标文件的代码已经过优化。

commit 163ee5eDerrick Stolee (derrickstolee)(2017年12月4日) (由Junio C Hamano -- gitster --合并于commit 97e1f85,2017年12月13日)

  

git log:使用sha1_file代替strbuf_add()

     

枚举时将strbuf_addf()替换为strbuf_addf()   strbuf_add()中的松散对象。既然我们已经   在消费之前检查字符串的长度和十六进制值   路径,我们可以通过使用较低的 -   等级方法。

     

for_each_file_in_obj_subdir()的一个消费者是缩写   码。 OID(object identifiers)缩写使用缓存的松散对象列表(每个对象子目录)来快速重复查询,但是   当有许多松散的对象时,显着的缓存加载时间。

     

大多数存储库在重新打包之前没有很多松散的对象,但在 GVFS 的情况下(参见" Announcing GVFS (Git Virtual File System)"),存储库可以增长拥有数以百万计的松散物体   分析' git log'在Git For Windows上,在一个支持GVFS的repo上有大约250万个松散对象的性能显示,在for_each_file_in_obj_subdir()中花费了12%的CPU时间。

     

strbuf_addf()添加新的性能测试   对此缓存加载敏感。
  通过限制为1000次提交,我们更接近于将历史记录读入寻呼机时的用户等待时间。

     

对于包含两个~512 MB包文件和~572K松散对象的Linux repo的副本,运行' git log --oneline --parents --raw -1000'有以下表现:

p4211-line-log.sh

2018年3月更新:Git 2.17将进一步改善 HEAD~1 HEAD ---------------------------------------- 7.70(7.15+0.54) 7.44(7.09+0.29) -3.4% :见this answer

更新:Git 2.20(2018年第4季度)添加Index Entry Offset Table (IEOT),允许git status更快地加载索引。

commit 77ff112commit 3255089commit abb4bb8commit c780b9ccommit 3b1d9e0commit 371ed0dBen 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日)

  

读取缓存:在工作线程上加载缓存条目

     

此补丁有助于解决使用时加载索引的CPU成本   索引条目偏移表(IEOT)来划分加载和转换   多个线程并行的缓存条目。

     

我使用git status生成了一些效果数据:

p0002-read-cache.sh
     

请注意,在1,000,000个文件的情况下,多线程缓存条目解析   不会产生表现胜利。这是因为要解析的成本   此repo中的索引扩展远远超过加载缓存的成本   条目。

允许:

  

Test w/100,000 files reduced the time by 32.24% Test w/1,000,000 files reduced the time by -4.77% :添加新的config配置设置

     

添加对将用于的新 index.threads 配置设置的支持   控制index.threads中的线程代码。

     
      
  • 值为0将告诉索引代码自动确定要使用的正确线程数   值为1将使代码单线程化。
  •   
  • 大于1的值将设置要使用的最大线程数。
  •   
     

出于测试目的,可以通过设置来覆盖此设置   do_read_index()环境变量的值大于0。

Git 2.21(2019年第一季度)引入了一项新的改进,更新了松散对象缓存,用于优化已更新的存在查找。

commit 8be88db(201年1月7日)和commit 4cea1cecommit d4e19e5commit 0000d65(2019年1月6日)René Scharfe (rscharfe)(由Junio C Hamano -- gitster --合并于commit eb8638a,2019年1月18日)

  

GIT_TEST_INDEX_THREADS=<n>:每个子目录使用一个object-store进行松散缓存

     

松散对象缓存根据需要一次填充一个子目录   它存储在oid_array中,必须在每次添加操作后使用。{   因此,在查询各种对象时,部分填充的数组最多需要使用255次,这比排序一次要长100倍。

     

每个子目录使用一个oid_array   这确保了条目必须只进行一次排序   它还避免了每个缓存查找的八个二进制搜索步骤作为一个小额外奖励。

     

缓存用于对日志占位符oid_array%h%t进行冲突检查,我们可以看到更改将它们加速到存储库中。每个子目录100个对象:

%p

答案 4 :(得分:4)

一般来说,我的mac可以使用git但是如果有很多松散的对象,那么它会变得非常慢。似乎hfs在单个目录中有很多文件并不是那么好。

git repack -ad

其次是

git gc --prune=now

将生成单个包文件并删除遗留的任何松散对象。运行这些可能需要一些时间。

答案 5 :(得分:3)

您可以尝试将--aggressive切换到git gc并查看是否有帮助:

# this will take a while ...
git gc --aggressive

此外,如果您在历史记录中有不需要的内容(例如,旧的二进制文件),则可以使用git filter-branch删除旧的提交和/或文件。

答案 6 :(得分:2)

对于它的价值,我最近发现我的主人和开发分支之间的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

我有105,000个对象存储,但似乎大文件比许多小文件更具威胁性。

答案 7 :(得分:1)

您也可以尝试git repack

答案 8 :(得分:0)

也许您使用的是病毒扫描程序? 我已经在Windows和Linux上测试了一些大项目 - 它真是太快了!

我认为你不需要在克隆的回购中使用git gc(它应该是干净的)。

你的硬盘好吗?每秒IOPS和R / W?也许它已经损坏了?

答案 9 :(得分:0)

也许聚光灯试图索引文件。也许为你的代码目录禁用聚光灯。检查活动监视器并查看正在运行的进程。

答案 10 :(得分:0)

答案 11 :(得分:0)

尝试运行Prune命令它将摆脱,松散的对象

  

git remote prune origin