By admin , 28 April 2026

Introduction

In Git, a branch is just a movable reference to a commit. Creating a branch is creating a 41-byte file. Compared to centralized systems where branches are full directory copies, Git's model makes branching cheap enough to use casually.

What a branch actually is

cat .git/refs/heads/main
# a1b2c3d4e5f6...
git rev-parse main

That hash is the tip of the branch. The "branch" itself is the chain of commits reachable from the tip via parent pointers.

Creating branches

git branch feature/login           # create, do not switch
git switch -c feature/login        # create and switch
git switch -c hotfix v1.2.3        # from a tag
git branch fixup HEAD~3            # from a relative ref

Moving the tip

Every commit on the current branch advances its tip by one. Commands that move tips include commit, merge, rebase, reset, and cherry-pick.

git commit -m "Work"           # main moves forward
git reset --hard HEAD~2        # main moves backward; commits become unreachable

Branches and reachability

A commit is "alive" as long as some ref reaches it. Delete every branch and tag pointing at a commit and it becomes dangling; Git's garbage collector eventually removes it.

git fsck --unreachable
git gc

Tracking upstream

A local branch can be linked to a remote-tracking branch:

git branch --set-upstream-to=origin/main main
git branch -u origin/main
git status            # shows ahead/behind based on the link

Branch maintenance

git branch --merged main           # branches fully merged
git branch --no-merged main        # branches with unmerged work
git branch -d feature/old          # delete merged
git branch -D feature/discarded    # force delete

Comparing branches

git log main..feature/login --oneline
git diff main...feature/login
git range-diff main..@{u} main..HEAD

range-diff is great for comparing two versions of a rebased branch.

Branch policies on hosts

Most hosting platforms let you protect branches by name pattern: require pull requests, signed commits, passing CI, or specific reviewers before a push is accepted. The Git side of this is implemented via pre-receive hooks; the platform side is configuration. From your local clone, branch protection is invisible until your push is rejected, at which point the server explains why. To inspect protection from the command line, use the host's CLI (gh, glab) or its API.

gh api repos/owner/repo/branches/main/protection

Common mistakes

Imagining branches as containers of commits. They are not; commits exist independently and many branches can reach the same commit. Deleting a "feature" branch and assuming the commits are gone; they are gone only after they become unreachable and the reflog expires (90 days by default). Using long single-word branch names that collide with file names; -- separators avoid the ambiguity. Finally, working directly on main in a shared repo; always branch for non-trivial work, even if you plan to fast-forward later.