Performance Git对于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 svn repo(11.13 GB),其中包含超过100000个对象

我已经准备好了

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