Last updated: 2026-05-18

Basic Branching and Merging

Branching becomes genuinely powerful when you understand how to use it in a real workflow — creating branches to isolate work, switching between them freely, and merging them back together when ready. This topic walks through a realistic scenario that covers everything from feature work to emergency hotfixes.


A Real-World Branching Scenario

Imagine you are working on a project. You have a stable main branch in production. You are mid-way through a new feature when an urgent bug report comes in that needs an immediate fix.

Without branches, this is a problem — your unfinished feature work is mixed in with the production code. With Git branches, this situation is routine:

  1. Create a branch for the feature and work on it.
  2. Receive the urgent bug report.
  3. Switch back to main, create a hotfix branch, fix the bug, and merge it.
  4. Switch back to the feature branch and continue where you left off.

This is the core branching workflow in practice.


Step 1 — Create a Feature Branch

You are starting work on issue #53. Create a branch and switch to it immediately:

git switch -c iss53

Make your changes and commit:

git commit -a -m "Create new footer [issue 53]"

Your history now looks like this:

main:  A -- B
              \
iss53:         C

The iss53 branch has moved forward with your commit. main is still at B.


Step 2 — Switch to Handle an Urgent Hotfix

An urgent bug is reported in production. You need to fix it immediately — without deploying your unfinished iss53 work.

First, make sure your working directory is clean (all changes committed), then switch back to main:

git switch main

Your working directory immediately reverts to the state it was in at commit B — as if you never touched iss53. Your feature work is safely stored on its own branch.

Create a hotfix branch off main:

git switch -c hotfix

Fix the bug and commit:

git commit -a -m "Fix broken email address"
main:  A -- B
            |  \
hotfix:     |   D
            |
iss53:      C

Step 3 — Merge the Hotfix (Fast-Forward)

The fix is tested and ready. Merge it back into main:

git switch main
git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

What is a fast-forward merge?

Notice the phrase "Fast-forward" in the output. This happens when the branch being merged (hotfix) is a direct descendant of the branch you are merging into (main) — there is no divergent history to reconcile. Git simply moves the main pointer forward to the same commit as hotfix.

Before:    main → B,  hotfix → D  (D is directly ahead of B)
After:     main → D,  hotfix → D  (main just moves forward)

No new commit is created. Git just advances the pointer.

After merging, delete the hotfix branch — it has served its purpose:

git branch -d hotfix

Step 4 — Return to the Feature Branch

Switch back to iss53 and continue the work:

git switch iss53
git commit -a -m "Finish the new footer [issue 53]"

Note that the hotfix changes are not in your iss53 branch. The two branches are independent. If you need the hotfix changes in your feature branch, you can merge main into iss53 at any time — or simply wait and let it happen naturally when you merge iss53 back into main.


Step 5 — Merge the Feature Branch (Three-Way Merge)

The feature is complete. Merge iss53 back into main:

git switch main
git merge iss53
Merge made by the 'ort' strategy.
 index.html | 1 +
 1 file changed, 1 insertion(+)

This merge is different from the hotfix merge. The histories have divergedmain has moved forward (with the hotfix) and iss53 has moved forward independently. There is no straight-line path from one to the other.

What is a three-way merge?

When branches have diverged, Git cannot simply move a pointer forward. Instead it performs a three-way merge using three snapshots:

  1. The tip of the branch being merged in (iss53).
  2. The tip of the branch being merged into (main).
  3. The common ancestor — the commit where the two branches last shared history.
         common
         ancestor
            |
main:  A -- B -- D -- E
            \
iss53:       C -- F

Git combines the changes from both tips relative to the common ancestor and creates a merge commit — a new commit with two parents. This is what makes a merge commit special: it records the point where two lines of history joined.

main:  A -- B -- D -- E -- M  ← merge commit (parents: E and F)
            \             /
iss53:       C ----------F

After a successful merge, delete the feature branch:

git branch -d iss53

Fast-Forward vs. Three-Way Merge — A Comparison

Fast-ForwardThree-Way Merge
When it happensThe merged branch is a direct ancestor of the targetThe branches have diverged
What Git doesMoves the pointer forwardCreates a new merge commit
New commit createdNoYes
ParentsOne (the existing chain)Two (one for each branch tip)
Output message"Fast-forward""Merge made by the 'ort' strategy"

Merge Conflicts

Merging is clean most of the time. But if both branches modified the same part of the same file differently, Git cannot automatically decide which version is correct and will stop to ask you:

CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git pauses the merge and marks the conflicting sections inside the file with conflict markers:

<<<<<<< HEAD
<div id="footer">contact: email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53

Reading the markers:

  • Everything between <<<<<<< HEAD and ======= is the version from the branch you are merging into (your current branch).
  • Everything between ======= and >>>>>>> iss53 is the version coming from the branch you are merging.

To resolve the conflict, edit the file to the result you want — removing all three marker lines and leaving only the content that should remain:

<div id="footer">
please contact us at email.support@github.com
</div>

Once resolved, stage the file to mark it as resolved and complete the merge:

git add index.html
git commit

Git pre-fills a merge commit message. You can add notes about how the conflict was resolved before saving.

Checking conflict status

At any point during a conflicted merge, git status shows which files are unresolved:

git status
Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified: index.html

Once all conflicts are resolved and staged, git status confirms you are ready to commit:

All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Using a merge tool

For complex conflicts, a visual merge tool can be easier than editing raw conflict markers:

git mergetool

Git launches a configured diff tool that presents the conflict visually. After resolving, save and exit — Git stages the resolved file automatically.


Summary

CommandWhat It Does
git switch -c <branch>Creates and switches to a new branch
git switch <branch>Switches to an existing branch
git merge <branch>Merges the specified branch into the current branch
git branch -d <branch>Deletes a merged branch
git mergetoolOpens a visual tool to resolve merge conflicts
git log --oneline --graph --allVisualises full branch history including divergence