Skip to content

Instantly share code, notes, and snippets.

@awadhwana
Created June 17, 2026 06:02
Show Gist options
  • Select an option

  • Save awadhwana/7bfd07c95a9be9a27098f4278b64ca81 to your computer and use it in GitHub Desktop.

Select an option

Save awadhwana/7bfd07c95a9be9a27098f4278b64ca81 to your computer and use it in GitHub Desktop.
README file for the gist update-all-repos.sh

update-all-repos

Walks every git repo in a directory and brings its base branch up to date — once a day, unattended. Built for a multi-repo (microservices) setup where feature branches go stale overnight.

Companion to the blog post: The 200-Line Bash Script That Rebases My Repos While I Sleep.

What it does

For each */ directory under REPOS_DIR that contains a .git:

  • Detached HEAD → skipped (no branch to update).
  • On the base branchgit pull --rebase.
  • On a feature branch → fast-forwards the local base ref without checking out (git fetch origin base:base). If that's refused because the local base diverged, it falls back to stash → checkout base → rebase → checkout back → unstash.

Plus the unglamorous parts that make it safe to run while you sleep:

  • Single-run lock via atomic mkdir — concurrent runs abort instead of clobbering.
  • Network wait — polls github.com and backs off before giving up.
  • Reversible fallback — restores your branch and stash on any failure.
  • Tri-state exit — success / failure / "rebase OK but stash needs manual resolve" (return 2).
  • macOS notification on completion, naming any repos that failed or need attention.
  • Optional parallelism via PARALLEL=N, with output replayed in original order.

Requirements

  • macOS (uses osascript for notifications)
  • git, curl
  • Bash 3.2+ (ships with macOS; Bash 4+ enables wait -n throttling)

Quick start

chmod +x update-all-repos.sh

# Run against the folder the script lives in:
./update-all-repos.sh

# Or point it elsewhere:
REPOS_DIR=/Users/me/code ./update-all-repos.sh

# Update 4 repos at a time:
PARALLEL=4 REPOS_DIR=/Users/me/code ./update-all-repos.sh

Environment variables

Var Default Meaning
REPOS_DIR script's own directory Folder whose immediate subdirs are repos
PARALLEL 1 Concurrent repo updates
LOG_DIR ~/.cache/update-all-repos Where last-run.log / prev-run.log go

Schedule it (launchd)

  1. Edit com.me.update-all-repos.plist — replace /Users/me/code with your paths.
  2. Install and load:
cp com.me.update-all-repos.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.me.update-all-repos.plist

Unload with launchctl unload ~/Library/LaunchAgents/com.me.update-all-repos.plist.

Prefer cron? It works but is deprecated on macOS and won't fire if the laptop was asleep at the trigger minute:

0 8 * * * REPOS_DIR=/Users/me/code /Users/me/code/update-all-repos.sh

Logs

  • ~/.cache/update-all-repos/last-run.log — most recent run
  • ~/.cache/update-all-repos/prev-run.log — the run before it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment