Git: Branching and Merging
Branches are one of Git's core strengths — they're cheap, fast, and local. A branch is just a pointer to a commit; creating one takes microseconds and uses almost no disk space. Branching lets you work on features or fixes in isolation without affecting the main codebase, then merge back when ready.
Commands Covered
git branch · git switch · git checkout · git merge · git show-branch · git merge-tree
git branch
# List local branches (* marks the current branch) $ git branch # List all branches including remote-tracking $ git branch -a # List remote-tracking branches only $ git branch -r # Create a new branch (doesn't switch to it) $ git branch feature-login # Create a branch starting from a specific commit or branch $ git branch fix-bug abc1234 $ git branch hotfix origin/main # Delete a branch (safe — won't delete if it has unmerged changes) $ git branch -d feature-old # Force delete (even if unmerged) $ git branch -D feature-old # Rename the current branch $ git branch -m new-name # Rename a specific branch $ git branch -m old-name new-name # Show the last commit on each branch $ git branch -v # Show branches that have/haven't been merged into current branch $ git branch --merged $ git branch --no-merged # Set upstream tracking for a branch $ git branch --set-upstream-to=origin/main main $ git branch -u origin/feature feature
git switch
Switches branches. Introduced in Git 2.23 as a clearer alternative to git checkout for branch switching specifically.
# Switch to an existing branch $ git switch main $ git switch feature-login # Create and switch to a new branch in one step $ git switch -c new-feature $ git switch --create new-feature # Create a branch from a specific starting point $ git switch -c hotfix origin/main $ git switch -c release-1.0 v1.0-rc1 # Switch to the previous branch (like cd -) $ git switch - # Force switch even if there are local changes (discards changes) $ git switch -f main
git checkout
The older, multi-purpose command that git switch and git restore replaced for clarity. Still widely used and not going away.
# Switch branches (equivalent to git switch) $ git checkout main $ git checkout feature-login # Create and switch (equivalent to git switch -c) $ git checkout -b new-feature $ git checkout -b hotfix origin/main # Restore a file to its committed state (equivalent to git restore) $ git checkout -- myfile.c $ git checkout HEAD -- README.md $ git checkout abc1234 -- src/main.c # restore from specific commit # Detach HEAD — point HEAD directly at a commit (not a branch) $ git checkout abc1234 # You're now in "detached HEAD" state — any commits won't be on a branch. # Create a branch to keep them: git switch -c new-branch
git merge
Joins two branches by integrating changes from one into another. There are different merge strategies; Git picks the right one automatically in most cases.
# Merge a branch into the current branch $ git checkout main $ git merge feature-login # Merge with a commit even if fast-forward is possible $ git merge --no-ff feature-login # Fast-forward merge moves the branch pointer without creating a merge commit. # --no-ff always creates a merge commit, preserving the branch history. # Merge without committing (stage the result for review first) $ git merge --no-commit feature-login # Abort a merge in progress (if there are conflicts) $ git merge --abort # Squash all commits from the branch into one staged change (don't merge) $ git merge --squash feature-login $ git commit -m "Add login feature (squashed)"
Merge Conflicts
# When a merge fails due to conflicts: $ git merge feature-login # CONFLICT (content): Merge conflict in src/auth.c # Automatic merge failed; fix conflicts and then commit. # Conflict markers in the file: <<<<<<< HEAD // current branch code ======= // incoming branch code >>>>>>> feature-login # Resolve: edit the file to keep what you want, remove the markers # Then stage and commit: $ git add src/auth.c $ git commit # Or use a merge tool: $ git mergetool # opens configured diff/merge tool $ git config --global merge.tool vimdiff $ git config --global merge.tool code # VS Code
git show-branch
Shows branches and their commits in a compact format. Useful for seeing how branches diverge.
# Show recent commits on current branch and its divergence from others $ git show-branch # Show specific branches $ git show-branch main feature-login hotfix # Show all branches $ git show-branch --all # Show remote branches $ git show-branch --remotes
git merge-tree
Performs a merge without touching the index or working tree — a "dry run" merge. Useful for checking whether a merge would conflict before actually doing it.
# Check if merging feature into main would conflict (Git 2.38+) $ git merge-tree --write-tree main feature-login # Exit code 0 = clean merge, non-zero = conflicts # Older syntax (three-way merge on tree objects) $ git merge-tree $(git merge-base main feature) main feature # Check conflicts and show them $ git merge-tree --write-tree --no-messages main feature 2>&1 | head -20
Branching Workflows
| Workflow | Branch structure | Best for |
|---|---|---|
| Feature branches | main + short-lived feature branches | Most projects; keeps main stable |
| Git Flow | main, develop, feature/*, release/*, hotfix/* | Projects with scheduled releases |
| Trunk-based | Everyone commits to main, very short-lived branches | CI/CD heavy teams; requires good test coverage |
| Forking | Each contributor forks the repo; PRs merge into upstream | Open source projects |
# Typical feature branch workflow: $ git switch -c feature-search # create and switch to feature branch # ... make commits ... $ git switch main # return to main $ git merge --no-ff feature-search # merge with a merge commit $ git branch -d feature-search # clean up # Keep a feature branch up to date with main: $ git switch feature-search $ git merge main # merge main's changes into feature # or: $ git rebase main # replay feature commits on top of main
dispelled