Skip to content

Beginner · Git in depth · topic 11 of 53 · 30 min

Branching, merging and conflicts

Explanation

A branch is a movable label that points at a commit, so creating one is instant and cheap. You do each piece of work on its own branch and merge it back when it is ready. If the target branch has not moved, Git simply moves the label forward (a fast-forward); otherwise it creates a merge commit. When both sides changed the same lines, you get a conflict and decide the result yourself.

Why branches?

Imagine you are halfway through a new checkout page when an urgent bug is reported in production. Without branches, your half-finished code is mixed with the fix. With branches, the new page lives on its own line of work. You switch to a fresh branch from main, fix the bug, ship it, and come back to your page later. Nothing gets mixed up.

A branch is just a pointer

In Git, a branch is a tiny file that holds the ID of one commit. When you make a new commit on a branch, the branch label moves forward to the new commit. HEAD is another pointer: it says which branch you are on right now. That is why branches cost nothing to create, and why teams create many of them.

Think of it like this: Think of commits as stations on a railway line and branches as bookmarks with a station name written on them. Creating a branch is writing a new bookmark. Committing moves your bookmark one station further. HEAD is the "you are here" sticker on the bookmark you are using.
bash
git branch                     # list branches; * marks the current one
git switch -c feature/upi-pay  # create a branch and switch to it
# ...edit, add, commit...
git switch main                # go back to main
git branch -d feature/upi-pay  # delete a branch that is already merged
git branch -D old-experiment   # force-delete, even if not merged (careful)
git switch is the newer, clearer command. The older git checkout -b name does the same as git switch -c name.

If you check out a commit ID instead of a branch name, Git says you are in "detached HEAD" state. You can look around, but new commits there belong to no branch. If you want to keep them, create a branch with git switch -c name before you leave.

Merging: fast-forward

You merge a branch into the branch you are on. If main has had no new commits since you created your feature branch, Git does not need a new commit: it just moves the main label forward to the tip of the feature branch. This is a fast-forward merge, and the history stays a straight line.

Merging: three-way merge

If both branches have new commits, Git finds their common ancestor (the merge base) and combines the changes from both sides since that point. It then creates a merge commit, a commit with two parents. git log --graph draws this as two lines joining.

bash
git switch main
git merge feature/upi-pay
git log --oneline --graph --all
*   7d41c2e Merge branch 'feature/upi-pay'
|\
| * a19f0b3 Add UPI QR payment option
* | 5e2c8d1 Fix delivery charge for pin codes
|/
* 3f9c2ab Add checkout page
Use git merge --no-ff to force a merge commit even when a fast-forward is possible, if your team wants every feature visible as a merge.

Merge conflicts

A conflict happens when both branches changed the same lines of the same file, or one deleted a file the other edited. Git cannot guess which version is right, so it stops and writes both versions into the file between conflict markers.

output
def delivery_charge(total):
<<<<<<< HEAD
    return 0 if total >= 499 else 40
=======
    return 0 if total >= 599 else 49
>>>>>>> feature/new-pricing
Between <<<<<<< and ======= is your side (HEAD, the branch you are on, called "ours"). Between ======= and >>>>>>> is the incoming branch ("theirs").
  1. Run git status to see which files are in conflict ("both modified").
  2. Open each file and decide the correct result. It may be one side, the other, or a mix. Talk to the person who wrote the other side if unsure.
  3. Delete all three marker lines.
  4. Run your tests, then git add the file to mark it resolved.
  5. Run git commit (or git merge --continue) to finish the merge.
Tip: Changed your mind in the middle of a messy merge? git merge --abort puts everything back as it was before you started.

Common mistakes and how to fix them

Careful: Committing a file that still contains <<<<<<< or >>>>>>> markers breaks the build, because the markers are not valid code. Search for them before committing (git diff --check warns about leftover markers), and let CI run the tests.
  • Long-lived branches cause big, painful conflicts. Merge small branches often, and bring main into your branch regularly.
  • Working on main by accident? Create a branch where you are with git switch -c feature/x; your commits come with you. Then reset main to match the server version.
  • Deleted a branch that was not merged? Find its last commit ID in git reflog and create the branch again.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Branching, merging and conflicts · 1/8

