无OhMyZsh环境下zsh的Git相关功能响应缓慢问题排查
Zsh在Git目录下的性能异常排查与解决
问题描述
- 仅在Git目录中,提示符加载缓慢;
- Tab自动补全变慢,例如执行
git checkout some-bra[tab]耗时远超以往。
推测原因
此前使用git switch拉取过一个未合并的远程分支,虽已删除本地分支,但所有Git仓库内zsh仍卡顿,推测zsh在构建提示符或处理自动补全时会检查远程Git内容。
用户配置信息
~/.zshrc相关配置片段
__git_files () { _wanted files expl 'local files' _files } autoload -Uz vcs_info precmd() { vcs_info } zstyle ':vcs_info:git:*' formats '(%b)' zstyle ':vcs_info:*' enable git zstyle ':vcs_info:*' check-for-changes true zstyle ':vcs_info:*' unstagedstr ' *' zstyle ':vcs_info:*' stagedstr ' +' zstyle ':vcs_info:git:*' formats '(%b%u%c)' zstyle ':vcs_info:git:*' actionformats '(%b|%a%u%c)' function git_branch_name() { branch=$(git symbolic-ref HEAD 2> /dev/null | awk 'BEGIN{FS="/"} {print $NF}') if [[ $branch == "" ]]; then : else echo '- ('$branch')' fi } setopt prompt_subst PROMPT=$' %F{white}\u256d %~ ${vcs_info_msg_0_} \u2570 %# %f' setopt auto_cd autoload -U compinit; compinit # zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' # 0 -- vanilla completion (abc => abc) # 1 -- smart case completion (abc => Abc) # 2 -- word flex completion (abc => A-big-Car) # 3 -- full flex completion (abc => ABraCadabra) zstyle ':completion:*' matcher-list '' \ 'm:{a-z\-}={A-Z\_}' \ 'r:[^[:alpha:]]||[[:alpha:]]=** r:|=* m:{a-z\-}={A-Z\_}' \ 'r:|?=** m:{a-z\-}={A-Z\_}'
~/.zshrc完整配置
if [[ "$ZPROF" = true ]]; then zmodload zsh/zprof fi # printf '\n%.0s' {1..100} # If you come from bash you might have to change your $PATH. # export PATH=$HOME/bin:/usr/local/bin:$PATH export PATH=$PATH:$HOME/custom-git-commands/ export MANPAGER="vim -M +MANPAGER -c 'syntax off' -c 'set foldlevel=9999' -c 'set number relativenumber' -\" plugins=(git wd zshmarks) export ZSH_COMPDUMP=$ZSH/cache/.zcompdump-$HOST # User configuration # Compilation flags # export ARCHFLAGS="-arch x86_64" # Set personal aliases, overriding those provided by oh-my-zsh libs, # plugins, and themes. Aliases can be placed here, though oh-my-zsh # users are encouraged to define aliases within the ZSH_CUSTOM folder. # For a full list of active aliases, run `alias`. # # Example aliases # alias zshconfig="mate ~/.zshrc" HISTSIZE=5000 HISTFILE=~/.zsh_history SAVEHIST=5000 HISTDUP=erase setopt appendhistory setopt sharehistory setopt incappendhistory setopt hist_ignore_all_dups setopt hist_save_no_dups setopt hist_ignore_dups setopt hist_find_no_dups # uses homebrew-installed GNU coreutils' ls alias ls='gls --group-directories-first -F -a --color=never' alias gm="jump" alias sm="bookmark" alias dm="deletemark" alias pm="showmarks" alias chrome="open -a 'Google Chrome'" alias copypath="pwd|pbcopy" alias python="python3" function chpwd_do_ls () { ls } chpwd_functions=( chpwd_do_ls ) declare -a SCOLDS SCOLDS=( "Everything is an instruction." "Remember the scream test." "rm is a dangerous command." "Read the error message." "Read the docs." "Generally, not trying too hard will result in good enough code." ) alias clear='echo ${SCOLDS[ $RANDOM % ${#SCOLDS[@]} + 1 ]}' alias c='clear' alias vimz='vim ~/.zshrc' alias vimv='vim ~/.vimrc' alias sc='source ~/.zshrc' alias ez='exec zsh' alias ..='cd ..' alias confgit='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME' alias ga='git add .' alias gcm='git commit -m' alias grao='git remote add origin' alias gp='git push' alias gst='git status' alias gpuo='git push --set-upstream origin' alias glo='git log --oneline' alias gvl='git vlog' alias gvd='git vdiff' alias grb='git rebase' alias gcb='git checkout -b' alias gco='git checkout' precmd() { print "" } __git_files () { _wanted files expl 'local files' _files } autoload -Uz vcs_info precmd() { vcs_info } zstyle ':vcs_info:git:*' formats '(%b)' zstyle ':vcs_info:*' enable git zstyle ':vcs_info:*' check-for-changes true zstyle ':vcs_info:*' unstagedstr ' *' zstyle ':vcs_info:*' stagedstr ' +' zstyle ':vcs_info:git:*' formats '(%b%u%c)' zstyle ':vcs_info:git:*' actionformats '(%b|%a%u%c)' function git_branch_name() { branch=$(git symbolic-ref HEAD 2> /dev/null | awk 'BEGIN{FS="/"} {print $NF}') if [[ $branch == "" ]]; then : else echo '- ('$branch')' fi } setopt prompt_subst PROMPT=$' %F{white}\u256d %~ ${vcs_info_msg_0_} \u2570 %# %f' setopt auto_cd autoload -U compinit; compinit # zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' # 0 -- vanilla completion (abc => abc) # 1 -- smart case completion (abc => Abc) # 2 -- word flex completion (abc => A-big-Car) # 3 -- full flex completion (abc => ABraCadabra) zstyle ':completion:*' matcher-list '' \ 'm:{a-z\-}={A-Z\_}' \ 'r:[^[:alpha:]]||[[:alpha:]]=** r:|=* m:{a-z\-}={A-Z\_}' \ 'r:|?=** m:{a-z\-}={A-Z\_}' timezsh() { shell=${1-$SHELL} for i in $(seq 1 10); do /usr/bin/time $shell -i -c exit; done } profzsh() { shell=${1-$SHELL} ZPROF=true $shell -i -c exit } if [[ "$ZPROF" = true ]]; then zprof fi
解决方案
1. 清理Git远程分支缓存
执行以下命令清理本地无效的远程分支引用与Git缓存:
git fetch --prune git gc --prune=now
2. 优化vcs_info性能
关闭check-for-changes以减少提示符渲染时的文件变更检查开销:
zstyle ':vcs_info:*' check-for-changes false
3. 修复precmd重复定义问题
合并两次定义的precmd()函数,避免逻辑覆盖:
precmd() { print "" vcs_info }
4. 优化Git补全策略
限制git分支补全仅考虑本地分支,减少远程查询开销:
zstyle ':completion:*:git-checkout:*' sort false zstyle ':completion:*:git-checkout:*' tag-order branches tags
5. 重新生成补全缓存
执行命令更新zsh补全缓存:
compinit -i
6. 定位性能瓶颈
使用配置中的profzsh函数分析zsh执行耗时,确认优化效果:
profzsh
内容的提问来源于stack exchange,提问作者Aaron Parisi
相关产品推荐
相关产品推荐

