Bash 和 Zsh 提示的 Git 状态
gitstatus is a 10x faster alternative to git status and git describe. Its primary use
case is to enable fast git prompt in interactive shells.
Heavy lifting is done by gitstatusd -- a custom binary written in C++. It comes with Zsh and Bash bindings for integration with shell.
The easiest way to take advantage of gitstatus from Zsh is to use a theme that's already integrated with it. For example, Powerlevel10k is a flexible and fast theme with first-class gitstatus integration. If you install Powerlevel10k, you don't need to install gitstatus.
For those who wish to use gitstatus without a theme, there is gitstatus.prompt.zsh. Install it as follows:
git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc
Users in China can use the official mirror on gitee.com for faster download.
中国大陆用户可以使用 gitee.com 上的官方镜像加速下载.
git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc
Alternatively, if you have Homebrew installed:
brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.zsh" >>! ~/.zshrc
(If you choose this option, replace ~/gitstatus with $(brew --prefix)/opt/gitstatus/gitstatus
in all code snippets below.)
Make sure to disable your current theme if you have one.
This will give you a basic yet functional prompt with git status in it. It's
over 10x faster than any alternative that can give you comparable prompt. In order
to customize it, set PROMPT and/or RPROMPT at the end of ~/.zshrc after sourcing
gitstatus.prompt.zsh. Insert ${GITSTATUS_PROMPT} where you want git status to go. For example:
source ~/gitstatus/gitstatus.prompt.zsh
PROMPT='%~%# ' # left prompt: directory followed by %/# (normal/root)
RPROMPT='$GITSTATUS_PROMPT' # right prompt: git status
The expansion of ${GITSTATUS_PROMPT} can contain the following bits:
| segment | meaning |
|---|---|
master |
current branch |
#v1 |
HEAD is tagged with v1; not shown when on a branch |
@5fc6fca4 |
current commit; not shown when on a branch or tag |
⇣1 |
local branch is behind the remote by 1 commit |
⇡2 |
local branch is ahead of the remote by 2 commits |
⇠3 |
local branch is behind the push remote by 3 commits |
⇢4 |
local branch is ahead of the push remote by 4 commits |
*5 |
there are 5 stashes |
merge |
merge is in progress (could be some other action) |
~6 |
there are 6 merge conflicts |
+7 |
there are 7 staged changes |
!8 |
there are 8 unstaged changes |
?9 |
there are 9 untracked files |
$GITSTATUS_PROMPT_LEN tells you how long $GITSTATUS_PROMPT is when printed to the console.
gitstatus.prompt.zsh has an example of using it to truncate the current
directory.
If you'd like to change the format of git status, or want to have greater control over the
process of assembling PROMPT, you can copy and modify parts of
gitstatus.prompt.zsh instead of sourcing the script. Your ~/.zshrc
might look something like this:
…
This snippet is sourcing gitstatus.plugin.zsh rather than gitstatus.prompt.zsh. The former
defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple
script that uses these bindings to assemble git prompt.
Unlike Powerlevel10k, code based on
gitstatus.prompt.zsh is communicating with gitstatusd synchronously. This
can make your prompt slow when working in a large git repository or on a slow machine. To avoid
this problem, call gitstatus_query asynchronously as documented in
gitstatus.plugin.zsh. This can be quite challenging.
The easiest way to take advantage of gitstatus from Bash is via gitstatus.prompt.sh. Install it as follows:
git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc
Users in China can use the official mirror on gitee.com for faster download.
中国大陆用户可以使用 gitee.com 上的官方镜像加速下载.
git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc
Alternatively, if you have Homebrew installed:
brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.sh" >> ~/.bashrc
(If you choose this option, replace ~/gitstatus with $(brew --prefix)/opt/gitstatus/gitstatus
in all code snippets below.)
This will give you a basic yet functional prompt with git status in it. It's over 10x faster than any alternative that can give you comparable prompt.
In order to customize your prompt, set PS1 at the end of ~/.bashrc after sourcing
gitstatus.prompt.sh. Insert ${GITSTATUS_PROMPT} where you want git status to go. For example:
source ~/gitstatus/gitstatus.prompt.sh
PS1='\w ${GITSTATUS_PROMPT}\n\$ ' # directory followed by git status and $/# (normal/root)
The expansion of ${GITSTATUS_PROMPT} can contain the following bits:
| segment | meaning |
|---|---|
master |
current branch |
#v1 |
HEAD is tagged with v1; not shown when on a branch |
@5fc6fca4 |
current commit; not shown when on a branch or tag |
⇣1 |
local branch is behind the remote by 1 commit |
⇡2 |
local branch is ahead of the remote by 2 commits |
⇠3 |
local branch is behind the push remote by 3 commits |
⇢4 |
local branch is ahead of the push remote by 4 commits |
*5 |
there are 5 stashes |
merge |
merge is in progress (could be some other action) |
~6 |
there are 6 merge conflicts |
+7 |
there are 7 staged changes |
!8 |
there are 8 unstaged changes |
?9 |
there are 9 untracked files |
If you'd like to change the format of git status, or want to have greater control over the
process of assembling PS1, you can copy and modify parts of
gitstatus.prompt.sh instead of sourcing the script. Your ~/.bashrc might
look something like this:
…
This snippet is sourcing gitstatus.plugin.sh rather than gitstatus.prompt.sh. The former
defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple
script that uses these bindings to assemble git prompt.
Note: Bash bindings, unlike Zsh bindings, don't support asynchronous calls.
If there are no gitstatusd bindings for your shell, you'll need to get your hands dirty.
Use the existing bindings for inspiration; run gitstatusd --help or read the same thing in
options.cc.
gitstatusd reads requests from stdin and prints responses to stdout. Requests contain an ID and a directory. Responses contain the same ID and machine-readable git status for the directory. gitstatusd keeps some state in memory for the directories it has seen in order to serve future requests faster.
Zsh bindings and Bash bindings start gitstatusd in
the background and communicate with it via pipes. Themes such as
Powerlevel10k use these bindings to put git status in
PROMPT.
Note that gitstatus cannot be used as a drop-in replacement for git status command as it doesn't
produce output in the same format. It does perform the same computation though.
The following benchmark results were obtained on Intel i9-7900X running Ubuntu 18.04 in
a clean chromium repository synced to 9394e49a. The
repository was checked out to an ext4 filesystem on M.2 SSD.
Three functionally equivalent tools for computing git status were benchmarked:
gitstatusdgit with core.untrackedcache enabled and core.fsmonitor disabledlg2 -- a demo/example executable from libgit2 that
implements a subset of git functionality on top of libgit2 API; for the purposes of this
benchmark the subset is sufficient to generate the same data as the other toolsEvery tool was benchmark in cold and hot conditions. For git the first run in a repository was
considered cold, with the following runs considered hot. lg2 was patched to compute results twice
in a single invocation without freeing the repository in between; the second run was considered hot.
The same patching was not done for git because git cannot be easily modified to refresh inmemory
index state between invocations; in fact, this limitation is one of the primary reasons developers
use libgit2. gitstatusd was benchmarked similarly to lg2 with two result computations in the
same invocation.
Two commands were benchmarked: status and describe.
In this benchmark all tools were computing the equivalent of git status. Lower numbers are better.
| Tool | Cold | Hot |
|---|---|---|
| gitstatus | 291 ms | 30.9 ms |
| git | 876 ms | 295 ms |
| lg2 | 1730 ms | 1310 ms |
gitstatusd is substantially faster than the alternatives, especially on hot runs. Note that hot runs are of primary importance to the main use case of gitstatus in interactive shells.
The performance of git status fluctuated wildly in this benchmarks for reasons unknown to the
author. Moreover, performance is sticky -- once git status settles around a number, it stays
there for a long time. Numbers as diverse as 295, 352, 663 and 730 had been observed on hot runs on
the same repository. The number in the table is the lowest (fastest or best) that git status had
shown.
In this benchmark all tools were computing the equivalent of git describe --tags --exact-match
to find tags that resolve to the same commit as HEAD. Lower numbers are better.
| Tool | Cold | Hot |
|---|---|---|
| gitstatus | 4.04 ms | 0.0345 ms |
| git | 18.0 ms | 14.5 ms |
| lg2 | 185 ms | 45.2 ms |
gitstatusd is once again faster than the alternatives, more so on hot runs.
Since gitstatusd doesn't have to print all staged/unstaged/untracked files but only report whether there are any, it can terminate repository scan early. It can also remember which files were di
暂无开放 Issues,或尚未同步最近议题。