One-liners: git sync
According to my shell history, git sync is my most-used Git command.
I jump between repos all day, so I use one command that checks out the branch behind origin/HEAD and pulls with rebase, then clears out stale worktree records and local branches whose upstream is gone.
Here’s what it looks like in my ~/.gitconfig:
[fetch]
prune = true
[pull]
rebase = true
[alias]
db = !git symbolic-ref refs/remotes/origin/HEAD --short | sed 's@origin/@@'
sync = !git checkout $(git db) && git pull && git worktree prune && git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads | awk '$2 ~ /gone/ {print $1}' | xargs -r git branch -D
Breaking it down
Prune on every fetch:
[fetch]
prune = true
This deletes stale remote-tracking refs. Without it, origin/* drifts from reality.
Make pull rebase by default:
[pull]
rebase = true
This makes git pull “fetch + rebase” instead of “fetch + merge”. History stays linear and you don’t pick up a merge commit on every pull.
Resolve the default branch dynamically:
[alias]
db = !git symbolic-ref refs/remotes/origin/HEAD --short | sed 's@origin/@@'
origin/HEAD follows the remote default branch (main, master, etc.).
Strip origin/, and you get a checkout-ready branch name. Hardcoding main is brittle.
And the sync one-liner:
[alias]
sync = !git checkout $(git db) && git pull && git worktree prune && git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads | awk '$2 ~ /gone/ {print $1}' | xargs -r git branch -D
The leading ! makes this a shell alias, so pipes and command substitution work.
git checkout $(git db): move to the repo’s actual default branch.git pull: fetch and rebase local commits (if any) onto the updated default branch.git worktree prune: forget worktrees whose directories no longer exist, since git won’t delete a branch checked out in one.git for-each-ref --format '%(refname:short) %(upstream:track)' refs/heads: list every local branch next to its tracking state, which reads[gone]once the upstream is deleted.awk '$2 ~ /gone/ {print $1}' | xargs -r git branch -D: extract those branch names and delete them.
-D is intentional: squash merges create a new commit on the default branch,
so -d often refuses to delete the source branch. If upstream is gone, I treat
the branch as disposable. Use -d only if you keep long-lived local branches.