Demo: creating and resolving a merge conflict
On This Lesson 11 topics
Lesson Overview
Reading about a conflict is not the same as meeting one. In this hands-on lesson you will create a merge conflict on purpose in the Bank Accounts project, resolve it by hand, and see the result in the history. You will also make a second planned mistake: committing the conflict markers while they are still in the file. Seeing the build break once, in a safe practice repository, is the best way to remember to check.
This lesson is the second half of the module lab (BEG-046-LAB1). It continues the project from the previous lesson, which already has a .gitignore and a few commits. If you did not do that lesson, any repository with a Java file and at least one commit will do. Your file contents will differ, so follow the steps, not the exact lines. Commands are for a terminal, because editor and IDE menus differ. All outputs below were produced with Git 2.44 and JDK 21; hashes will differ for you.
Learning Objectives
By the end of this lesson you will be able to:
- Create a conflict deliberately by changing the same line on two branches.
- Recognise that a conflicted merge is paused, and read
git statusand the conflict markers. - Resolve the conflict by editing the file to the intended final text.
- Explain what happens when markers, or both versions of a line, are left in.
- Finish a merge with
git addandgit commitand verify with a compile. - Read
git log --oneline --graphto see a merge.
Written Explanation
The plan
A conflict needs two branches that change the same line differently. The recipe:
- Start from a clean
mainwith a line that both branches will edit. - On a branch, change that line and commit.
- On
main, change the same line differently and commit. - Merge the branch into
main.
We will use a monthly fee in Account.java. The sentence to remember: a conflict is two people deciding different things about the same line.
Step 0: A shared starting point
Check you are on main with nothing pending:
git statusAdd one line to Account (below the balance field) and commit it, so that both branches start from it:
private double monthlyFee = 5.0;git commit -am "Add monthly fee field"(-a stages changes to already tracked files, then commits. It does not add new files.)
Step 1: Change the line on a branch
git switch -c add-fee-waiverEdit the line to private double monthlyFee = 0.0; (the fee is waived), then:
git commit -am "Waive monthly fee"Step 2: Change the same line on main
git switch mainEdit the same line to private double monthlyFee = 7.5;, then:
git commit -am "Raise monthly fee to 7.5"Both branches now contain a different decision about one line. The two lines of history have diverged, as in lesson L04.
Step 3: Merge and meet the conflict
git merge add-fee-waiverAuto-merging src/Account.java
CONFLICT (content): Merge conflict in src/Account.java
Automatic merge failed; fix conflicts and then commit the result.Git did not give up and did not lose anything; it paused. git status -s shows:
UU src/Account.javaUU means the file is unmerged, modified on both sides. Open the file:
public class Account {
private final String owner;
private double balance;
<<<<<<< HEAD
private double monthlyFee = 7.5;
=======
private double monthlyFee = 0.0;
>>>>>>> add-fee-waiver
public Account(String owner, double balance) {Above ======= is the current branch (main: 7.5). Below is add-fee-waiver (0.0). You can still stop here and run git merge --abort to go back to before the merge, if you want to start over.
Step 4: The planned mistake, commit with markers
A hurried developer sees the conflict, runs:
git add src/Account.java
git commit -m "Merge add-fee-waiver"[main 5d9be22] Merge add-fee-waiverGit accepted it. Git marks a conflict as resolved when you git add the file; it does not read the file to see whether the markers are gone. But the project no longer builds:
javac -d out src/*.javasrc\Account.java:4: error: illegal start of type
<<<<<<< HEAD
^
src\Account.java:4: error: > expected
<<<<<<< HEAD
^(The path separator appears as \ on Windows and / elsewhere. There are further error lines.) The compiler messages point at the first marker line. That is your clue: "illegal start of type" on a line starting with <<<<<<< means unresolved markers.
Step 5: Fix it, and a second trap
The quick-fix a beginner tries is to delete only the three marker lines. That leaves both versions of the line:
private double monthlyFee = 7.5;
private double monthlyFee = 0.0;and the compiler says:
src\Account.java:5: error: variable monthlyFee is already defined in class AccountThis shows what resolving means: you choose the final text. Both lines cannot stay. The team decides the fee is waived, so keep 0.0 and delete the 7.5 line. The file reads:
private double monthlyFee = 0.0;Check, then record the fix as a normal commit:
javac -d out src/*.java
git diff --stat
git commit -am "Resolve fee conflict: waive monthly fee, remove leftover markers" src/Account.java | 4 ----
1 file changed, 4 deletions(-)Confirm no markers remain anywhere:
git grep -n "<<<<<<<"It prints nothing (exit status 1 means no match). The earlier bad merge commit stays in history, with the fix right after it. That is honest and good enough for this stage. Rewriting history to hide the slip is an advanced topic, and for commits that other people already have it can cause trouble, so we do not do it here.
Step 6: See the merge
git log --oneline --graph* 115b825 Resolve fee conflict: waive monthly fee, remove leftover markers
* 5d9be22 Merge add-fee-waiver
|\
| * ed81b2e Waive monthly fee
* | 7f31231 Raise monthly fee to 7.5
|/
* 6683578 Add monthly fee field
* ab0fa5e Add deposit and withdraw
* 2948ea1 Add Main that creates one account
* 833d77b Add Account class with owner and balanceYou can see the shared commit at the bottom, the two diverging commits, the merge commit that joins them, and the fix on top. You can now delete the merged branch:
git branch -d add-fee-waiverThe correct order, summarised
When you do it carefully the sequence is shorter, with no broken commit:
git merge branch(conflict reported).git status(which files?).- Edit each file to the final text, with all markers removed.
- Compile (and run tests, when you have them).
git add file.git commit.
Examples
Example 1: Abort and retry (simple)
After the conflict in Step 3, you change your mind:
git merge --abort
git status -sThe status is clean and both branches are as before. You can retry the merge whenever you like. This is the safest way to look at a conflict: try, look, abort.
Example 2: Combining both sides (practical)
Suppose instead of one number, both branches added a different method at the same place in Account.java. Git marks both as conflicting. The right resolution is not to choose; it is to keep both methods and delete only the marker lines. Then compile, git add, and git commit. Resolving does not mean "pick a winner"; it means "write the correct final file".
Example 3: A conflict in a comment, not code (realistic)
A conflict can happen in any text file: a README line, a configuration file, a comment. The same markers appear, but the compiler will not warn you if you leave them in a .txt or .md file. For non-code files, rely on the habit of searching for <<<<<<< before committing: git grep -n "<<<<<<<" lists every tracked file that still contains the marker, including files the compiler never reads.
Backend Insight
Conflicts in backend projects often land in configuration (for example, a database setting or a port number) and in central classes that everyone touches. A wrong resolution in a configuration file may compile fine and only fail when the service starts in an environment you did not test. The compile check you used in this demo is the minimum; real teams add automated tests and review (BEG-047 and JNR-053) so a bad merge is caught before it reaches production.
Remember also that a conflict is often a decision, such as the fee above. Developers resolve it by talking, not by guessing. The commit message of the resolution is a good place to record the outcome ("waive monthly fee"), so the history explains why.
Common Mistakes
Mistake 1: Committing the markers
- Incorrect:
git addandgit commitright after the conflict message. - Correct: edit first, compile, then
git addandgit commit.
Mistake 2: Deleting only the marker lines
Leaving both versions of a conflicted line often causes a compile error (as in Step 5) or, worse, a silent logic error. Decide the final text.
Mistake 3: Resolving in the wrong place
Edit the file in your working folder, not in .git. Never edit anything inside .git.
Mistake 4: Panicking and deleting the repository
Nothing is lost during a conflict. git merge --abort goes back, and git status tells you what is left to do.
Exercises
Level A: Foundation
A1. Name the four steps needed to create a conflict on purpose.
Show solution A1
A1. Start from a shared commit; change a line on a branch and commit; change the same line differently on main and commit; merge the branch into main.
A2. What does UU in git status -s mean?
Show solution A2
A2. The file is unmerged: both sides modified it and the conflict is not resolved yet.
A3. Which command abandons a conflicted merge?
Show solution A3
A3. git merge --abort.
Level B: Application
B1. In a practice repository, create a conflict on one line of a file and resolve it by choosing the version from the branch you are merging in. List your commands.
Show solution B1
B1.
git switch -c feature
# edit line 3, then
git commit -am "Change line 3 on feature"
git switch main
# edit line 3 differently, then
git commit -am "Change line 3 on main"
git merge feature
# edit the file: keep the feature text, remove all marker lines
git add File.java
git commit -m "Merge feature: keep feature wording"B2. After resolving, how do you check that no marker lines remain in any tracked file? Name two checks (one command and one tool).
Show solution B2
B2. git grep -n "<<<<<<<" (and likewise for >>>>>>>), which prints nothing when clean; and javac on the Java files, which fails if markers remain. Searching in your editor works too.
B3. Explain why the commit that Git creates after git add of a file with markers is "valid" for Git but not for Java.
Show solution B3
B3. Git only needs git add to mark the file resolved; it does not parse the content. The Java compiler parses the content, and <<<<<<< is not Java syntax.
Level C: Challenge
C1. Both branches added a different method to the same class at the same spot. Describe the conflict you expect, the resolved file, and the commit message you would write.
Show solution C1
C1. Git shows both methods inside one conflict block, one above ======= and one below. Resolved file: both methods kept, markers deleted, formatting tidy. Message example: Merge add-fee-waiver: keep both fee methods.
C2. You committed a merge with markers and pushed on to two more commits before noticing. Describe how you repair it without rewriting history, and why that is acceptable.
Show solution C2
C2. Open the file in the latest commit, remove the markers (and keep the right text), compile, and commit the fix. The history keeps the bad commit but shows the repair. This is acceptable because rewriting history that others have already received can cause them problems; fixing forward is safer.
Mini Challenge
On your Bank Accounts repository, run the whole recipe on a different line from the one in the demo (for example, an interest rate or a maximum withdrawal). Do it twice. The first time make the planned mistake (commit with markers, watch the compiler complain) and repair it. The second time, in a fresh branch pair, do it correctly: abort the merge once to practise, then merge again, edit, compile, git add, git commit. Save the final git log --oneline --graph output.
Check your work: the graph shows the merge commit; git grep -n "<<<<<<<" prints nothing; the project compiles; your resolution message says what was decided.
Summary & Next Lesson
Key takeaways
- A conflict needs two branches changing the same line differently.
- The merge pauses;
git statusshowsUU, andgit merge --abortgoes back. - Resolve by writing the final text, with all marker lines removed and no duplicate lines.
- Git does not check for markers; compile and search before committing.
- A repair commit is a normal way to fix a bad merge commit.
git log --oneline --graphshows where the lines joined.
Next lesson
Next, in BEG-047, "Remotes, push, and pull" takes the history you built here and shares it between computers, starting with GitHub.
Self-check
- What do you need to make a conflict?
- Why can
git commitsucceed with markers in the file? - What error is typical when markers are left in a Java file?
- What does it mean to "resolve" a conflict?
- How do you see the merge in the history?
Show answers
- Two branches that change the same line in different ways, then a merge.
- Git only checks that you staged the file; it does not read its content.
illegal start of typeat a line starting with<<<<<<<.- To edit the file into the correct final text, with the markers removed, then
git addandgit commit. git log --oneline --graph.
References
- Pro Git book, "Basic Branching and Merging". It supports the conflict marker layout, the resolve steps (edit,
git add,git commit), and deleting merged branches withgit branch -d. - Git documentation,
git log. It supports--graphand--oneline. - Not verified from an official page: that Git does not check for leftover markers when you
git add(observed by running it), the behaviour ofgit merge --abort, and the advice about rewriting shared history. The demo and every output, including the compiler messages, come from a real run with Git 2.44 and JDK 21.
Practice
Apply this lesson with the module's lab, exercises and quiz.
Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.