90

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

我试过了git gc,但是git cleangit repack用的时间仍然/几乎相同。

子模块或任何其他概念(如将 repo 分解成更小的部分)会有帮助吗?如果是这样,哪个是拆分更大回购的最佳选择。有没有其他方法可以改善大型 repo 上 git 命令所花费的时间?

4

11 回答 11

48

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

手册git-update-index(本质上是手动模式git-status)描述了您可以采取哪些措施来缓解这种情况,方法是使用--assume-unchanged标志来抑制其正常行为并手动更新您已更改的路径。您甚至可以对编辑器进行编程以在每次保存文件时取消设置此标志。

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

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

于 2011-02-14T17:27:46.927 回答
39

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

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

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

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

于 2012-05-30T20:48:24.063 回答
35

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

更新- 不知道否决票来自哪里,但 git 手册特别指出:

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

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

当 git status 很慢时,我总是在运行 git gc 后注意到不同之处!

更新二- 不知道我是怎么错过的,但 OP 已经尝试过git gc并且git clean. 我发誓最初并不存在,但我没有看到编辑有任何变化。对不起!

于 2016-05-24T20:58:35.367 回答
22

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

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

您将失去提醒您可能忘记的任何子模块中存在未分阶段更改的便利,但您仍将保留了解子模块何时与主存储库不同步的主要便利。另外,您仍然可以将工作目录更改为子模块本身,并像往常一样在其中使用 git status 以查看更多信息。有关“脏”含义的更多详细信息,请参阅此问题。

于 2012-08-24T14:40:27.223 回答
9

git status 的性能应该会随着 Git 2.13(2017 年第二季度)的改进而提高。

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

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

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

在非常大的 repo 上的状态期间并且有许多更改,总运行时间的很大一部分用于重新分配wt_status.changesarray

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


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

请参阅Nguyễn Thái Ngọc Duy ( ) 的提交 ca54d9b(2018 年 1 月 27 日(由Junio C Hamano 合并 -- --090dbea 提交中,2018 年 2 月 15 日)pclouds
gitster

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()

在远程分支 " " 后面的本地实例 "master" 的 Linux repo 副本上,origin/master大约 60,000 次提交,我们发现 " git status" 的性能从 1.42 秒变为 1.32 秒,相对差异为 -7.0%。


Git 2.24(2019 年第三季度)提出了另一种提高git status性能的设置:

请参阅Derrick Stolee ( ) 的提交 aaf633c提交 c6cc4c5提交 ad0fb65提交 31b1de6提交 b068d9a提交 7211b9e(2019 年 8 月 13 日(由Junio C Hamano 合并 -- --提交 f4f8dfe中,2019 年 9 月 9 日)derrickstolee
gitster

repo-settings:创建 feature.manyFiles 设置

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

但:

在 Git 2.24(2019 年第四季度)中,读取index.version配置的代码路径因最近的更新而被破坏,该更新已得到纠正。

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

repo-settings: 为 index.version 读取一个 int

签字人:Derrick Stolee

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

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

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

这没有被代码库捕获,因为放置的版本检查t1600-index.sh没有足够测试“基本”场景。在这里,我们修改测试以包含这些正常设置,以防止被features.manyFilesor覆盖GIT_INDEX_VERSION
虽然“默认”版本是 3,但在do_write_index()不需要时会降级为版本 2。


由于 Git 2.33(2021 年第三季度),git status 还将更快地比较 SHA1,在写入索引文件的代码路径中使用优化的哈希文件 API。

请参阅Derrick Stolee ( ) 的提交 f6e2cd0提交 410334e提交 2ca245f(2021 年 5 月 18 日)和提交 68142e1(2021 年 5 月 17 日(由Junio C Hamano 合并 -- --0dd2fd1 提交中,2021 年 6 月 14 日)derrickstolee
gitster

csum-file.h: 增加哈希文件缓冲区大小

签字人:Derrick Stolee

hashfile API 使用 8KB 的硬编码缓冲区大小,并且自从它在c38138c中引入以来就一直存在(“ git-pack-objects:使用 SHA1 csum 编写包文件”,2005-06-26,Git v0.99 --合并)。
它执行与 中的哈希缓冲区类似的功能read-cache.c,但该代码在f279894中从 8KB 更新为 128KB (“ read-cache:使索引写入缓冲区大小为 128K”,2021-02-18,Git v2.31.0-rc1 --合并) .
理由是do_write_index()从 1.02 秒提高到 0.72 秒。
由于我们的最终目标是让索引编写代码使用 hashfile API,我们需要统一这个缓冲区大小以避免性能回归。

由于这些缓冲区现在在堆上,我们可以根据消费者的需要调整它们的大小。
特别是,调用者hashfd_throughput()期望在缓冲区刷新时报告进度指示器。
这些调用者更喜欢较小的 8k 缓冲区以避免更新之间的大延迟,尤其是对于网络较慢的用户。
当不使用进度指示器时,最好使用较大的缓冲区。

通过在块格式 API 中添加一个新trace2区域,我们可以看到 ' git multi-pack-index write' ( man )的写入部分在 Linux 机器上从 ~1.49s 降低到 ~1.47s。
这些影响在其他文件系统上可能更加明显或减弱。

于 2017-04-26T20:55:06.080 回答
5

git config --global core.preloadIndex true

为我完成了这项工作。在此处查看官方文档。

于 2018-01-23T13:20:40.697 回答
4

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

于 2019-04-16T00:00:24.903 回答
3

还没有提到的是,激活 Windows 机器上的文件系统缓存(Linux 文件系统完全不同,git 针对它们进行了优化,因此这可能只对 Windows 有帮助)。

git config core.fscache true


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

git config core.ignoreStat true

但是:更改后的文件必须由开发人员自己使用git add. Git 本身不会发现更改。

来源

于 2019-07-03T20:21:41.580 回答
2

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

在绝望的举动中,我试图更新笔记本电脑的图形驱动程序并...

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

……我也是!

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

于 2021-06-02T12:03:43.087 回答
1

剩余index.lock文件

git status当您有剩余index.lock文件时,可能会变得异常缓慢。

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

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


细节

我发现我的 shell git status 在我的 repo 中非常慢,在 Ubuntu 16.04 上使用 git 2.19。

挖进去发现/usr/bin/time git status在我的assetsgit 子模块中花了 1.7 秒。

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

我用谷歌搜索了这个问题,发现了Use of index and 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 操作中都会注意到它,但是对于你不经常提交的子模块,你可能几个月都不会注意到它,因为它只在向索引添加内容时出现;警告不会在 read-only 上引发git status

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

因此,如果您的 git 状态异常缓慢,请检查find .git/ -name index.lock并删除剩余部分。

于 2019-10-10T16:21:15.550 回答
-1

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

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

于 2019-11-22T05:16:32.373 回答