PowerShell 中 Prompt 显示 Git 分支

PowerShell 的 Prompt 中显示 Git 分支已经有非常成熟的解决方案 — posh-git ,脚本写得非常严谨,但是使用 posh-git 首先需要忍受其加载时间,如果在 PowerShell 的 profile 文件中加载往往需要 5 秒左右,对于一个强迫症患者是无法忍受的,所以可以通过 lazy load 的方式来加载 posh-git module,如下面的脚本所示

function git_prompt {
  if (-not $(Get-InstalledModule -Name "posh-git")) {
    Install-Module posh-git -Scope CurrentUser -Force
  }
  if (-not (Get-Module -Name "posh-git")) {
    Import-Module -Name posh-git -Scope Global
  }
  else {
    $GitPromptSettings.EnablePromptStatus = -not $GitPromptSettings.EnablePromptStatus
  }
}

使用 posh-git 面临的第二个挑战是执行时间。我们知道 PowerShell 环境下修改 prompt 是通过 Override 内置函数 prompt 来实现的,posh-git 也是同样的原理,所以我们使用类似 Unix Shell 中 time 命令的 Measure-Command 来验证一下 posh-git 中 prompt 函数的执行时间,执行的截图如下所示。

在这里插入图片描述
可能是我实验的 Repo 有点大,prompt 函数的执行时间确实非常感人,可以达到 221 毫秒,这个延迟足以让人误以为 CPU 是不是 100% 了而感到心慌。所以抱着节约生命不瞎折腾的心态坚持使用了 posh-git 一年后,我还是决定自己造个轻便一点的小轮子,也就有了下文。


参考 Bash 和 Zsh 环境 Prompt 显示 Git 分支 的思路,通过判断 .git/HEAD 文件内容来决定是否重新计算 branch 的方式来优化 prompt 执行时间,脚本参考如下。

function git_branch_internal {
  $dir = $PWD.Path
  do {
    if (Test-Path "${dir}/.git/HEAD") {
      $head = Get-Content "${dir}/.git/HEAD"
      if ($head -eq $Global:GIT_NAME_HEAD) {
        return
      }
      $Global:GIT_NAME_HEAD = $head
      if ($head -match "^ref\:\ refs\/heads\/(?<branch>.*)") {
        $Global:GIT_NAME_TITLE = "branch"
        $Global:GIT_NAME_CONTENT = $Matches.branch
      }
      else {
        $describe = $(git describe --tags --abbrev=7 2> $null)
        if ($describe) {
          $Global:GIT_NAME_TITLE = "tag"
          $Global:GIT_NAME_CONTENT = $describe
        }
        else {
          $Global:GIT_NAME_TITLE = "commit"
          $Global:GIT_NAME_CONTENT = $head.Substring(0, 7)
        }
      }
      $Global:GIT_NAME_LEFT = ":["
      $Global:GIT_NAME_RIGHT = "]"
      "$Global:GIT_NAME_TITLE$Global:GIT_NAME_LEFT$Global:GIT_NAME_CONTENT$Global:GIT_NAME_RIGHT" | Out-Null
      return
    }
    ${dir} = Split-Path -Parent -Path "${dir}"
  } while (${dir})

  $Global:GIT_NAME_TITLE = ""
  $Global:GIT_NAME_CONTENT = ""
  $Global:GIT_NAME_LEFT = ""
  $Global:GIT_NAME_RIGHT = ""
  $Global:GIT_NAME_HEAD = ""
}

function prompt_custom {
  git_branch_internal
  Write-Host $(prompt_bak) -NoNewline
  Write-Host ${GIT_NAME_TITLE}${GIT_NAME_LEFT} -ForegroundColor Cyan -NoNewline
  Write-Host ${GIT_NAME_CONTENT} -ForegroundColor Yellow -NoNewline
  Write-Host ${GIT_NAME_RIGHT}">" -ForegroundColor Cyan -NoNewline
  # Prompt function requires a return, otherwise defaults to factory prompt
  return " "
}

function git_prompt {
  if (Get-Command prompt_bak -errorAction SilentlyContinue) {
    Copy-Item Function::Global:prompt_bak Function::Global:prompt
    Remove-Item Function::prompt_bak
    $Global:GIT_NAME_HEAD = ""; "$Global:GIT_NAME_HEAD" | Out-Null
  }
  else {
    Copy-Item Function::Global:prompt Function::Global:prompt_bak
    Copy-Item Function::Global:prompt_custom Function::Global:prompt
  }
}

修改后使用 Measure-Command 测试了一下 prompt 函数的执行时间,截图如下。

在这里插入图片描述
可以看到,prompt 函数的执行时间从百毫秒级降到了毫秒级,经验证可以同时支持 MacOS/Linux/Windows 系统下的 Powershell 运行环境。


参考文档

  1. Microsoft Docs / PowerShell / Scripting / About Prompts
  2. Tutorial: Set up Powerline in Windows Terminal
  3. A1.8 Appendix A: Git in Other Environments - Git in PowerShell
  4. how-can-i-display-my-current-git-branch-name-in-my-powershell-prompt
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值