改善git status性能的方法


80

我在NFS上的Linux机器上有10 GB的存储库。第一次git status需要36分钟,随后git status需要8分钟。似乎Git依赖于OS来缓存文件。只有第一个git命令(如commitstatus涉及到打包/重新打包整个存储库,才需要花费很长的时间才能生成大型存储库。我不确定您是否使用git status过这么大的回购协议,但是有人遇到过这个问题吗?

我已经试过git gcgit cleangit repack但所花费的时间仍是/几乎是相同的。

子模块或任何其他概念(如将回购分成更小的子集)是否有帮助?如果是这样,那是拆分更大的仓库的最佳选择。还有其他方法可以改善大型仓库上git命令花费的时间吗?


2
NFS几乎是这里的瓶颈。lstat是一个相当同步的操作。
user611775 2011年

Answers:


45

更准确地说,git取决于lstat(2)系统调用的效率,因此调整客户端的“属性缓存超时”可能会成功。

手册git-update-index(本质上是手册模式git-status)描述了通过使用该--assume-unchanged标志抑制其正常行为并手动更新已更改的路径来缓解此问题的方法。您甚至可以对编辑器进行编程,以使其在每次保存文件时均未设置此标志。

正如您所建议的那样,另一种方法是减小签出的大小(packfiles的大小实际上并没有发挥作用)。选项是稀疏签出,子模块或Google的回购工具。

(有一个关于将Git与NFS一起使用的邮件列表线程,但是它没有回答很多问题。)


31
您错过的事情:Linus的补丁实际上确实被合并了,可以通过将其设置core.preloadindex为true来启用它-有关git-config更多说明,请参阅文档。(我的工作场所使用NFS,但我
确实

1
此处应将'git config core.preloadindex true'添加到接受的答案中。可能带有来自user1077329的-uno标志
ostler.c 2014年

1
core.preloadindex标志设置为true,默认为Git的2.1.0:git.kernel.org/pub/scm/git/git.git/tree/Documentation/RelNotes/...
切赫Gazarov

38

我还在通过NFS共享的大型项目中看到了此问题。

我花了一些时间发现可以同时为git commit和git status赋予的-uno标志。

该标志的作用是禁止查找未跟踪的文件。这样可以大大减少nfs操作的次数。原因是,为了使git发现未跟踪的文件,它必须在所有子目录中查找,因此,如果您有许多子目录,这会伤害您。通过禁止git查找未跟踪的文件,您可以消除所有这些NFS操作。

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


git-status(1)所述,可以通过设置status.showUntrackedFiles配置将其设置为默认值。
johankj

33

尝试git gc。另外,git clean 可能会有所帮助。

更新-不确定否决权来自何处,但是git手册专门指出:

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

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

当git status很慢时,我总是在运行git gc之后发现差异!

更新II-不确定我怎么错过了,但是OP已经尝试了git gcgit clean。我发誓原来不存在,但是我看不到编辑内容有任何变化。抱歉!


4
我也不理解这次的否决。这真的很有帮助。git gcgit log我的一个仓库中的运行时间从15秒减少到0。
GreenRaccoon16年

@NicolasC啊!不知道我是怎么想念它的,但是我也会拒绝我的回答。:-/
Jabari

1
git cg很好,git clean可能会删除一些不需要的文件?
卡·雷格尔林

18

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

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

您将失去提醒的便利,即您可能忘记的任何子模块中都有未进行的阶段性更改,但是您仍将保留主要的便利,即知道子模块何时与主仓库不同步。另外,您仍然可以将工作目录更改为子模块本身,并照常在其中使用git status来查看更多信息。有关“脏”的含义的更多详细信息,请参见此问题


7

git status的性能应随Git 2.13(2017年第2季度)提高。

参见Jeff Hostetler(提交950a234(2017年4月14日(由Junio C Hamano合并--commit 8b6bba6中,2017年4月24日)jeffhostetler
gitster

> string-list:重新分配时使用ALLOC_GROWstring_list

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

在状态非常大的仓库上并且有很多更改时,花费了总运行时间的很大一部分来重新分配wt_status.changes数组

wt_status_collect_changes_worktree()在我的大型存储库中,此更改将时间从125秒减少到45秒。


此外,Git 2.17(2018年第二季度)将引入新的跟踪,以测量在繁重的索引操作中花费的时间。

提交ca54d9b通过(2018年1月27日)阮泰玉维战(pclouds
(通过合并JUNIOÇ滨野- gitster-提交090dbea 2月15日2018)

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存储库的副本中,远程分支“”后面有“ master”本地实例,origin/master提交了约60,000次提交,我们发现“ git status”的性能从1.42秒变为1.32秒,相对差异为-7.0%。


Git 2.24(Q3 2019)提出了另一种设置来提高git status性能:

请参阅Derrick Stolee(提交的commit aaf633ccommit c6cc4c5commit ad0fb65commit 31b1de6commit b068d9acommit 7211b9e(2019年8月13日(由Junio C Hamano合并--commit f4f8dfe中,2019年9月9日)derrickstolee
gitster

回购设置:创建feature.manyFiles设置

feature.manyFiles设置适用于工作目录中包含许多文件的存储库。
通过设置index.version=4core.untrackedCache=true,诸如' git status'之类的命令将得到改进。

但:

在Git 2.24(Q4 2019)中,读取index.version配置的代码路径已被最新更新破坏,该更新已得到纠正。

参见Derrick Stolee()的commit c11e996(2019年10月23日(由Junio C Hamano合并--commit 4d6fb2b中,2019年10月24日)derrickstolee
gitster

repo-settings:读取index.version的int

签字人:德里克·斯托利

几个配置选项repo_settings在ds / feature-macros中组合为一个结构,包括在7211b9e中移动“ index.version”配置设置(“ repo-settings:合并一些配置设置”,2019-08-13,Git v2.24.0-rc1 -合并批次0中列出的内容)。

不幸的是,该文件看起来像很多样板文件,并且显然是复制粘贴超载的一个因素,使用configrepo_config_ge_bool()而不是解析配置设置repo_config_get_int()。这意味着设置“ index.version = 4”将无法正确注册,并将恢复为默认版本3。

我在将v2.24.0-rc0合并到VFS for Git代码库中时发现了这一点,我们真的在乎该索引在版本4中。

这没有被代码库捕获,因为放置的版本检查t1600-index.sh不足以测试“基本”方案。在这里,我们修改测试以包括这些常规设置,以不会被features.manyFiles或覆盖GIT_INDEX_VERSION
当“默认”版本为3时,在do_write_index()不需要时将其降级为版本2 。


又见stackoverflow.com/a/43667992/6309和新的index.threads配置设置
VonC

GIT_TRACE = true git log这是运行跟踪并查找瓶颈的方法
dhavale

@dhavale实际上,从Git .22开始,您还拥有trace2:stackoverflow.com/a/56094711/6309
VonC

3

git config --global core.preloadIndex true

为我做了工作。在此处查看官方文档。


您正在使用哪个版本的Git?
VonC

2.7.4。我使用Windows的Linux子系统,甚至进行了更新,apt-get似乎都引用了相当旧的软件包。
klimat

1
好吧,有道理。我认为最新版本不需要它。
VonC

这甚至帮助我使用git 2.17.1版本
Markus Zeller

1

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


1

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

git config core.fscache true


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

git config core.ignoreStat true

但是:开发人员随后必须使用添加更改的文件git add。Git本身不会发现更改。

资源


即使我使用的Windows Git版本较新,这也对Windows 10有所帮助。谢谢。我的存储库是.git文件夹中的100 Gb(git lfs)
Alex Sorokoletov

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在我的assetsgit子模块中花费了1.7秒。

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

我搜索了这个问题,发现使用索引和Racy Git问题

尝试过git 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并删除剩余的。


0

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

您提到您的git repo约为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重新提交文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.