在 Bash 提示符中显示 Git 分支与状态

自定义 Bash 提示符以即时显示 Git 上下文

目录

一个配置良好的显示 git 仓库信息的 bash 提示符可以显著提升你的开发工作流程。

你不需要不断地运行 git statusgit branch 命令,就可以在终端提示符中始终看到这些关键信息。

oh-my-posh

Oh-my-posh 提示符示例。

为什么要在你的 Bash 提示符中添加 Git 信息?

当你一天中使用多个 Git 仓库和分支时,上下文切换会成为显著的生产力损耗。一个具备 Git 意识的提示符可以解决一些常见问题:

  • 防止分支混淆:在提交之前,你始终知道当前在哪个分支上
  • 减少命令开销:不需要不断地运行 git statusgit branch
  • 即时视觉反馈:一目了然地看到未提交的更改、未跟踪的文件和上游状态
  • 减少错误:避免不小心提交到错误的分支或推送脏代码

理解 Bash 的 PS1 变量

Bash 提示符由 PS1 环境变量控制。这个变量可以包含:

  • 文字内容:你想要显示的任何字符
  • 转义序列:以 \ 开头的特殊代码,用于显示动态信息
  • 命令替换$(...) 中的命令,执行并显示其输出
  • ANSI 颜色代码:改变文本颜色的转义序列

常见的 PS1 转义序列包括:

  • \u - 当前用户名
  • \h - 主机名
  • \w - 当前工作目录
  • \$ - # 用于 root 用户,$ 用于普通用户
  • \t - 24 小时格式的当前时间

一个基本的提示符可能如下:PS1='\u@\h:\w\$ ',输出可能像 user@hostname:/path/to/dir$ 。如需更多 Bash 基础知识和转义序列,请查看我们的全面 Bash 命令速查表

方法 1:使用 Git 内置的 git-prompt.sh 脚本

Git 发行版包含一个名为 git-prompt.sh 的辅助脚本,提供 __git_ps1 函数。这是最可靠且功能最丰富的做法。

找到 git-prompt.sh

首先,找到脚本在你系统上的位置:

# Linux 上的常见位置
/usr/share/git-core/contrib/completion/git-prompt.sh
/etc/bash_completion.d/git-prompt
/usr/lib/git-core/git-sh-prompt

# macOS 上的常见位置(使用 Homebrew)
/usr/local/etc/bash_completion.d/git-prompt.sh
/Library/Developer/CommandLineTools/usr/share/git-core/git-prompt.sh

# 如果需要,可以搜索它
find /usr -name git-prompt.sh 2>/dev/null

基本配置

将以下内容添加到你的 ~/.bashrc~/.bash_profile

# 引入 git-prompt 脚本
source /usr/lib/git-core/git-sh-prompt

