This is a bit of a silly post: it's relatively trivial, but someone asked me if this was possible the other day and I realized that it's perhaps not so trivial if you're unfamiliar with the various bits of necessary tooling.
You can have uv sync
(or npm install
. etc.) run automatically every time you change branches by adding an executable1 .git/hooks/post-checkout
file to the repository in question with the following contents:
#!/usr/bin/env bash
# capture changed files between two refs ($1 and $2)
changed_files="$(git diff-tree -r --name-only --no-commit-id $1 $2)"
# Exit early if no files changed
[ -z "$changed_files" ] && exit 0
# Note that $0, $1, and $2 in the body of the function are not the same as the above,
# due to argument scoping rules for bash functions:
check_run() {
echo "$changed_files" | grep --quiet "$1" && echo "Running $2..." && eval "$2" || true
}
check_run uv.lock "uv sync"
This will execute when git-checkout
or git-switch
is run, after having updated the worktree.
The git docs provide additional details, but essentially the hook is given three parameters: the previous ref, the new ref, and a flag that indicates whether the checkout was a branch checkout or a file checkout.
The script2 runs a git diff-tree
filter to extract out the names of all files that have a delta between the two refs. These filenames are then fed to a simple check()
function that compares that list against a target file (in our case, uv.lock
). If the target filename is found within the list of changed filenames, then a command is eval
'ed: in this case, uv sync
.
You can also adjust the code to watch for any other kind of file, such as a package-lock.json
, and then run the relevant npm
commands as necessary.
Don't forget to chmod +x
the file after you've created it, otherwise git will not execute the script.
You can and should read up on bash scripting! It's a bit weird, but shell scripts glue the world together.
There are some scenarios where you may be in the middle of merging/rebasing/etc. with a target lockfile that is in conflict, so this isn't a panacea, but it should be handy enough in the most common branch switching cases to merit its implementation.