Branches & merging
A branch is just a movable pointer to a commit. Creating one costs nothing, so the normal way to work is: one
branch per feature or bug fix, main always in a working state.
The everyday loop
git switch -c feature/login # create the branch and move onto it
# ...edit & commit...
git switch main
git merge feature/login
git branch -d feature/login # delete once merged
git switch (Git 2.23+) is the modern command for moving between branches; git checkout still does the same job
but also does several unrelated things, which is why it was split.
git branch # list local branches, * marks the current one
git branch -a # include remote-tracking branches
git switch main # move to an existing branch
git branch -m old new # rename a branch
Two kinds of merge
| Situation | Result | History |
|---|---|---|
main has not moved since you branched |
Fast-forward: the pointer simply slides ahead | Perfectly linear |
main gained commits while you worked |
Merge commit with two parents | Shows the branch |
Force a merge commit even when a fast-forward is possible with git merge --no-ff feature/login. Many teams prefer
this so the history shows that a group of commits belonged to one feature.
Keeping a long-running branch fresh
If your branch lives for days, pull main into it regularly so the final merge is small:
git switch feature/login
git fetch origin
git merge origin/main
Small, frequent merges mean small, easy conflicts.
Conflicts
A conflict occurs only when both branches changed the same lines of the same file. Git pauses and writes markers into the file:
<<<<<<< HEAD
TAX_RATE = 0.18
=======
TAX_RATE = 0.12
>>>>>>> feature/login
Fix it in four steps: edit the file into the correct final version, delete every marker line, git add the file,
then git commit. git merge --abort puts you back exactly where you started if you want to rethink.
Naming branches
feature/invoice-pdf new work
fix/gst-rounding bug fix
chore/upgrade-django maintenance
hotfix/payment-timeout urgent production fix
A consistent prefix makes a busy repository readable at a glance, and most tools group branches by it.
Common mistakes
- Committing directly to
main"just this once", then being unable to release without the half-done work. - Letting a branch run for three weeks; the merge becomes a day of conflict resolution.
- Deleting a branch with
-D(force) before it is merged, losing the commits. - Forgetting which branch you are on. Add the branch name to your shell prompt.
Practice
In a test repo, create feature/discount and feature/gst, and edit the same line of config.py on both.
Merge the first (a fast-forward), then merge the second and resolve the conflict. Finally, redo the exercise
with --no-ff and compare git log --oneline --graph --all.