# 设置提示符以包含 git 信息
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\[\033[01;31m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '

$(__git_ps1 " (%s)") 部分调用该函数,%s 会被当前分支名称替换。周围的空格和括号使其格式更美观。

编辑后,重新加载你的配置:

source ~/.bashrc

git-prompt.sh 的高级选项

通过环境变量启用 git-prompt.sh 的可选功能,可以使其更强大:

# 显示未暂存 (*) 和已暂存 (+) 的更改
export GIT_PS1_SHOWDIRTYSTATE=1

# 显示是否有暂存的更改 ($)
export GIT_PS1_SHOWSTASHSTATE=1

# 显示是否有未跟踪的文件 (%)
export GIT_PS1_SHOWUNTRACKEDFILES=1

# 显示 HEAD 和上游之间的差异
# 选项:auto, verbose, name, legacy, git, svn
export GIT_PS1_SHOWUPSTREAM="auto"

# 启用彩色提示(需要 bash 4.0+)
export GIT_PS1_SHOWCOLORHINTS=1

# 显示操作期间的仓库状态
# (MERGING, REBASING, BISECTING 等)
export GIT_PS1_DESCRIBE_STYLE="default"

这些指示符的含义如下:

  • * - 未暂存的更改(已修改但未添加的文件)
  • + - 已暂存的更改(已添加但未提交的文件)
  • $ - 存在暂存的更改
  • % - 存在未跟踪的文件
  • < - 落后于上游分支
  • > - 超前于上游分支
  • <> - 与上游分支分叉
  • = - 与上游分支相同

完整示例配置

这是一个全面的 ~/.bashrc 配置示例:

# 引入 git-prompt
if [ -f /usr/share/git-core/contrib/completion/git-prompt.sh ]; then
    source /usr/share/git-core/contrib/completion/git-prompt.sh
fi

# 配置 git-prompt 选项
export GIT_PS1_SHOWDIRTYSTATE=1
export GIT_PS1_SHOWSTASHSTATE=1
export GIT_PS1_SHOWUNTRACKEDFILES=1
export GIT_PS1_SHOWUPSTREAM="auto"
export GIT_PS1_SHOWCOLORHINTS=1

# 颜色定义
COLOR_RESET='\[\033[00m\]'
COLOR_USER='\[\033[01;32m\]'      # 绿色
COLOR_PATH='\[\033[01;34m\]'      # 蓝色
COLOR_GIT='\[\033[01;33m\]'       # 黄色

# 设置提示符
PS1="${COLOR_USER}\u@\h${COLOR_RESET}:${COLOR_PATH}\w${COLOR_GIT}"'$(__git_ps1 " (%s)")'"${COLOR_RESET}\$ "

方法 2:手动 Git 命令替换

如果你没有访问 git-prompt.sh 的权限,或者想要一个最小化的解决方案,可以直接在提示符中执行 Git 命令:

# 仅显示分支名称
PS1='\u@\h:\w$(git branch 2>/dev/null | grep "^*" | colrm 1 2 | sed "s/^/ (/;s/$/)/")\$ '

# 显示分支名称和状态指示器
parse_git_dirty() {
    [[ $(git status 2> /dev/null | tail -n1) != "nothing to commit, working tree clean" ]] && echo "*"
}

parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e "s/* \(.*\)/ (\1$(parse_git_dirty))/"
}

PS1='\u@\h:\w\[\033[01;33m\]$(parse_git_branch)\[\033[00m\]\$ '

这种方法更便携,但缺乏 git-prompt.sh 的复杂性,而且在大型仓库中可能较慢。

方法 3:现代提示工具

为了获得更丰富的体验和最少的配置,可以考虑以下现代替代方案:

Starship 提示符

Starship 是一个用 Rust 编写的快速、可定制的提示符,适用于多个 shell(bash、zsh、fish、PowerShell)。

# 安装 Starship
curl -sS https://starship.rs/install.sh | sh

# 添加到 ~/.bashrc
eval "$(starship init bash)"

Starship 会自动检测 Git 仓库并显示:

  • 分支名称
  • 分离状态下的提交哈希
  • 仓库状态(合并、变基等)
  • 修改文件数量
  • 超前/落后上游状态
  • 以及更多可自定义的图标

通过 ~/.config/starship.toml 进行配置:

[git_branch]
symbol = "🌱 "
format = "on [$symbol$branch]($style) "

[git_status]
conflicted = "🏳"
ahead = "⇡${count}"
behind = "⇣${count}"
diverged = "⇕⇡${ahead_count}⇣${behind_count}"
untracked = "🤷"
stashed = "📦"
modified = "📝"
staged = '[++\($count\)](green)'
renamed = "👅"
deleted = "🗑"

Oh My Bash

Oh My Bash 是一个用于管理 bash 配置的框架,包含主题和插件:

# 安装 Oh My Bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmybash/oh-my-bash/master/tools/install.sh)"

# 编辑 ~/.bashrc 以设置主题
OSH_THEME="powerline"

许多 Oh My Bash 主题默认包含 Git 集成。

Oh My Posh

Oh My Posh 是一个现代、跨平台的提示引擎,适用于 bash、zsh、PowerShell 和其他 shell。它提供美观、可定制的提示,具有出色的 Git 集成,并使用 Nerd Fonts 以支持图标。

在 Linux 上安装

使用单个命令安装 Oh My Posh:

# 安装到 ~/bin 或 ~/.local/bin(默认)
curl -s https://ohmyposh.dev/install.sh | bash -s

# 或指定自定义安装目录
curl -s https://ohmyposh.dev/install.sh | bash -s -- -d ~/bin

基本设置

将 Oh My Posh 添加到你的 ~/.bashrc

# 使用主题初始化 Oh My Posh
eval "$(oh-my-posh init bash --config ~/.poshthemes/jandedobbeleier.omp.json)"

安装和使用主题

Oh My Posh 包含许多预构建的主题。首先下载它们:

# 创建主题目录
mkdir ~/.poshthemes

# 下载所有主题
curl -s https://ohmyposh.dev/themes.json | \
  jq -r '.[] | .url' | \
  xargs -I {} sh -c 'curl -s {} -o ~/.poshthemes/$(basename {})'

流行的主题包括:

  • jandedobbeleer.omp.json - 创建者个人主题,具有完整的 Git 集成
  • powerline.omp.json - 经典 powerline 风格
  • atomic.omp.json - 简约,包含基本信息
  • night-owl.omp.json - 颜色丰富的主题,包含详细的 Git 信息

通过更改配置路径来切换主题:

eval "$(oh-my-posh init bash --config ~/.poshthemes/atomic.omp.json)"

Git 功能

Oh My Posh 自动显示全面的 Git 信息:

  • 当前分支名称
  • 提交数超前/落后远程
  • 工作目录状态(干净/脏)
  • 暂存数量
  • 合并/变基状态
  • 标签信息
  • 分离 HEAD 状态下的提交哈希

自定义配置

通过复制现有主题创建自定义主题:

# 复制一个主题作为起点
cp ~/.poshthemes/jandedobbeleer.omp.json ~/.mytheme.omp.json

# 编辑你的主题
nano ~/.mytheme.omp.json

# 使用你的自定义主题
eval "$(oh-my-posh init bash --config ~/.mytheme.omp.json)"

Git 段的示例 JSON 配置:

{
  "type": "git",
  "style": "powerline",
  "powerline_symbol": "",
  "foreground": "#193549",
  "background": "#fffb38",
  "background_templates": [
    "{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}",
    "{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}",
    "{{ if gt .Ahead 0 }}#B388FF{{ end }}",
    "{{ if gt .Behind 0 }}#B388FF{{ end }}"
  ],
  "properties": {
    "fetch_status": true,
    "fetch_upstream_icon": true,
    "branch_icon": " ",
    "branch_max_length": 25,
    "truncate_symbol": "…"
  }
}

字体要求

Oh My Posh 最佳搭配 Nerd Fonts 以支持图标:

# 下载并安装一个 Nerd Font(示例:FiraCode)
mkdir -p ~/.local/share/fonts
cd ~/.local/share/fonts
curl -fLo "FiraCode Nerd Font.ttf" \
  https://github.com/ryanoasis/nerd-fonts/raw/HEAD/patched-fonts/FiraCode/Regular/FiraCodeNerdFont-Regular.ttf
fc-cache -fv

然后配置终端使用 Nerd Font。

Oh My Posh 的优势

  • 跨平台:Linux、macOS 和 Windows 上的配置相同
  • 快速:用 Go 编写,性能高
  • 可扩展:Git、时间、路径、语言、云提供商等模块化段
  • 丰富的主题:大量预制作主题
  • 活跃开发:定期更新和改进
  • 终端无关:适用于任何 ANSI 兼容终端

Bash-git-prompt

一个专注于 Git 信息的专用 Bash 提示符工具:

# 克隆仓库
git clone https://github.com/magicmonty/bash-git-prompt.git ~/.bash-git-prompt --depth=1

# 添加到 ~/.bashrc
if [ -f "$HOME/.bash-git-prompt/gitprompt.sh" ]; then
    GIT_PROMPT_ONLY_IN_REPO=1
    source $HOME/.bash-git-prompt/gitprompt.sh
fi

大型仓库中的性能考虑

Git 状态操作在大型仓库中可能很慢。以下是优化策略:

选择性禁用昂贵功能

# 在 .bashrc 中,根据仓库大小条件性禁用功能
if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
    repo_size=$(du -sh .git 2>/dev/null | cut -f1)
    # 对于超过 100MB 的仓库禁用脏状态检查
    if [[ "$repo_size" =~ ^[0-9]+M$ ]] && [ "${repo_size%M}" -gt 100 ]; then
        export GIT_PS1_SHOWDIRTYSTATE=0
    fi
fi

使用 Git 配置选项

配置 Git 以优化状态检查:

# 启用文件系统监控以加快状态检查
git config core.fsmonitor true
git config core.untrackedCache true

# 对于非常大的仓库,考虑部分克隆
git config core.commitGraph true
git config gc.writeCommitGraph true

替代方案:异步提示符

Starship 等工具使用异步操作以防止提示符延迟。提示符在获取 Git 信息后更新,而不是阻塞。

常见问题排查

提示符未显示 Git 信息

  1. 验证 git-prompt.sh 是否已加载:在终端中运行 type __git_ps1。如果显示“未找到”,则脚本未加载。
  2. 检查文件权限:确保 git-prompt.sh 可读:ls -l /path/to/git-prompt.sh
  3. 验证你是否在 Git 仓库中:运行 git status 以确认
  4. 检查 PS1 语法:确保包含 $(__git_ps1) 并正确引用

颜色未显示

  1. 转义序列问题:PS1 中的颜色必须用 \[ \] 包裹以防止换行问题
  2. 终端支持:验证终端是否支持 ANSI 颜色:echo -e "\033[31mRed Text\033[0m"
  3. 重置代码:始终用重置代码 \033[00m 结束颜色序列

提示符破坏换行

使用颜色时,非打印转义序列必须用 \[\] 包裹:

# 错误 - 导致换行问题
PS1="\033[32m\u\033[00m\$ "

# 正确
PS1="\[\033[32m\]\u\[\033[00m\]\$ "

WSL 或网络驱动器上的提示符缓慢

在 Windows 网络共享或 WSL 上的 Git 操作可能很慢:

# 在慢文件系统上禁用昂贵的 git-prompt 功能
export GIT_PS1_SHOWDIRTYSTATE=0
export GIT_PS1_SHOWUNTRACKEDFILES=0

考虑使用原生 Windows Git bash 而不是 WSL 来处理 Windows 驱动器上的仓库。

与开发工作流程的集成

具备 Git 意识的提示符与其他 shell 增强功能结合时会更强大:

Git 别名用于快速导航

将增强的提示符与有用的 Git 别名结合以最大化效率。如需全面的 Git 命令和快捷方式列表,请查看我们的 Git 命令速查表

# 添加到 ~/.gitconfig 或 ~/.bashrc
alias gs='git status'
alias gb='git branch'
alias gc='git checkout'
alias gp='git pull'
alias gpu='git push'

条件提示符行为

# 不同状态使用不同颜色的提示符
__git_ps1_colorize() {
    local git_status="$(git status 2>/dev/null)"
    if [[ $git_status =~ "nothing to commit" ]]; then
        echo -e "\[\033[32m\]"  # 清洁时使用绿色
    else
        echo -e "\[\033[31m\]"  # 脏时使用红色
    fi
}

PS1='\u@\h:\w$(__git_ps1_colorize)$(__git_ps1 " (%s)")\[\033[00m\]\$ '

终端标题栏集成

用仓库信息更新终端标题栏:

PROMPT_COMMAND='echo -ne "\033]0;${PWD##*/}$(__git_ps1 " [%s]")\007"'

最佳实践和建议

  1. 保持可读性:不要在提示符中塞入太多信息
  2. 战略性使用颜色:用不同颜色表示不同状态(清洁 vs 脏)
  3. 在多种场景中测试:验证提示符在普通目录、Git 仓库和 Git 操作期间都能正常工作
  4. 记录你的配置:在 .bashrc 中添加注释,以便你记住每个部分的作用
  5. 备份你的配置:将你的 dotfiles 版本控制在 Git 仓库中。如果你运行自己的 Git 服务器,你可能想探索 Gitea 服务器安装 作为一个轻量级的自托管选项
  6. 考虑你的工作流程:仅启用你实际需要的功能
  7. 尽可能使用现代工具:Starship 和类似工具经过良好测试且性能良好

关于自托管 Git 解决方案,学习 Gitea 备份和恢复 以确保你的仓库受到保护。如果你对自动化 Git 工作流程感兴趣,请查看我们的 GitHub Actions 速查表 以获得全面的 CI/CD 自动化。

有用链接

其他有用文章