Published on : 2026-03-11 10:07
Some time ago ( 2025-07-10 ) I wrote about a small script for
updating and navigating Git repositories:
(DIR) Automating Git Repo Updates and Navigation with a POSIX Shell Script
Since then, my workflow has evolved a bit. The script below is an
updated version with a few quality-of-life improvements, mainly
around usability and integration with my terminal and tmux
workflow.
What This New Script Does
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
The script manages all Git repositories stored in ~/Work.
It performs two main tasks:
* Updates every repository in the directory
* Lets me quickly search, select and open a repository
See the script in action
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
You can view the video linked below and see it in action:
(BIN) Update repositories (new script) in action
Get the script
‾‾‾‾‾‾‾‾‾‾‾‾‾‾
(TXT) 💾 Source code
Change lines 3 and 4 to update your work directory and terminal
Why I Like This Approach
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
This setup keeps things simple and efficient:
* all repositories update with one command
* fuzzy search makes project selection instant
* every repository has its own tmux session
* everything relies on small Unix tools
Tools used:
‾‾‾‾‾‾‾‾‾‾‾
* bash
* git
* fzf
* tmux
* dunst - for notifications
* alacritty - my terminal of choice
The workflow is simple:
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
* Update all repositories with git pull
* Send a desktop notification when the update is finished
* Present a repository list using fzf
* Open the selected repository in a tmux session in a terminal
This turns a plain directory of projects into a lightweight
project launcher.
Updating All Repositories
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
The first part scans the directory for .git folders and pulls
updates.
for gitdir in */.git; do
[ -d "$gitdir" ] || continue
repo="${gitdir%/.git}"
echo "Updating $repo"
git -C "$repo" pull --ff-only || true
done
Using --ff-only prevents accidental merge commits during automated
pulls. If a repository cannot fast-forward, it is simply skipped.
Desktop Notification
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Once all repositories are processed, the script sends a
notification:
dunstify -h string:x-dunst-stack-tag:git "Git Update" \
"All repositories has been updated"
This integrates nicely with lightweight notification daemons
like dunst.
Discovering Repositories
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
The script then searches for Git repositories inside the working
directory:
find "$WORKDIR" -mindepth 1 -maxdepth 1 -type d \
-exec test -d "{}/.git" \; -print
The directory names are extracted, sorted, and turned into a menu
list for fzf. An Exit option is added so the menu can be
dismissed easily.
Selecting a Repository
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Repository selection is handled with fzf:
repo=$(printf "%s\n" "$menu" | fzf \
--prompt="Select repo > " \
--height=35% \
--border=rounded \
--tmux)
This makes navigating a large number of repositories fast
and convenient.
Opening the Project in tmux
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Once a repository is selected, the script checks if a tmux session
already exists:
tmux has-session -t "$repo" 2>/dev/null ||
tmux new-session -d -s "$repo" -c "$dir"
If the session doesn't exist, it creates one in the repository
directory.
Finally, a new terminal window (in my case alacritty) opens and
attaches to that session.
This means every project keeps its own persistent tmux workspace.
Closing Thoughts
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Small scripts like this are a good reminder of how powerful
simple tools can be. A bit of shell scripting can replace much
heavier project management workflows.
And like most scripts, it keeps evolving as the workflow evolves.
(DIR) Back to my phlog