在Windows系统上,git stash执行速度较慢。

54

在我的Windows机器上,每次调用git stash大约需要3.5秒的开销,这会给我的git提交钩子增加约7秒的时间。同一命令在Linux下(同一台机器)只需约0.01秒。该性能问题也适用于空代码库。

我已经尝试了此文此文中提到的以下几点:

  • core.fscache设置为true
  • core.preloadindex设置为true
  • gc.auto设置为256
  • 设置PS1='$ '
  • 以管理员模式运行cmd
  • cmd.exe中运行而非git-bash

运行GIT_TRACE=true git stash list

16:58:16.844591 git.c:563               trace: exec: 'git-stash' 'list'
16:58:16.844591 run-command.c:336       trace: run_command: 'git-stash' 'list'
16:58:19.699591 git.c:350               trace: built-in: git 'rev-parse' '--git-dir'
16:58:19.859591 git.c:350               trace: built-in: git 'rev-parse' '--git-path' 'objects'
16:58:20.069591 git.c:350               trace: built-in: git 'rev-parse' '--show-toplevel'
16:58:20.154591 git.c:350               trace: built-in: git 'rev-parse' '--git-path' 'index'
16:58:20.244591 git.c:350               trace: built-in: git 'config' '--get-colorbool' 'color.interactive'
16:58:20.334591 git.c:350               trace: built-in: git 'config' '--get-color' 'color.interactive.help' 'red bold'
16:58:20.424591 git.c:350               trace: built-in: git 'config' '--get-color' '' 'reset'
16:58:20.514591 git.c:350               trace: built-in: git 'rev-parse' '--verify' '--quiet' 'refs/stash'

real    0m3.845s
user    0m0.000s
sys     0m0.047s

运行GIT_TRACE_PERFORMANCE=true git stash list

16:59:18.414591 trace.c:420             performance: 0.001078046 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'rev-parse' '--git-dir'                                          
16:59:18.569591 trace.c:420             performance: 0.000947184 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'rev-parse' '--git-path' 'objects'                               
16:59:18.779591 trace.c:420             performance: 0.001253627 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'rev-parse' '--show-toplevel'                                    
16:59:18.869591 trace.c:420             performance: 0.001285517 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'rev-parse' '--git-path' 'index'                                 
16:59:18.955591 trace.c:420             performance: 0.001139994 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'config' '--get-colorbool' 'color.interactive'                   
16:59:19.040591 trace.c:420             performance: 0.001182881 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'config' '--get-color' 'color.interactive.help' 'red bold'       
16:59:19.125591 trace.c:420             performance: 0.001128997 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'config' '--get-color' '' 'reset'                                
16:59:19.215591 trace.c:420             performance: 0.001567766 s: git command: 'C:\Program Files\Git\mingw64\libexec\git-core\git.exe' 'rev-parse' '--verify' '--quiet' 'refs/stash'                    
16:59:19.295591 trace.c:420             performance: 3.730583540 s: git command: 'C:\Program Files\Git\mingw64\bin\git.exe' 'stash' 'list'                                                                

real    0m3.819s                                                                                                                                                                                          
user    0m0.000s                                                                                                                                                                                          
sys     0m0.062s                                                                                                                                                                                          

从日志中我们可以看到,在运行git-stash命令和git-rev-parse命令之间需要大约3秒钟的时间。是否有其他参数可以运行以找到瓶颈?

从日志中可见git-stash和git-rev-parse之间存在较长的延迟,是否有其他标识可以使用以确定瓶颈?


