Create, Track and Safely Delete Branches with git branch

Branches pile up fast, and deleting the wrong one at the wrong moment is a very bad afternoon. With git branch you will inspect a repository's branches, create a topic branch from a known starting point, connect it to an upstream, rename it, and remove it without guessing what will be lost. The examples use Git 2.43.0, the version installed on this machine. Allow about 10 minutes if you already have a repository and a remote; the commands themselves do not need elevated privileges.

1. Check where you are

Run these commands inside the repository you intend to change. They are read-only and establish the current branch, its commit and any configured upstream:

$ git status --short --branch
## main...origin/main
$ git branch --show-current
main
$ git branch -vv
* main 7f3a1c2 [origin/main] Update deployment notes

Your branch name and commit will differ. Three things to read from that output:

Checkpoint: you know the repository, current branch and starting commit. If the working tree contains changes you cannot explain, stop before switching or deleting anything.

2. List local and remote branches

With no non-option arguments, git branch lists local branches. Disable terminal colouring when saving or comparing output so display settings cannot confuse a script or a copy-and-paste check:

$ git branch --no-color
* main
  topic/report
$ git branch --remotes --no-color
  origin/HEAD -> origin/main
  origin/main
  origin/release
$ git branch --all --no-color
* main
  topic/report
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/release

To filter a listing, include --list and quote the shell wildcard. Without --list, a pattern can be interpreted as a request to create a branch:

$ git branch --list 'topic/*' --no-color
  topic/report

Use git branch --merged to show branches whose tips are reachable from HEAD, which is a useful deletion candidate list. It is a reachability check, not a review of whether the branch's work was useful. Use --no-merged to find branches not yet contained by HEAD. Add a commit, such as origin/main, when that is the comparison point you actually mean.

3. Create a branch without touching worktree files

Create a branch at the current commit, or supply a start point such as a remote-tracking branch, tag or commit ID:

$ git branch topic/report origin/main
branch 'topic/report' set up to track 'origin/main'.
$ git branch --list 'topic/*' --verbose --no-color
  topic/report 7f3a1c2 Update deployment notes [origin/main]

This creates the name but leaves the current branch checked out. To create and switch in one operation, use git switch --create topic/report origin/main instead. If the start point is a remote-tracking branch, Git 2.43.0 normally creates upstream configuration automatically because branch.autoSetupMerge defaults to true. Make the choice explicit when it matters:

$ git branch --track=direct topic/report origin/main
$ git branch --no-track topic/local HEAD

These settings affect what git status, git branch -v and argument-free git pull use; they do not publish the branch to a remote.

Verify the result before switching:

$ git rev-parse --verify topic/report
7f3a1c2...
$ git rev-parse --abbrev-ref topic/report@{upstream}
origin/main

If the second command fails, the branch has no upstream. That is not necessarily an error: set one later with git branch --set-upstream-to=origin/main topic/report, or leave the branch deliberately untracked.

4. Rename or copy a branch

Rename a local branch with --move. When run without the old name, it renames the current branch:

$ git branch --move topic/report topic/release-notes
$ git branch --show-current
topic/release-notes

The rename carries the branch configuration and reflog. Git refuses to replace an existing target name.

Destructive action: treat -M as an overwrite. It forces the rename and can hide the branch name currently occupying the target. Inspect first with git branch --list 'topic/*'.

Use --copy when both names should remain. It copies the branch, its configuration and its reflog:

$ git branch --copy topic/release-notes topic/release-notes-backup
$ git branch --list 'topic/*' --verbose --no-color

These operations update local refs only. A remote branch needs a separate push or deletion operation, and that is outside the scope of git branch.

5. Delete only after checking the boundary

First identify branches merged into the intended base:

$ git branch --merged main --no-color
* main
  topic/release-notes

Warning: deleting a branch changes a ref. A normal delete is deliberately conservative and refuses an unmerged branch:

$ git branch --delete topic/release-notes
Deleted branch topic/release-notes (was 7f3a1c2).

Do not use -D just to silence an error. It is the forced form of deletion and removes the branch even when its tip is not merged or is not a valid commit. Before using it, save a recovery name pointing at the exact tip:

$ git branch safety/topic-release-notes topic/release-notes
$ git branch --delete --force topic/release-notes

Recovery: to undo that deletion while the safety branch exists, recreate the original name from it.

$ git branch topic/release-notes safety/topic-release-notes

Deleting a remote-tracking ref with git branch --delete --remotes origin/topic-name does not delete the branch on the server. A later fetch may recreate it unless the remote no longer has it or your fetch configuration excludes it. Use remote-management commands only when you mean to change the server or prune stale tracking refs.

Common traps

Done means