Branching and merging

Branches let you work on several things at once without mixing them up.

Prefer a video by a teacher? Find free videos on “git branching merging merge conflict tutorial” on YouTube ↗

In real life: Two developers on a grocery delivery app in Hyderabad

Ravi changes the free-delivery limit from 499 to 599 rupees on a pricing branch. On another branch, Meena changes the delivery fee from 40 to 49 rupees in the same line. Meena merges first. When Ravi merges main into his branch, Git shows a conflict in pricing.py. Ravi checks with the product manager, keeps the 599 limit and the 49 fee, removes the markers, runs the tests, and commits the merge. The pull request now shows one clean, agreed change.

bash
git switch feature/new-pricing
git merge main            # CONFLICT (content): Merge conflict in pricing.py
# edit pricing.py, remove the markers
git add pricing.py
git commit                # finishes the merge

Practice (0/3 done)

Task 1 · Question

What does git switch -c feature/login do?

Task 2 · Code · Python

A merge can be a fast-forward only if the current branch tip is an ANCESTOR of the other branch tip (it is reachable by following parent links backwards). Write can_fast_forward(parents, current, other). parents is a dict mapping each commit ID to a list of its parent IDs (the first commit has an empty list). Return True if current can be reached from other by following parents, or if they are the same commit.

Task 3 · Code · Python

Write split_conflict(text) that takes a file with merge conflict markers and returns a tuple (ours, theirs): the whole file as it would be if you kept only your side, and as it would be with only their side. Lines outside a conflict go into both. A line starting with "<<<<<<<" begins our side, "=======" switches to their side, and ">>>>>>>" ends the conflict. Marker lines are never copied. Join the lines with "\n".

Quick quiz

Question 1

1.In Git, what is a branch?

Question 2

2.main has no new commits since feature was created. What does git merge feature (run on main) do by default?

Question 3

3.In a conflicted file, which part is between ======= and >>>>>>> feature?

Question 4

4.You fixed all conflicts in two files. What is the next step?

Question 5

5.What is "detached HEAD"?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

In Git, what is a branch?

Answer: A movable pointer to a commit

A branch is a small reference holding one commit ID. It moves forward when you commit.

main has no new commits since feature was created. What does git merge feature (run on main) do by default?

Answer: Moves main forward to the tip of feature (fast-forward)

When main is an ancestor of feature, Git just moves the pointer. Use --no-ff if you want a merge commit anyway.

In a conflicted file, which part is between ======= and >>>>>>> feature?

Answer: The version from the branch being merged in (theirs)

Our side (HEAD) is first; the incoming branch's version comes after =======.

You fixed all conflicts in two files. What is the next step?

Answer: git add the files, then git commit

Staging the files marks them resolved; the commit completes the merge. --abort would throw your work away.

What is "detached HEAD"?

Answer: HEAD points directly at a commit instead of a branch

New commits made there belong to no branch. Create one with git switch -c name to keep them.

What does git switch -c feature/cart do?Related

Answer: Creates a branch called feature/cart and moves you to it

-c means create. switch moves you to that branch so your new commits go there.

From Git and GitHub

In trunk-based development, how do teams merge unfinished features safely?Related

Answer: They hide unfinished work behind feature flags

Feature flags let half-built code be merged and deployed while switched off, so branches stay short-lived.

From Collaboration: remotes, pull requests and branching strategies

You ran git add on a file. Which command shows the changes that will go into the next commit?Related

Answer: git diff --staged

git diff --staged compares the staging area with the last commit. Plain git diff shows only unstaged changes.

From Git basics: repositories, staging and commits

You need one bug-fix commit from main in the release/3.1 branch, and nothing else. Which command fits?Related

Answer: git cherry-pick <fix-commit-id>

cherry-pick applies just that commit's changes as a new commit on the current branch.

From Rebase, undo and rescue: rebase, reset, revert, reflog and stash

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Git in depth” before its exam: Rebase, undo and rescue: rebase, reset, revert, reflog and stash, Collaboration: remotes, pull requests and branching strategies, Semantic versioning, tags and releases.
  2. Module 3 exam: Git in depth · 13 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Docker. 53 topics left in the course before the final exam.

← Previous: Git basics: repositories, staging and commits