<!--order=4-->
<h1>Git: Branching and Merging</h1>
<p>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.</p>

<h2>Commands Covered</h2>
<p><code>git branch</code> · <code>git switch</code> · <code>git checkout</code> · <code>git merge</code> · <code>git show-branch</code> · <code>git merge-tree</code></p>

<h2>git branch</h2>
<pre>
# 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
</pre>

<h2>git switch</h2>
<p>Switches branches. Introduced in Git 2.23 as a clearer alternative to <code>git checkout</code> for branch switching specifically.</p>
<pre>
# 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
</pre>

<h2>git checkout</h2>
<p>The older, multi-purpose command that <code>git switch</code> and <code>git restore</code> replaced for clarity. Still widely used and not going away.</p>
<pre>
# 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
</pre>

<h2>git merge</h2>
<p>Joins two branches by integrating changes from one into another. There are different merge strategies; Git picks the right one automatically in most cases.</p>
<pre>
# 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)"
</pre>

<h3>Merge Conflicts</h3>
<pre>
# 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:
&lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
  // current branch code
=======
  // incoming branch code
&gt;&gt;&gt;&gt;&gt;&gt;&gt; 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
</pre>

<h2>git show-branch</h2>
<p>Shows branches and their commits in a compact format. Useful for seeing how branches diverge.</p>
<pre>
# 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
</pre>

<h2>git merge-tree</h2>
<p>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.</p>
<pre>
# 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>&amp;1 | head -20
</pre>

<h2>Branching Workflows</h2>

<table>
  <thead><tr><th>Workflow</th><th>Branch structure</th><th>Best for</th></tr></thead>
  <tbody>
    <tr><td>Feature branches</td><td><code>main</code> + short-lived feature branches</td><td>Most projects; keeps main stable</td></tr>
    <tr><td>Git Flow</td><td><code>main</code>, <code>develop</code>, <code>feature/*</code>, <code>release/*</code>, <code>hotfix/*</code></td><td>Projects with scheduled releases</td></tr>
    <tr><td>Trunk-based</td><td>Everyone commits to <code>main</code>, very short-lived branches</td><td>CI/CD heavy teams; requires good test coverage</td></tr>
    <tr><td>Forking</td><td>Each contributor forks the repo; PRs merge into upstream</td><td>Open source projects</td></tr>
  </tbody>
</table>

<pre>
# 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
</pre>

<h2>References</h2>
<ul>
  <li><a href="https://git-scm.com/docs/git-branch" target="_blank" rel="noopener">git-branch documentation ↗</a></li>
  <li><a href="https://git-scm.com/docs/git-merge" target="_blank" rel="noopener">git-merge documentation ↗</a></li>
  <li><a href="https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell" target="_blank" rel="noopener">Pro Git Book — Branching ↗</a></li>
</ul>
