Two Friends, One Trip Plan
Your class is planning a trip, and the plan is written on one sheet of paper. Priya takes the sheet and writes “Leave at 6 AM” under the timing line. Later, Karan takes the same sheet and writes “Leave at 8 AM” on the very same line. Now the sheet has a problem. The paper cannot decide which time is right. Someone has to read both, talk to the class, and choose.
Merging in Git is the same. Most of the time, Git combines two branches by itself, because people changed different parts of the files. But when two branches change the same line in different ways, Git stops and asks a human to decide. That is a merge conflict.
In the Branches lesson, Asha built new pages for the Utsav fest site on separate branches. Now she needs to bring that work back into main. And one day, her friend Ravi and she both edit the same line.
Merging a Branch: git merge
git merge takes the commits from another branch and brings them into the branch you are on. So the rule is: first switch to the branch that should receive the work (usually main), then name the branch you want to bring in.
# 1. Go to the branch that should RECEIVE the work
git switch main
# 2. Bring in the feature branch
git merge feature/registration-form
You will see something like this (your commit IDs will differ):
Updating a1b2c3d..e4f5a6b
Fast-forward
register.html | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 register.html
The word Fast-forward tells you which kind of merge happened. There are two kinds.
Fast-Forward vs Merge Commit
Fast-forward: main simply moves ahead
If main has not changed since you created the feature branch, there is nothing to combine. Git just slides the main label forward to the latest feature commit. No new commit is created.
Before the merge:
main: A---B
\
feature: C---D
After a fast-forward merge (main simply slides forward):
main, feature: A---B---C---D
Merge commit: joining two lines of work
If both branches got new commits (for example, Ravi added a contact page to main while Asha worked on the schedule), Git cannot just slide a label. It creates a new merge commit that has two parents and joins both lines together.
Before the merge (both branches have new commits):
main: A---B---E
\
feature: C---D
After the merge (Git creates a new merge commit M):
main: A---B---E-------M
\ /
feature: C-------D
When this happens, the output looks like this. (“ort” is the name of the method Git uses to combine changes; you do not need to remember it.)
Merge made by the 'ort' strategy.
schedule.html | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 schedule.html
If you did not give a message, Git may open your editor with a ready message such as Merge branch 'feature/schedule'. Save and close the editor to finish. Run git log --oneline --graph to see the joined history:
* 9f8e7d6 Merge branch 'feature/schedule'
|\
| * b2c3d4e Add schedule page
* | c3d4e5f Add contact page
|/
* a1b2c3d Add home page
| Fast-forward | Merge commit | |
|---|---|---|
| When it happens | Only the feature branch has new commits | Both branches have new commits |
| New commit created? | No | Yes, with two parents |
| History shape | A straight line | Two lines that join |
Why Merge Conflicts Happen
Git compares each branch with the commit where they split. If one branch changed the header and the other changed the footer, Git takes both changes happily. A conflict happens only when:
- both branches changed the same line (or lines right next to each other) in different ways, or
- one branch edited a file and the other deleted it.
A conflict is not an error and not your fault. It is Git being careful. It refuses to guess which version is right.
What a Conflict Looks Like
Here is how Asha and Ravi ended up with one. Both changed the fest date line in index.html:
# Ravi, on his branch, changes the date line to 15 February
git switch -c fix/fest-date
git commit -am "Change fest date to 15 February"
# Meanwhile on main, Asha changes the SAME line to 16 February
git switch main
git commit -am "Change fest date to 16 February"
# Now Asha tries to merge Ravi's branch
git merge fix/fest-date
You will see:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git has now paused the merge. It writes both versions into index.html, surrounded by conflict markers:
<h1>Utsav 2026</h1>
<<<<<<< HEAD
<p>Date: 16 February</p>
=======
<p>Date: 15 February</p>
>>>>>>> fix/fest-date
<footer>Contact the fest team</footer>
| Marker | Meaning |
|---|---|
<<<<<<< HEAD | Start of your version: the branch you are on (main) |
======= | The dividing line between the two versions |
>>>>>>> fix/fest-date | End of the incoming version: the branch you are merging in |
git status also tells you which files need attention:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
Resolving a Conflict, Step by Step
- Open the file listed under “Unmerged paths”.
- Decide what the correct result is. Keep your version, keep the incoming version, or combine both. If you are not sure, ask the teammate who wrote the other version. Asha calls Ravi, and they learn the fest actually runs on both days.
- Edit the text so it shows the final result, and delete all three marker lines. Nothing starting with
<<<<<<<,=======or>>>>>>>may stay. - Save the file and check it in the browser.
- Mark it resolved with
git add, then commit to finish the merge.
After step 3, Asha’s file looks like this:
<h1>Utsav 2026</h1>
<p>Date: 15 and 16 February</p>
<footer>Contact the fest team</footer>
Then she finishes the merge:
# Check that no conflict markers are left anywhere
git diff --check
# Tell Git the conflict in this file is fixed
git add index.html
# Finish the merge (Git suggests a message for you)
git commit -m "Merge fix/fest-date: fest runs on 15 and 16 February"
git diff --check prints nothing if all is well. If you forgot a marker, it points at the line. If several files have conflicts, repeat the steps for each one before you commit.
Using VS Code’s Conflict Buttons
VS Code makes conflicts much easier to read. When you open a file with conflict markers, it colours the two versions and shows small clickable links just above them:
- Accept Current Change: keep your version (the HEAD part).
- Accept Incoming Change: keep the version from the branch you are merging in.
- Accept Both Changes: keep both, one after the other. You often need to tidy the result by hand.
- Compare Changes: show the two versions side by side.
The buttons remove the markers for you. Newer versions also offer a Resolve in Merge Editor button, which opens a three-part view with the final result at the bottom. Whichever you use, read the result before you save. Then stage the file in the Source Control view (click the + next to it) and commit.
Accept Both is not always right. For the date line, accepting both would give two date lines on the page. Always read the final code and test the page before you commit.
Changed Your Mind? git merge --abort
If the conflict is confusing, or you merged the wrong branch, you can cancel the whole merge. Your files go back to how they were just before you typed git merge.
# Cancel the merge and go back to how things were before it
git merge --abort
# Check: everything is as it was
git status
You will see:
On branch main
nothing to commit, working tree clean
Take a break, talk to your teammate, and merge again when you are ready.
Real-Life Example: Two New Menu Links
Asha added a “Register” link to the menu on main. Imran added a “Sponsors” link on feature/sponsors, in the same spot. When Asha merges Imran’s branch, she gets:
<nav>
<<<<<<< HEAD
<a href="index.html">Home</a>
<a href="register.html">Register</a>
=======
<a href="index.html">Home</a>
<a href="sponsors.html">Sponsors</a>
>>>>>>> feature/sponsors
</nav>
Neither version is wrong: the menu needs both links. This is a “combine” conflict. Asha keeps the Home link once, adds both new links, deletes the markers, then runs git add and git commit:
<nav>
<a href="index.html">Home</a>
<a href="register.html">Register</a>
<a href="sponsors.html">Sponsors</a>
</nav>
Try these changes:
- Recreate this conflict in a practice folder and fix it with VS Code’s Accept Both Changes, then remove the repeated Home link by hand.
- Create a conflict, then cancel it with
git merge --abortand confirm withgit status. - Merge a branch where only the feature branch changed, and look for the word Fast-forward.
Habits That Prevent Conflicts
- Make small, frequent commits and merge branches soon. A branch that lives for three weeks collects many conflicts.
- Pull often. Bring the latest
maininto your work every day, so you see your teammates’ changes early. You will learn this in the Remotes lesson. - Talk to your teammates. A quick message like “I am editing the header today” avoids two people changing the same lines.
- Keep files focused. Separate files for pages and styles mean fewer people edit the same file at once.
Common Mistakes
- Merging from the wrong side.
git merge mainwhile on the feature branch brings main into the feature, not the other way round. Fix:git switch mainfirst, thengit merge feature/.... - Leaving markers in the file. A page that shows
=======to visitors is a common sight. Fix: search the file for<<<<<<<and rungit diff --checkbefore committing. - Forgetting git add after fixing. Git still thinks the file is in conflict. Fix: run
git addon each fixed file, thengit commit. - Deleting the other person’s work without asking. Clicking Accept Current every time is fast but may throw away a teammate’s fix. Fix: read both versions and ask if you are unsure.
- Merging with uncommitted changes. Commit your own work first, so a merge never mixes with half-done edits.
Practice Task: Create and Fix Your Own Conflict
The best way to stop fearing conflicts is to create one on purpose. Use a new practice folder so your real project is safe.
- Create a folder
merge-practice, rungit init -b main, add a filetrip.txtwith the lineTrip to: Mysoreand commit it. - Create a branch
plan/ooty, change the line toTrip to: Ootyand commit. - Switch to
main, change the same line toTrip to: Coorgand commit. - Merge
plan/ootyintomainand read the conflict markers. - Abort once with
git merge --abort, then merge again. - Resolve it so the file says
Trip to: Ooty, then add, commit, view the graph and delete the branch.
Show one possible answer (try it yourself first!)
# Setup: a practice repository
mkdir merge-practice
cd merge-practice
git init -b main
echo "Trip to: Mysore" > trip.txt
git add trip.txt
git commit -m "Add trip plan"
# 1. Branch and change the line
git switch -c plan/ooty
echo "Trip to: Ooty" > trip.txt
git commit -am "Change trip to Ooty"
# 2. Back on main, change the same line differently
git switch main
echo "Trip to: Coorg" > trip.txt
git commit -am "Change trip to Coorg"
# 3. Merge and see the conflict
git merge plan/ooty
git status
# 4. Try aborting once, then merge again
git merge --abort
git merge plan/ooty
# 5. Edit trip.txt in VS Code so it reads: Trip to: Ooty
# (delete all three marker lines), save, then:
git add trip.txt
git commit -m "Merge plan/ooty: the class chose Ooty"
# 6. Check the history and clean up
git log --oneline --graph --all
git branch -d plan/ooty
Key Takeaways
git merge namebrings another branch into the branch you are on. Switch to the receiving branch first.- A fast-forward moves the label ahead. A merge commit joins two lines of work that both moved on.
- A conflict happens when both branches change the same lines. It is normal, not a failure.
- Resolve by choosing or combining, deleting every marker, then
git addandgit commit. git merge --abortsafely cancels a merge that went wrong.- Small commits, frequent pulls and talking to teammates keep conflicts rare.