提高git状态表现的方法

时间:2011-02-14 16:49:04

标签: performance git nfs

我在一台位于NFS上的Linux机器上有一个10 GB的仓库。第一次git status需要36分钟,后续git status需要8分钟。似乎Git依赖于操作系统来缓存文件。只有gitcommit这些涉及打包/重新打包整个回购的status命令需要很长时间才能获得巨大的回购。我不确定您是否在这么大的回购中使用了git status,但有没有人遇到过这个问题?

我尝试了git gcgit cleangit repack,但所用时间仍然/几乎相同。

子模块或任何其他概念(例如将repo分解为较小的那些)会有帮助吗?如果是这样,那么最好分割更大的回购。有没有其他方法可以改善大型仓库上git命令的时间?

12 个答案:

答案 0 :(得分:39)

更准确地说,git取决于lstat(2)系统调用的效率,因此调整客户端的“attribute cache timeout”可能会有所帮助。

git-update-index的手册 - 基本上是git-status的手动模式 - 描述了您可以采取哪些措施来缓解此问题,通过using the --assume-unchanged flag来抑制其正常行为并手动更新您的路径已经改变。您甚至可以编程编辑器以在每次保存文件时取消设置此标志。

正如您所建议的那样,另一种方法是减少结帐的大小(包文件的大小在这里并没有真正发挥作用)。选项包括稀疏结帐,子模块或Google的repo工具。

(有一个邮件列表thread about using Git with NFS,但它没有回答很多问题。)

答案 1 :(得分:32)

我也在通过NFS共享的大型项目上看到了这个问题。

花了一些时间才发现可以同时给git commit和git status的标志 -uno

此标志的作用是禁用查找未跟踪的文件。这显着减少了nfs操作的数量。原因是为了让git发现未跟踪的文件,它必须查看所有子目录,所以如果你有许多子目录,这将伤害你。通过禁止git查找未跟踪的文件,可以消除所有这些NFS操作。

将它与core.preloadindex标志相结合,即使在NFS上也可以获得合理的性能。

答案 2 :(得分:25)

试试git gc。另外,git clean 可以帮助。

更新 - 不确定向下投票的来源,但git手册明确指出:

  

在当前存储库中运行许多内务处理任务,例如压缩文件修订(以减少磁盘空间和 提高性能 )并删除可能已存在的无法访问的对象从之前的git add调用中创建。

     

鼓励用户定期在每个存储库中运行此任务,以保持良好的磁盘空间利用率和良好的运行性能。

当git状态很慢时,我总是注意到在运行git gc后有所不同!

UPDATE II - 不确定我是怎么错过这个,但OP已经尝试过git gc和git clean。我发誓原本不在那里,但我没有看到编辑中的任何变化。对不起!

答案 3 :(得分:15)

如果您的git repo大量使用子模块,您可以通过编辑.git目录中的配置文件并在任何特别大/重的子模块上设置ignore = dirty来大大加快git状态的性能。例如:

[submodule "mysubmodule"]
url = ssh://mysubmoduleURL
ignore = dirty

你会丢失提醒的便利性,你可能已经忘记了任何子模块中的非分段更改,但你仍然可以保持知道子模块何时与主模块不同步的主要方便性回购。此外,您仍然可以将工作目录更改为子模块本身,并按常规使用git status以查看更多信息。有关“脏”的含义的详细信息,请参阅this question

答案 4 :(得分:6)

git 2.13(2017年第二季度)将改善git状态的表现。

commit 950a234Jeff Hostetler (jeffhostetler)(2017年4月14日) Junio C Hamano -- gitster --于2017年4月24日commit 8b6bba6合并)

> string-list:在重新分配string_list

时使用ALLOC_GROW macro
  

重新分配ALLOC_GROW()数组时使用string_list宏   而不是简单地将它增加32   这是性能优化。

     

在一个非常大的回购的状态期间,有很多变化,   占用总运行时间的很大一部分用于重新分配wt_status.changes array

     

此更改会将wt_status_collect_changes_worktree()上的时间从125秒减少到45秒。

另外,Git 2.17(2018年第二季度)将引入一条新的跟踪,用于衡量在索引繁重的操作中花费的时间。

commit ca54d9bNguyễn Thái Ngọc Duy (pclouds)(2018年1月27日) (由Junio C Hamano -- gitster --合并于commit 090dbea,2018年2月15日)

  

trace:衡量在索引繁重的操作中花费的时间

     

测量所有已知的重代码块(对象数据库除外)   访问)。这有助于确定优化是否有效或   不是。
  未经优化的git-status将提供如下内容:

0.001791141 s: read cache ...
0.004011363 s: preload index
0.000516161 s: refresh index
0.003139257 s: git command: ... 'status' '--porcelain=2'
0.006788129 s: diff-files
0.002090267 s: diff-index
0.001885735 s: initialize name hash
0.032013138 s: read directory
0.051781209 s: git command: './git' 'status'

