Maybe you have a big ol' monorepo, and git
operations are pretty slow in it. For those of us who like to show information about the repository's dirty status in our prompt, that means a slow prompt. Waiting 1s every time you hit the return
key can really add up! Instead of just giving up and eschewing the dirty status entirely, why not just cache it in the background have your prompt read from the cache?
First, install fswatch
:
brew install fswatch
Also, if your monorepo doesn't come with a tmp/
or log/
directory, quickly create those first just in case:
cd /path/to/monorepo
mkdir -p tmp
mkdir -p log
Copy the contents of watch-for-git-changes
script and install it in /usr/local/bin
:
pbpaste > /usr/local/bin/watch-for-git-changes
chmod +x /usr/local/bin/watch-for-git-changes
Then, copy the contents of the plist and install it in your LaunchAgents directory:
pbpaste > ~/Library/LaunchAgents/com.$USER.update-monorepo-git-dirty.plist
Replace any instances of USER
with your system username, and replace /path/to/monorepo
with... well... the path to your monorepo.
Finally, load the launchagent so it starts running:
launchctl load ~/Library/LaunchAgents/com.$USER.update-pay-server-git-dirty.plist
To verify that it's running correctly, check its status:
launchctl list | grep "com.$USER"
If it's actually running and hasn't exited, the first value will be a PID instead of empty. Try modifying a file in the your monorepo that's tracked by git. After you do so, there should now be a cache of the change at /path/to/monorepo/tmp/.git_dirty
.
If launchctl list
is showing something bad or your tempfile isn't being created, hopefully the log file at /path/to/monorepo/log/update-git-dirty.log
says something. If not, feel free to ping me on Twitter for help.
Now that you have that .git_dirty
file, you can use it to report on there being changes from your prompt. For example, this is what my git prompt looks like now (and, yes, it's fish
. sorry not sorry! π):
# The function you want to look at is `_git_dirty`
function __fish_prompt_git
set -g __git_branch_name (command git symbolic-ref --short -q HEAD ^/dev/null)
if not set -q -g __git_functions_defined
set -g __git_functions_defined
function _git_dirty
if test -e $PWD/tmp/.git_dirty
echo (cat $PWD/tmp/.git_dirty)
else
echo (command git status -s --ignore-submodules=dirty)
end
end
function _git_ahead
echo (command git log --format=oneline origin/$__git_branch_name..$__git_branch_name ^/dev/null)
end
function _git_behind
echo (command git log --format=oneline $__git_branch_name..origin/$__git_branch_name ^/dev/null)
end
end
set -l cyan (set_color -o cyan)
set -l yellow (set_color -o yellow)
set -l purple (set_color -o purple)
set -l blue (set_color -o blue)
set -l normal (set_color normal)
set -l cwd $cyan(prompt_pwd)
if [ $__git_branch_name ]
set -l git_branch $purple$__git_branch_name
set git_info "$blue $git_branch"
if [ (_git_dirty) ]
set -l dirty $yellow!
set git_info $git_info$dirty
end
if [ (_git_ahead) ]
set -l ahead $blueβ
set git_info $git_info$ahead
end
if [ (_git_behind) ]
set -l behind $blueβ
set git_info $git_info$behind
end
end
echo $git_info
end
This results in a prompt that looks like this when there are new changes in tracked files (or if there are new untracked files):
All the relevant function does now is check for the existence of a file at $PWD/tmp/.git_dirty
and read from it. If it's not there, it'll run git status
on the fly.