Oh-my-zsh 运行缓慢,但仅限于某些 Git 仓库。

我最近开始使用 Zsh,它非常棒。不幸的是,对于我认为是“main”的项目,一切都很慢。我的意思是,每次我运行一个命令——例如 ls——在执行命令和再次使用终端之间大约有5秒钟的延迟。

这次回购有什么不同之处让 Zsh 变得如此缓慢?我假设这是一个特定于 Zsh 的东西,因为在我开始使用 Zsh 之前没有任何问题。我尝试做 git clean,但没有任何明显的差异。

如果有必要的话,我用的是 Mac OS X。

更新: 原来是我的 .zshenv的这一行让它变慢了:

[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function

如果我注释这一行,它会从3秒钟变成1秒钟。不幸的是,我需要这一行,因为我的许多项目使用 RVM。我不知道现在该怎么办。

更新2 : 这似乎是一个特别的 oh-my-zsh 事件。

79048 次浏览

有各种各样的方式来加速一个 oh-my-zsh,如详细的“ Zsh 开始得非常慢”,清理插件部分。

例如,博客文章“ 修复了 oh-my-zsh git-svn 提示符的缓慢性”提到 parse_git_dirty函数是一个潜在的问题。

它可以是在每个命令之后调用 git 和 rvm 的主题。

对我来说,将 ZSH_THEME="juanghurtadoto"改为 ZSH_THEME="miloshadzic"完全消除了每次命令后2秒钟的延迟。

主题可以在 https://github.com/robbyrussell/oh-my-zsh/wiki/themes找到

我终于想明白了。我的项目有一个 rake文件夹,其中包含大量文件(比如20,000个)。我不知道那个文件夹是干什么用的,但我删除了它,Zsh 不再慢了,我的应用程序似乎还能用。

您可以将其添加到您的 git 配置中,zsh 将不再检查状态

git config --add oh-my-zsh.hide-status 1
git config --add oh-my-zsh.hide-dirty 1

解释

Lib/git.zsh中有两个中央 git 函数:

  • git_prompt_info()
  • parse_git_dirty()

每个 Method 都有一个 git 配置开关来禁用它:

  • oh-my-zsh.hide-status
  • oh-my-zsh.hide-dirty

有些主题创建自己的 git 查询,有时创建 忽略这些旗帜

Oh _ my _ zsh 对于某些回购来说似乎比较慢,因为它在每个命令之后检查回购的状态。 这种行为可以在. oh _ my _ zsh 的新版本中重写。 只需在. zhrc 中取消注释以下行:

DISABLE _ UNTRACKED _ Files _ DIRTY = “ true”

此后,重新启动终端或运行以下命令:

来源 ~/. zhrc

对我来说,它在 VirtualBox (客户端)上运行缓慢,因为我使用的是同步文件夹。我仍然希望它在 OS X (主机)上启用它的速度足够快。我没有使用本地配置设置,而是使用 仅在客户端上设置全局配置:

git config --global --add oh-my-zsh.hide-dirty 1

如果只是为了一次回购:

git config --add oh-my-zsh.hide-dirty 1

如果除了 git之外您不关心其他版本控制程序,那么您只需禁用 *.zsh-theme中的所有 vcs_info并用本机 git命令替换它们即可。

例如,我通过以下方式调整我的 agnoster.zsh-theme:

  1. 注释/删除所有包含 vcs_info的行,
  2. 编辑 prompt_git()函数中的代码:

    ref="$vcs_info_msg_0_"

    ref="$(git branch 2>/dev/null | grep -Po '(?<=\* ).*$')"

所以,基本上,我只是禁用了所有的 vcs_info操作,而是使用一个本地 git命令来检查回购的状态。因此,我仍然可以看到有用的 git 提示符,其速度与在非 git 目录中工作的速度一样快。通过这个小小的修改,我的 zsh 在 git 回购协议中的工作速度可以提高4-5倍。

注意: 使用 GNU grep 而不是 BSD grep。

上面的答案并没有解决我的问题。在我的例子中,函数 git_prompt_status比其他函数花费了太多的时间。所以我修改了 ~/。Oh-my-zsh/lib/git.zsh,用我的早期返回版本替换 git_prompt_status函数:

function git_prompt_status() {
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
echo $STATUS
return


local INDEX STATUS
INDEX=$(command git status --porcelain -b 2> /dev/null)
STATUS=""
if $(echo "$INDEX" | command grep -E '^\?\? ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_UNTRACKED$STATUS"
fi
if $(echo "$INDEX" | grep '^A  ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
elif $(echo "$INDEX" | grep '^M  ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
elif $(echo "$INDEX" | grep '^MM ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_ADDED$STATUS"
fi
if $(echo "$INDEX" | grep '^ M ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
elif $(echo "$INDEX" | grep '^AM ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
elif $(echo "$INDEX" | grep '^MM ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
elif $(echo "$INDEX" | grep '^ T ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_MODIFIED$STATUS"
fi
if $(echo "$INDEX" | grep '^R  ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_RENAMED$STATUS"
fi
if $(echo "$INDEX" | grep '^ D ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
elif $(echo "$INDEX" | grep '^D  ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
elif $(echo "$INDEX" | grep '^AD ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_DELETED$STATUS"
fi
if $(command git rev-parse --verify refs/stash >/dev/null 2>&1); then
STATUS="$ZSH_THEME_GIT_PROMPT_STASHED$STATUS"
fi
if $(echo "$INDEX" | grep '^UU ' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_UNMERGED$STATUS"
fi
if $(echo "$INDEX" | grep '^## [^ ]\+ .*ahead' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_AHEAD$STATUS"
fi
if $(echo "$INDEX" | grep '^## [^ ]\+ .*behind' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_BEHIND$STATUS"
fi
if $(echo "$INDEX" | grep '^## [^ ]\+ .*diverged' &> /dev/null); then
STATUS="$ZSH_THEME_GIT_PROMPT_DIVERGED$STATUS"
fi
echo $STATUS
}

虽然我使用 ZSH _ THEME _ GIT _ PROMPT _ MODIFIED 作为未确定的标记,但是您可以选择任何您希望指示的状态,或者在您的情况下实现一个更快的 git_prompt_status函数。

对于任何使用 宇宙飞船主题的人来说,把这个添加到 .zshrc:

SPACESHIP_GIT_STATUS_SHOW="false"

显然,你会在终端提示符中丢失 git 状态。

这个主题的 git 选项可以找到 在这里

编辑

更新链接到 git 选项是 给你

对于那些希望改进 zsh git 延迟的人来说,下面的代码将我的延迟从 40ms减少到了 4ms:

  1. 编译并安装优化的 git-branch-name命令:

    git clone https://github.com/notfed/git-branch-name
    cd git-branch-name
    make
    sudo install git-branch-name /usr/local/bin/
    
  2. 把这个加到你的 ~/.zshrc:

    function git_prompt_info() {
    ref=$(git-branch-name -q -h 12 -b 64) || return
    echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref}${ZSH_THEME_GIT_PROMPT_CLEAN}${ZSH_THEME_GIT_PROMPT_SUFFIX}"
    }
    

(-h-b标志分别控制分支名称和散列的截断长度。)

有了这个,我可以坚持进入,不会经历任何滞后。

我也有同样的问题。我运行以下命令来获得所有没有使用硬编码 git 插件的主题列表:

grep --files-without-match "git" ~/.oh-my-zsh/themes/*

提示语变得更快了,但我不喜欢这些主题中的任何一个。

我最后使用的是 powerline10k,它可以配置成看起来非常漂亮,而且没有速度问题。

我想保持我的 Git 状态,所以其他的答案对我没有帮助。

真正帮助我的是在 git 存储库中运行这个命令,它对我来说很慢:

git gc

它代表垃圾收集,完全解释了 给你,但基本上:

[它]在当前存储库中运行许多内部管理任务,比如压缩文件修订(以减少磁盘空间并提高性能)

运行这个命令之后,就不再加载了,一切都恢复了即时性。

最高解决方案是

git config --add oh-my-zsh.hide-status 1
git config --add oh-my-zsh.hide-dirty 1

可以工作,但是禁用了一些很酷的功能,比如分支名称和脏东西。 对我来说,有效的方法是压缩 git 的数据库,但是使用 aggressive标志:

git gc --aggressive

这是大回购,回购中的回购等情况。我的解决方案(比起更改 Oh My Zsh 的配置,我更喜欢它)是在缓慢的回购中运行 git status