Andrew Mercer
on this page

07 · Branch Management

← Overview · Prev: Stash · Next: Hooks →

Create, switch, rename

git switch <branch>                 # old: git checkout <branch>
git switch -c <new-branch>          # create and switch (from current HEAD)
git switch -c <new-branch> origin/<branch>    # start from a remote branch
git branch -m <old> <new>           # rename local branch
git branch -vv                      # branches with upstream and ahead/behind
git branch --merged main            # already merged into main (safe to delete)
git branch --no-merged main         # still has unmerged work

Renaming a branch that is already on the remote:

git branch -m <old> <new>
git push origin --delete <old>
git push -u origin <new>

git-adm: git-adm branch rename does all three steps.

Naming

Put the ticket key first so tooling can extract it, then a short kebab-case description: PROJ-1234-fix-login-redirect. git-adm branch create builds the name that way and sanitises the suffix.

Delete branches (local and remote)

git branch -d <branch>                         # safe: refuses if unmerged
git branch -D <branch>                         # force
git push origin --delete <branch>              # remote

# several at once
for b in <branch1> <branch2>; do git branch -d "$b"; git push origin --delete "$b"; done

# everything already merged into main (skips main/master and the current branch)
git branch --merged main | grep -vE '^\*|main|master' | xargs -r git branch -d

# clean up stale remote-tracking refs
git fetch --prune

git-adm: * git-adm branch delete [name] — -d first, asks before forcing. * git-adm branch nuke <name> — local and remote, typed confirmation. * git-adm branch prune — delete local branches already merged into the base.

Reading: https://www.freecodecamp.org/news/how-to-delete-a-git-branch-both-locally-and-remotely

Protect the default branch

  • Server-side: enable branch protection (required reviews, required CI, no force-push).
  • Client-side: git-adm refuses destructive operations on main/master, and a pre-push hook can too:
#!/usr/bin/env bash
# pre-push: refuse to push directly to main/master
while read -r local_ref _ remote_ref _; do
  case "$remote_ref" in refs/heads/main|refs/heads/master)
    echo "Direct pushes to ${remote_ref#refs/heads/} are blocked. Use a PR." >&2; exit 1;;
  esac
done

Worktrees: several branches checked out at once

git worktree add ../hotfix hotfix-branch      # second working directory sharing the same repo
git worktree list
git worktree remove ../hotfix

Faster and safer than stashing when you need to jump to a hotfix and back.

Cherry-pick

git cherry-pick <sha>                 # copy one commit onto the current branch
git cherry-pick A^..B                 # a range, inclusive
git cherry-pick -x <sha>              # record the original SHA in the message
git cherry-pick --continue | --abort