在 Nix 下配置 Git Shell 提示符
原文由 Michael Lynch 于 发布,订阅该博客
最近我读了 Julia Evans 的关于 git 的最新一期 zine,其中有一个小技巧是将终端 shell 提示符配置为显示 git 状态。
Julia 的终端提示符是这样的:
main 是 Julia 当前所在的 git 分支。当她正在执行 bisect 或 merge 这类 git 操作时,终端会变成这样:
我以前从没想过要自定义 shell 提示符,但立刻就意识到了它的价值。
我经常要运行 git status 来确认自己在哪个分支上,而且也经常忘记自己正处于 git 合并的中途。
在终端中设置 git 提示符
Julia 的 zine 说服了我把终端 shell 自定义为显示 git 状态,但具体怎么做却不太清楚。看起来,我需要一个叫 git-prompt.sh 的文件,但在我安装了 git 2.30.2 的 Debian 系统上却找不到它:
$ find / -name 'git-prompt.sh' -type f -print
# No results另一个办法是从 GitHub 下载一份官方的 git-prompt.sh:
# Download git-prompt.sh
curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > ~/.git-prompt.sh
# Add it to my .bashrc
echo '. ~/.git-prompt.sh' >> ~/.bashrc
# Reload .bashrc
. ~/.bashrc为了测试它是否生效,我创建了一个临时的 git 仓库:
mkdir examplerepo && \
cd examplerepo && \
git init如果 git-prompt.sh 正常工作,__git_ps1 命令应该会显示当前的 git 分支:
$ __git_ps1
(master)太好了,生效了。
但我不想每次都手动调用 __git_ps1——我想像 Julia Evans 演示的那样,让分支自动出现在终端提示符里。
在终端 shell 中显示 git 状态最简单的方法,就是在 bash 会话中重写 PS1 变量:
$ export PS1='$(__git_ps1 "(%s)") \$ '
(master) $现在,当我执行 git 命令时,终端会随之变化以反映当前状态:
(master) $ echo 'hi' > hello.txt && git add -A && git commit -m "Test commit"
[master (root-commit) 7b14d2a] Test commit
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
(master) $ git checkout -b branchA && echo 'hey' > hello.txt && git add -A && git commit -m "test A"
Switched to a new branch 'branchA'
[branchA 65b3d63] test A
1 file changed, 1 insertion(+), 1 deletion(-)
(branchA) $ git checkout master
Switched to branch 'master'
(master) $ git checkout -b branchB && echo 'hello' > hello.txt && git add -A && git commit -m "test B"
Switched to a new branch 'branchB'
[branchB 198c875] test B
1 file changed, 1 insertion(+), 1 deletion(-)
(branchB) $ git merge branchA
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.
(branchB|MERGING) $不错,看起来是生效了。
但这样一来,shell 提示符里就看不到当前工作目录了,于是我把 PS1 改成了这样:
$ export PS1='\w $(__git_ps1 "(%s)") \$ '
~/examplerepo (branchB|MERGING) $我还想让提示符带上好看的颜色,于是也加上了:
export PS1='\[\033[01;34m\]\w\[\033[00m\]\[\033[01;32m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '到了这一步,编辑 PS1 已经变得相当复杂了,我建议使用Bash Prompt Generator这类免费工具来帮你生成命令并自动加上颜色。
这是我的最终终端提示符效果:
为了让这个改动永久生效,我把那行 export PS1 加到了 ~/.bashrc 文件中,这样每次启动新的 bash shell 时都会使用我自定义的终端提示符。
在 Nix 上把 git 集成到 bash shell 提示符中
上面这些步骤的问题在于,我使用的是Nix和Home Manager,它们虽然很好用,却让 bash 配置的方方面面都变得更复杂了。我不能简单地往 .bashrc 里加一行,因为下次运行 Home Manager 时,它会把我的改动覆盖掉。
幸运的是,Jeff Kreeftmeijer 的这篇文章帮我搞清楚了如何把 git-prompt.sh 的方案适配到 Nix 上。
我在 Home Manager 的 home.nix 文件中做了如下修改:
programs.bash = {
enable = true;
enableCompletion = true;
initExtra = ''
# Load __git_ps1 bash command.
. ~/.nix-profile/share/git/contrib/completion/git-prompt.sh
# Also load git command completions for bash.
. ~/.nix-profile/share/git/contrib/completion/git-completion.bash
# Show git branch status in terminal shell.
export PS1='\[\033[01;34m\]\w\[\033[00m\]\[\033[01;32m\]$(__git_ps1 " (%s)")\[\033[00m\]\$ '
'';
};更新完文件后,我运行了 home-manager switch,它更新了我的 .bashrc,一切都按预期工作了。
清理开发环境中 Nix 终端的多余信息
不过,我自定义的 bash 终端提示符还有最后一个小问题。
我所有的开发工作都是在按项目隔离的 Nix shell中进行的。当我运行 nix develop 来加载开发环境时,发现 Nix 在我的终端前额外加了一段前缀:
~/examplerepo (branchB|MERGING) $ nix develop
...
(nix:nix-shell-env) ~/examplerepo (branchB|MERGING) $
^^^^^^^^^^^^^^^^^^^ why?这个前缀占了很大一块地方。现在的终端提示符几乎有一半只是在告诉我正处于 Nix 环境中。
在某些项目中,Nix 的 shell 提示符前缀甚至更长。这是我在PicoShare中看到的情况:
~/examplerepo (branchB|MERGING) $ nix develop
...
(nix:nix-shell-x86_64-unknown-linux-musl-env) ~/picoshare (master)$
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ too much!这个 shell 前缀占用了大量屏幕空间。怎么才能去掉它呢?
原来 nix develop 有一个 --bash-prompt-prefix 参数,可以让我像这样自定义终端 shell 前缀:
$ nix develop --bash-prompt-prefix 'nix:'
nix:~/picoshare (master)$如果完全不想要前缀,也可以把它设为空字符串:
$ nix develop --bash-prompt-prefix ''
~/picoshare (master)$但显然,我不想每次运行 nix develop 时都额外加上这个命令行参数。
我发现这些多余信息其实来自我的 nix.conf 文件,在我的 Debian 系统上它位于 /etc/nix/nix.conf。我猜这个前缀是Determinate Systems Nix installer帮我设置的:
$ grep 'bash-prompt-prefix' /etc/nix/nix.conf
bash-prompt-prefix = (nix:$name)我把那一行改成了更简洁的 nix: 前缀:
bash-prompt-prefix = nix:然后,我重启了 Nix 以使改动生效:
sudo systemctl restart nix-daemon现在,当我处于 Nix 开发环境中时,会看到这样一个简短而有用的前缀:
总结
在进行软件开发时,自定义终端 shell、让每个 shell 提示符都能显示所在目录的 git 状态,会很有帮助。
希望这篇文章能帮助那些想在普通 bash 系统,以及由 Nix 和 Home Manager 管理 bash 配置的系统上实现类似配置的人。
随机一篇博客
评论
登录后参与讨论