相同的Git 2.17(2018年第二季度)改善了git status

  

revision.c:减少对象数据库查询

     

mark_parents_uninteresting()中,我们检查是否存在   目标文件,看看我们是否应该将提交视为已解析。结果   是设置"解析"提交位。

     

将条件修改为仅检查has_object_file()结果   会改变解析的位。

     

当本地分支与其上游参考不同时," git status"   将计算前/后计数   这会使用paint_down_to_common()并点击mark_parents_uninteresting()

     

在Linux repo的副本上,本地实例为" master"在远程分支后面" origin/master"通过~60,000次提交,我们发现了性能   " git status"为亲戚,从1.42秒到1.32秒   相差-7.0%。

答案 5 :(得分:1)

git config --global core.preloadIndex true

这份工作对我而言。查看官方文档here

答案 6 :(得分:1)

在我们的代码库中,我们拥有20到30个子模块的范围,
git status --ignore-submodules
大大加快了我的工作速度。请注意,此不会报告子模块的状态

答案 7 :(得分:1)

好吧,如果我不亲眼看到,这很难相信......我在全新的工作笔记本电脑上的性能非常差,git status 需要 5 到 10 秒才能完成,即使是最愚蠢的存储库。 我已经尝试了该线程中的所有建议,然后我注意到 git log 也很慢,所以我扩大了对 git 全新安装的一般缓慢的搜索范围,我发现了这一点 https://github.com/gitextensions/gitextensions/issues/5314#issuecomment-416081823

我迫不及待地尝试更新笔记本电脑的图形驱动程序,然后......

<块引用>

神圣的圣诞老人 sh*t... 成功了!

...对我来说也是!

显然显卡驱动程序在这里有一些关系......很难理解为什么,但现在性能“如预期”!

答案 8 :(得分:0)

我不知道它有什么意义,但对我来说状态是花了30分钟,我尝试了我能在网上找到的一切,最后,我做了git reset我有100次改变我从存储中应用存储从不同的分支创建存储但应用于此分支,它们都是暂存但未提交(只是解释,我在遇到此问题之前做了不同的事情),git reset花了15分钟,但之后一切都开始快速起作,状态不到一秒钟。我不是一个git专家只是告诉我的问题解决了什么,希望它能帮助其他人登陆这个页面。

答案 9 :(得分:0)

尚未提及的是在Windows计算机上激活文件系统缓存(Linux文件系统完全不同,并且git已针对它们进行了优化,因此这可能仅在Windows上有用)。

git config core.fscache true


作为最后的选择,如果git仍然很慢,则可以关闭修改时间检查,即git需要找出哪些文件已更改。

git config core.ignoreStat true

但是:之后,开发人员必须使用git add添加更改的文件。 Git本身找不到更改。

source

答案 10 :(得分:0)

剩余的index.lock个文件

当剩下git status个文件时,

index.lock在病理上可能会变慢。

尤其是当您拥有git submodules时,会发生这种情况,因为那样的话,您通常不会注意到这样的剩余文件。

摘要:运行find .git/ -name index.lock,并在检查剩余的文件确实未被当前正在运行的程序使用后,将其删除


详细信息

我发现回购中的shell git状态非常慢,在Ubuntu 16.04上使用git 2.19。

深入研究,发现我的/usr/bin/time git status git子模块中的assets用了1.7秒。

strace找到了,git用mmap在那里读取了我所有的大文件。 通常不会这样做,通常stat就足够了。

我搜索了问题并找到了Use of index and Racy Git problem

尝试heregit update-index somefile(在子模块结帐中为gitignore) 但是失败了

fatal: Unable to create '/home/niklas/src/myproject/.git/modules/assets/index.lock': File exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.

这是一个经典错误。通常您在任何git操作中都会注意到它,但是对于您不经常提交的子模块,您可能几个月都不会注意到它,因为它仅在向索引添加内容时出现;在只读git status上不会发出警告。

删除index.lock文件后,git status立即变得很快,mmaps消失了,现在速度快了1000倍。

因此,如果您的git状态异常缓慢,请选中find .git/ -name index.lock并删除剩菜。

答案 11 :(得分:0)

这是一个很老的问题。不过,令我惊讶的是,鉴于存储库的大小,没有人对二进制文件发表评论。

您提到您的git回购约为10GB。似乎除了NFS问题和其他git问题(可通过git gc解决,并且git配置更改为其他答案中概述的问题)之外,由于存在大量git命令(git status,git diff,git add)存储库中的二进制文件。 git不擅长处理二进制文件。您可以使用以下命令删除不必要的二进制文件(例如NetCDF文件的示例;之前已备份git存储库):

git filter-branch --force --index-filter \  
'git rm --cached --ignore-unmatch *.nc' \   
--prune-empty --tag-name-filter cat -- --all

不要忘记将``* .nc''放到gitignore文件中以阻止git重新提交文件。