Chapter 6 of 10 · Git and GitHub for Beginners — Complete Free Tutorial
Resolving Merge Conflicts
A screen full of <<<<<<< symbols is the moment most beginners close the terminal. It should not: this sixth chapter of the Git and GitHub for Beginners series shows that a conflict is Git politely refusing to guess, and that resolving one is a short routine you can walk through calmly every single time.
Why conflicts happen
Git merges automatically when two branches touch different files — or even different regions of the same file. It stops only when both sides changed the same lines and no algorithm can decide which version you actually want. Picture a page where main updates the opening hours while a feature branch rewrites them for a holiday schedule: Git will not silently throw away either version. Instead it pauses, marks the file, and asks you to make a human decision. Nothing is broken, nothing is lost, and your repository is exactly as it was before the merge attempt — conflicts are a normal part of teamwork, not an error state.
Anatomy of a conflict marker
When Git halts, it writes the disputed region into your file wrapped in three marker lines:
<h2>Opening hours</h2>
<<<<<<< HEAD
<p>Open 8 am to 8 pm daily.</p>
=======
<p>Open 9 am to 9 pm, closed Mondays.</p>
>>>>>>> feature-online-orders
<<<<<<< HEADopens your version — the branch you had checked out (also called ours).=======separates the two sides.>>>>>>> feature-online-ordersopens the incoming version (theirs), labelled with the other branch's name.
Your entire job is to rewrite that region into the result you want — keep one side, keep the other, or write a third — and delete all three marker lines. The markers must never survive into the committed file; leaving them in is the one true conflict-resolution bug.
The four-step fix
- Survey — run
git status. It lists every file under “Unmerged paths”. Work through them one by one. - Edit — open each file, resolve each marked region, save.
- Mark resolved —
git add <file>. Hereaddmeans “this conflict is settled”, not “stage new work”. - Commit the merge —
git commitfinishes the merge with a default message you can keep as-is.
Repeat steps 2 and 3 for every file Git listed. When status reports “all conflicts fixed but you are still merging”, one final commit closes the process.
Tools that help (and the escape hatch)
- Take a whole side —
git checkout --ours <file>orgit checkout --theirs <file>keeps one version wholesale. Beware the naming: during a merge, ours is the branch you were on when you started it, which is not always the branch you expect. - Visual merging —
git mergetoolopens a three-pane editor if you prefer buttons to marker surgery. - Bail out safely —
git merge --abortrestores the exact pre-merge state, files included. Using it is not failure; it is a reset button. - See what arrived —
git log --oneline --graph -6shows how the two lines of history connect before you choose.
Keep this quick reference handy — it covers every move a conflict can demand:
| Goal | Command |
|---|---|
| List the conflicted files | git status |
| Keep your version of a file | git checkout --ours <file> |
| Keep the incoming version | git checkout --theirs <file> |
| Merge in a visual editor | git mergetool |
| Cancel the merge completely | git merge --abort |
Preventing conflicts before they happen
Conflicts grow with the distance between branches, so prevention is mostly discipline: pull the latest main before starting work, merge or rebase your branch at least daily, keep each branch to one focused change, and tell teammates which files you are touching. Two people rewriting the same function for a week guarantees a conflict; two-day branches rarely meet one.
git merge feature-online-orders
Expected output:
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
git status
Expected output:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit
git add index.html
git commit -m "Merge branch 'feature-online-orders' with new opening hours"
Expected output:
[main d4e5f6a] Merge branch 'feature-online-orders' with new opening hours
Common mistakes
- Committing with the markers still in the file — the merge “succeeds” and ships broken markup; search for
<<<<<before every conflict commit. - Forgetting to
git addthe resolved file — Git still considers the path unmerged and refuses to finish the commit. - Panicking and running
merge --abortafter already editing — abort discards your resolutions too; resolve properly or abort before you start, not halfway through. - Assuming a conflict means someone's work is deleted — both sides stay in history; you are only choosing what the next snapshot contains.
- Resolving alone in silence — if the “right” version is a product decision, ask the teammate whose code you are merging.
Practice checklist
- Create two branches, edit the same lines of one file on each, and merge to force a conflict on purpose.
- Read the markers aloud: identify ours, theirs, and the separating line.
- Resolve the file by hand, removing every marker, then run
git statusbefore staging. - Stage the file, commit, and confirm with
git log --oneline --graphthat both branches are joined. - Repeat the exercise and finish it with
git merge --abortto prove the reset button works.
What's next?
Local merging is now in your toolkit — but your teammates cannot see your work until it leaves your machine. Continue to Working with Remotes and GitHub to connect your repository to the world.
Frequently Asked Questions
Git is a distributed version control system: it records snapshots of your project over time, lets you jump back to any point, branch off to try ideas safely, and merge other people's work. It is the industry standard — nearly every developer job assumes basic Git fluency — and it is the best insurance you can have against lost or broken code.
Git is the tool that runs on your machine and stores history locally; it works fully offline. GitHub is one of many websites (GitLab, Bitbucket) that hosts Git repositories in the cloud and adds collaboration features: pull requests, code review, issues and CI. You can use Git forever without GitHub — GitHub needs Git to be useful.
A repository (repo) is your project folder plus a hidden .git directory containing the entire history: every commit, branch and tag. It can be local (only on your computer) or remote (cloned on GitHub). Deleting .git loses the history but keeps your files; deleting the files while keeping .git leaves history with nothing to show.
git add moves changed files into the staging area — your draft of the next snapshot — so you can review exactly what will be recorded. git commit writes the staged snapshot permanently with a message describing why the change happened. Two steps by design: stage deliberately, commit intentionally.
A branch is a movable pointer to a commit — creating one costs almost nothing. Use a branch for every unit of work (feature, fix, experiment): it keeps unfinished code out of main, lets you review changes in a pull request, and makes abandoning a bad idea as simple as deleting the branch.
It depends on where the change lives. Unstaged edits: git restore file. Staged but uncommitted: git restore --staged file. Committed but not pushed: git reset --soft to keep changes staged. Already pushed: git revert commit — it writes a new commit that undoes the old one instead of rewriting shared history. The undoing chapter covers each case with commands.
A conflict happens when two branches changed the same lines and Git cannot choose automatically. Your file gets marked up with <<<<<<<, ======= and >>>>>>> sections; you edit it down to the correct result, remove the markers, then git add and git commit. Conflicts are normal, small and entirely fixable — they are not an error state.
A pull request (PR) is GitHub's proposal to merge one branch into another. It shows the diff, runs checks, and lets teammates comment line by line before the code lands. It is the centre of modern collaboration: work on a branch, open a PR, review, approve, merge.
Write the subject in imperative mood, under about 50 characters: "Add email validation to signup". Explain why, not what, in the body when it is not obvious. Many teams use Conventional Commits (feat:, fix:, docs:) so tools can generate changelogs — the workflows chapter shows the format in practice.
Secrets (API keys, .env files), dependencies (node_modules), build output (dist), and operating-system junk (.DS_Store, Thumbs.db). A .gitignore file excludes them from the start; the common mistakes chapter shows what to do if something already slipped into history.