2
本地 Git 存储库是托管在您的本地驱动器上还是远程/网络存储库? - g19fanatic
1
如果你只是想让事情更快地运行,你可以尝试创建一个临时分支,将所有内容提交到那里,这样你就会得到与隐藏更改相同的效果(我经常这样做)。但如果你问这个问题是为了更好地理解stash功能是如何工作的,那么你可以查看git源代码:https://github.com/git/git - Mladen B.
我使用git-for-windows 2.11.1.windows.1时遇到了与OP相同的问题。我的gitconfig和存储库都在本地SSD上。@MladenB.虽然可以使用分支实现相同的结果,但需要更多的步骤,使其变得不切实际(与使用缓慢的stash一样糟糕或更糟)。此外,stash的整个重点是不创建记录在历史记录中的提交。 - OlivierD
@PascalLeMerrer 我注意到所有其他命令都相当快。checkout、branch、status、add、commit只需要不到一秒钟的时间就能执行完毕。只有stash命令非常慢(在我的情况下需要15秒)。 - OlivierD
1
相关:https://github.com/git/git/pull/495 - levant pied
显示剩余9条评论
2个回答

23
Git for Windows 2.19(2018年9月)中,git stash(和git rebase)不再是仅限于脚本的,而是实际上是使用git.exe编译的二进制文件。
请参见git-for-windows/build-extra PR 203

要激活它们,请键入

git config --global rebase.useBuiltin true
git config --global stash.useBuiltin true

警告:

虽然速度提升很好,但是相关的补丁仍在变动中,完全没有经过实战检验。

因此,目前脚本版本的 git stash 仍然是默认的,这样:

  • 想要通过三个Google Summer of Code项目并行工作得到原始速度提升的用户可以使用它,
  • 而那些不愿意成为试验品只运行经过充分测试的代码的人则可以保持安全。

重点是:在Git的下一个版本中,git-stash 的bash脚本最终将消失,其替代品将更快。

注意:下一个版本将是Git 2.27(2020年第二季度):“git stash”已经保留了逃生口以使用脚本版本进行几个版本,但已经过时。

它已被删除。

请参见commit 8a2cd3fcommit b0c7362(2020年3月3日)由Thomas Gummerer (tgummerer)提交。
(由Junio C Hamano -- gitster --commit 369ae75中合并,2020年3月27日)

stash:删除stash.useBuiltin设置

签名作者:Thomas Gummerer

