thecodingidiot.com

Version ControlBranches

Branches

You are working on a stable version of your project. A feature idea comes up — something worth trying, but risky enough that you do not want it touching the working code until you know it works. Or you need to fix a bug while another change is already half-done.

Branches solve this. They let you maintain multiple independent lines of development in the same repository and merge them when you are ready.

A branch is a pointer to a commit. Not a copy of your files — a pointer. Creating one is cheap: it is a single file in .git/refs/ containing a forty-character hash. When you commit on a branch, the pointer moves forward to the new commit. When you switch branches, git swaps the working tree and index to match what that pointer references. Nothing is duplicated.


Creating a branch

git branch feature

You are still on main. Switch to the new branch:

git switch feature

Create and switch in one step:

git switch -c feature

The classic form works too and you will see it in older guides and existing scripts:

git checkout -b feature

git branch with no arguments lists all branches and marks the current one with *.


Diverging

Make two commits on feature:

echo "feature line 1" >> notes.txt
git add notes.txt && git commit -m "add feature line 1"
 
echo "feature line 2" >> notes.txt
git add notes.txt && git commit -m "add feature line 2"

Switch back to main and make one commit there:

git switch main
echo "main update" > main-notes.txt
git add main-notes.txt && git commit -m "add main-notes"

Look at the history across both branches:

git log --oneline --graph --all

Output:

* 3f8a1d2 (HEAD -> main) add main-notes
| * b4c9e7f (feature) add feature line 2
| * a1d3c8e add feature line 1
|/
* 9e2b4f1 add hello.txt
(earlier commits omitted for clarity)

The history has forked. main and feature share a common ancestor and have diverged from it. git log --graph makes the topology visible; this becomes important when you have multiple long-lived branches.


Merging

Merge feature back into main:

git switch main
git merge feature

Fast-forward merge: if main has not moved since feature branched, git simply advances main's pointer to the tip of feature. No merge commit is created. The history is linear.

Merge commit: when both branches have new commits (as above), git cannot fast-forward. It creates a new commit with two parents — one from each branch. The graph shows the branches rejoining:

*   7d1a3b9 (HEAD -> main) Merge branch 'feature'
|\
| * b4c9e7f (feature) add feature line 2
| * a1d3c8e add feature line 1
* | 3f8a1d2 add main-notes
|/
* 9e2b4f1 add hello.txt

The merge commit records when the integration happened and what was integrated. Prefer it over rebasing for long-lived branches — the integration point should be visible in the log.


Resolving a conflict

Sometimes two branches modify the same part of the same file. Git cannot decide which version to keep, so it stops and asks you.

Manufacture a conflict: both branches write to the same line.

git switch -c conflict-demo
echo "branch A version" > shared.txt
git add shared.txt && git commit -m "branch A edit"
 
git switch main
echo "branch B version" > shared.txt
git add shared.txt && git commit -m "branch B edit"
 
git merge conflict-demo

Git stops:

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

Open shared.txt. Git has written both versions with markers:

<<<<<<< HEAD
branch B version
=======
branch A version
>>>>>>> conflict-demo

Between <<<<<<< HEAD and ======= is what the current branch had. Between ======= and >>>>>>> is what the incoming branch had. Edit the file to the result you want, delete all three marker lines (they are not valid in any file format — they are temporary annotations), then:

git add shared.txt
git commit

Git opens your editor with a pre-filled merge commit message. Save and close to finish. The editor is the merge tool. No external program required.


Cleaning up

Delete a merged branch:

git branch -d feature

Git refuses if the branch has not been merged — the commits would become unreachable. To delete a branch that has not been merged when you are certain you do not need those commits, use -D. Do not use -D reflexively; it discards work.