删除stash.useBuiltin设置,该设置是为了在Git 2.22首次发布时禁用内置版本的stash而添加的一个逃生口。携带旧版stash是一项维护负担,并且自2.23版本发布以来因测试失败而变得过时,直到现在都没有人注意到。因此,用户将得到一个提示,要回退到可能存在漏洞的工具版本。我们曾经使用git config来获取useBuiltin配置,以避免在生成旧版stash之前更改任何全局状态。但是现在不再需要这样做,所以只需使用'git_config'函数来获取设置即可。与我们在d03ebd411c中所做的类似(“rebase: remove the rebase.useBuiltin setting”,2019-03-18,Git v2.22.0-rc0 - merge列在batch #5中),我们删除了rebase的相应设置,但保留了文档,以便人们在搜索时可以参考它,并且我们可以在提交消息中引用它。

在Git 2.22中更新Q2 2019,git stash完全重写为C语言。 请参见commit 40af146, commit 48ee24a, commit ef0f0b4, commit 64fe9c2, commit 1ac528c, commit d553f53, commit d4788af, commit 41e0dd5, commit dc7bd38, commit 130f269, commit bef55dc, commit dac566c, commit ab8ad46 (2019年2月25日) 由Paul-Sebastian Ungureanu (weekly-digest[bot])完成。
请参见commit c4de61d, commit 577c199, commit 4e2dd39, commit 8a0fc8d (2019年2月25日) 由Joel Teichroeb (klusark)完成。
请参见commit 7906af0, commit 90a4627, commit 8d8e9c2 (2019年2月25日) 由Johannes Schindelin (dscho)完成。
(由Junio C Hamano -- gitster --于2019年4月22日合并至commit e36adf7)

您仍然可以使用带有git legacy-stash的shell脚本
并且:

stash: 将stash--helper.c转换为stash.c

旧的shell脚本git-stash.sh已被删除,完全由builtin/stash.c替换。
为此,createpush被调整为无需stash.sh即可工作。

例如,在此提交之前,git stash create调用git stash--helper create --message "$*"。如果它调用了git stash--helper create "$@",那么就不需要进行这些更改。

此提交还删除了单词helper,因为现在直接调用stash而不是通过shell脚本调用。

有优化:

stash: 优化 get_untracked_files()check_changes()

这个提交通过避免重复调用相同的函数来进行了优化。 例如,`git stash push -u` 在某些时刻会调用下列函数: - `do_push_stash()` 中的 `check_changes()` - `do_create_stash()`,其中包括调用:`check_changes()` 和 `get_untracked_files()`
注意,`check_changes()` 也会调用 `get_untracked_files()`。因此,`check_changes()` 被调用了两次,而 `get_untracked_files()` 则被调用了三次。
旧的 `check_changes()` 函数现在变成了两个函数: `get_untracked_files()` 和 `check_changes_tracked_files()`。
以下是 `push` 和 `create` 的调用链: - `push_stash()` -> `do_push_stash()` -> `do_create_stash()` - `create_stash()` -> `do_create_stash()`
为了避免反复调用相同的函数,在 `do_create_stash()` 中的 `check_changes()` 现已放置于调用函数(`create_stash()` 和 `do_push_stash()`)内部。 这样一来,`check_changes()` 和 `get_untracked_files()` 只会被调用一次。

在 Git 2.36 (2022年第二季度) 中,终于移除了警告 "the stash.useBuiltin support has been removed!"!

请参见 commit e9b272e, commit deeaf5e, commit 5d4dc38, commit 6de0722,作者为 Johannes Schindelin (dscho)
(合并者为 Junio C Hamano -- gitster --,合并提交为 commit b9f791a,日期为 2022年2月16日)

stash: 停止警告关于已过时的stash.useBuiltin配置设置

签名:Johannes Schindelin

8a2cd3f(“stash: 删除stash.useBuiltin设置”,2020年3月3日,Git v2.27.0-rc0 -- batch #2中列出的merge),我们删除了对stash.useBuiltin的支持,但仍然保留了一个警告。

经过将近两年和几个主要版本的更新,现在是时候甚至删除那个警告了。


谢谢!现在它运行得很快。对于小的更改,使用存储大约需要0.3秒在我的电脑上。 - sighol
在 Git 版本 2.18.0.windows.1 上没有任何改进。 - GorvGoyl
1
@JerryGoyal 但是2.18版本似乎有点旧了。2.21是当前版本,能够更快地列出提交记录(https://dev59.com/IWEh5IYBdhLWcg3wMA0t#53382508),并在rebase方面有进一步的改进(https://dev59.com/5a3la4cB1Zd3GeqPPZlr#54973838)。 - VonC
这是否包括 git stash push --patch?它一直非常缓慢,特别是在大型仓库中,即使使用 pathspec 也是如此。 - CervEd
@CervEd 不确定。你在两端都测试了Git 2.38+吗?并且启用了Scalar吗? - VonC

3
[更新] 正如VonC在他的回答中所提到的: 自git 2.19(2018年9月)起,git stash是一个内置命令而不再是外部脚本。 如果您使用的是git 2.19或更高版本,则以下说明不再适用。
git-stash是一个脚本,而不是编译在git.exe二进制文件中的命令。
在Linux上:我可以在/usr/lib/git-core/git-stash找到git-stash - 我会让您在Windows上查找正确的路径...
该脚本使用#!/bin/sh来运行,我不知道在Windows上运行时使用哪个shell实现。
您可以尝试使用另一个兼容的shell(这里是bash)运行它:
# the git-core/ dir needs to be in the PATH,
# obviously  you will need to provide the correct path for your git-core dir

$ PATH=/usr/lib/git-core:$PATH bash /usr/lib/git-core/git-stash

您还可以打开-x标志,它会打印出所有执行的命令的跟踪,并且可以通过目视检查子命令中是否有挂起情况。
$ PATH=/usr/lib/git-core:$PATH bash -x /usr/lib/git-core/git-stash

1
在Windows上,shbash --posix,据我所知。 - CervEd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接