انتقل إلى المحتوى
أمين أبوزيد
منشورBEG-046-L05

الدمج والتعارضات

  • الدرس 5 من 8
  • 10 دقيقة قراءة
  • مبتدئ
في هذا الدرس 11 موضوعات

هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.

Lesson Overview

A branch is only useful if its work can come back. Merging brings the commits of one branch into another, usually a finished feature into main. Most of the time Git does this by itself in a second. Sometimes it cannot, because both branches changed the same lines in different ways and Git will not guess which version you want. That situation is a merge conflict.

Conflicts frighten beginners, but they are a normal part of team work. A conflict is Git saying, "I need a human decision here". In this lesson you will learn the two kinds of merge, how to read the conflict markers Git writes in your file, and the exact steps to resolve a conflict by hand: edit, remove the markers, add, commit.

You need two branches and the basics from lessons L02 to L04. Outputs come from Git 2.44; hashes and some wording may differ for you. The Java files are tiny, but the process is the same for big ones.

Learning Objectives

By the end of this lesson you will be able to:

  • Merge a branch into the current branch with git merge.
  • Tell a fast-forward merge from a merge that creates a merge commit.
  • Explain when and why a merge conflict happens.
  • Read the markers <<<<<<<, =======, and >>>>>>> and say which side each part belongs to.
  • Resolve a conflict by hand and finish the merge with git add and git commit.
  • Abort a merge with git merge --abort.
  • Describe why committing marker lines breaks a Java build.

Written Explanation

The basic rule: merge into the branch you are on

bash
git switch main
git merge add-interest

The first command makes main the current branch. The second brings the commits of add-interest into it. Always switch to the branch that should receive the work first. add-interest itself is not changed.

Two kinds of merge

1. Fast-forward. If main has not moved since you created the branch, the branch is simply "ahead" of main. Git just slides the main pointer forward. No new commit is created.

text
Updating 728269d..f78efde
Fast-forward
 Hello.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

2. A merge with a merge commit. If both branches have new commits (they have diverged, as in lesson L04), Git combines both lines of work and records a merge commit, which has two parents. Git compares the two tips with their last common ancestor (a "three-way merge") and joins the changes.

text
Merge made by the 'ort' strategy.
 B.java | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 B.java
text
*   ed8f94e Merge branch 'feature'
|\  
| * 4b9cb47 Add B on feature
* | 38db0ef Edit A on main
|/  
* 42d209f Add A

The top commit is the merge commit, and its two lines join below it. Here the branches changed different files, so Git needed no help. It also works when two branches changed different parts of the same file. If your terminal opens a text editor to confirm a merge message, accept the default, save, and close it; this depends on your setup.

When Git cannot decide: a conflict

Suppose Account.java has private double rate = 0.01;. On branch add-interest you commit a change to 0.03. On main you commit a change to 0.02. Both changed the same line. Now:

bash
git switch main
git merge add-interest
text
Auto-merging Account.java
CONFLICT (content): Merge conflict in Account.java
Automatic merge failed; fix conflicts and then commit the result.

The merge is now paused halfway. Nothing is broken and nothing is lost. git status explains where you are:

text
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:   Account.java

Reading the conflict markers

Open Account.java. Git has written both versions into the file:

text
public class Account {
<<<<<<< HEAD
    private double rate = 0.02;
=======
    private double rate = 0.03;
>>>>>>> add-interest
}
  • <<<<<<< HEAD starts the conflict. Everything between it and ======= is your current branch (here main).
  • ======= is the divider.
  • Everything between ======= and >>>>>>> add-interest is the branch being merged in.
  • >>>>>>> add-interest ends the conflict.

These three lines are text Git inserted. They are not code. A file can contain several conflict blocks; resolve each one.

Resolving a conflict by hand

  1. Decide the correct final text. Keep one side, keep the other, combine them, or write something new. Git cannot know; you (and perhaps your teammate) decide. Suppose the team agrees on 3 percent.
  2. Edit the file so it contains exactly that final text, with all three marker lines removed:
java
public class Account {
    private double rate = 0.03;
}
  1. Stage the file to tell Git the conflict is resolved:
bash
git add Account.java
  1. Commit to finish the merge:
bash
git commit

Git proposes a message such as Merge branch 'add-interest'. You can accept it or add a short line on how you resolved the conflict. (git commit -m "Merge branch 'add-interest'" also works.) Run git log --oneline --graph to see the merge commit with its two parents.

Before step 3, compile and test. A resolved file must be valid Java.

Changing your mind: git merge --abort

If you start a merge and decide it is the wrong moment, run:

bash
git merge --abort

Git returns to the state before the merge. git status is clean again. Use it freely when you are unsure.

Why leftover markers break the build

Git does not check that you removed the markers. It will happily commit a file that still contains them. But the markers are not valid Java. Compiling such a file gives errors like:

text
Account.java:2: error: illegal start of type
<<<<<<< HEAD
^

So: after resolving, search the file for <<<<<<<, =======, and >>>>>>>, then compile before you commit.

Reducing conflicts

Conflicts are normal, but you can make them rarer and smaller: keep branches short, merge main into your branch regularly, make small focused commits, and talk to teammates about who edits which file. IDEs (for example IntelliJ IDEA) offer a merge tool that shows the two sides next to each other; the menus differ by IDE and version. Doing it by hand first shows you what those tools do.

Examples

Example 1: A fast-forward merge (simple)

bash
git switch -c greeting
# edit Hello.java, then:
git commit -am "Print a full greeting"
git switch main
git merge greeting

main had no new commits, so Git reports Fast-forward. git log --oneline is one straight line. Afterwards you can delete the branch:

bash
git branch -d greeting

Example 2: A merge with no conflict (practical)

feature added B.java; main edited A.java. After git switch main and git merge feature, Git says Merge made by the 'ort' strategy and creates a merge commit. The files are different, so no decision was needed. git log --oneline --graph shows the two lines joining. Branch work is combined, history is honest about what happened in parallel, and you did nothing special.

Example 3: Resolving a real conflict (realistic)

Two people changed the interest rate line as described above. The merge reports a conflict. You:

  1. Run git status and see both modified: Account.java.
  2. Open Account.java, see the markers, agree with your teammate on 3 percent, and edit the file to one line with no markers.
  3. Compile with javac Account.java (no errors).
  4. Run git add Account.java.
  5. Run git commit and accept the default message.
  6. Run git log --oneline --graph and confirm the merge commit.

Total time: about two minutes, and now you have done it once by hand.

Backend Insight

In a backend team, several people change the same service at the same time: one adds a field to a controller, another changes validation in the same class. Conflicts happen in shared files such as configuration, build files, and central classes. A conflict in a business rule, like the interest rate above, is not a text problem. It is a decision, and the correct resolution may need a conversation with the person who wrote the other change.

That is why resolving by hand matters. Merging the wrong side silently can change how money is calculated. Always compile and run the tests (when you have them) after a merge, before sharing the result. The pull-request workflow in BEG-047 and JNR-053 wraps this process with reviews, but under the hood it is the same merge you did today.

Common Mistakes

Mistake 1: Treating a conflict as a failure

  • Incorrect: "I broke Git."
  • Correct: "Two changes touched the same lines and I must choose the final text."

Mistake 2: Leaving the markers in the file

  • Incorrect: running git add and git commit without editing.
  • Correct: edit first, remove all three marker lines, then add and commit.

Why it happens: Git lets you commit them. How to avoid it: search for <<<<<<< and compile before committing.

Mistake 3: Merging in the wrong direction

If you run git merge while on the feature branch, you merge main into the feature, not the other way round. Check git status (it prints On branch ...) before merging.

Mistake 4: Accepting one side without reading

Choosing "my version" blindly can discard a teammate's fix. Read both sides before deciding.

Exercises

Level A: Foundation

A1. Which branch receives the changes when you run git merge feature while on main?

أظهر الحل A1

A1. main, the branch you are on. feature is unchanged.

A2. What are the three marker lines Git writes in a conflicted file?

أظهر الحل A2

A2. <<<<<<< (start, followed by HEAD or the current branch label), ======= (divider), and >>>>>>> (end, followed by the other branch's name).

A3. Which command abandons a merge that is in progress?

أظهر الحل A3

A3. git merge --abort.

Level B: Application

B1. Create a branch greeting, commit a change to a file, switch to main, and merge. Which kind of merge happened, and how do you know?

أظهر الحل B1

B1. A fast-forward merge, if main had no new commits. Git prints Fast-forward and the log is a straight line.

B2. Given this conflicted file, write the resolved version that keeps the larger limit, and say what the two sides were:

text
<<<<<<< HEAD
    private int limit = 500;
=======
    private int limit = 1000;
>>>>>>> raise-limit
أظهر الحل B2

B2. The part above ======= is the current branch (main): 500. The part below is raise-limit: 1000. Resolved:

java
    private int limit = 1000;

The three marker lines are removed.

B3. After editing a conflicted file, list the two Git commands you must run, in order.

أظهر الحل B3

B3. git add <file> then git commit.

Level C: Challenge

C1. Create a conflict on purpose: on branch feature change line 3 of a file to one text and commit; on main change line 3 to another text and commit; merge. Resolve it by hand. List the commands you ran and what git log --oneline --graph shows at the end.

أظهر الحل C1

C1. Example sequence:

bash
git switch -c feature
# edit line 3, then
git commit -am "Set text to feature version"
git switch main
# edit line 3 differently, then
git commit -am "Set text to main version"
git merge feature        # CONFLICT
# edit the file: keep the final text, delete the three markers
javac File.java          # check it compiles, if it is Java
git add File.java
git commit               # accept the default merge message
git log --oneline --graph

The log shows the merge commit at the top with two lines joining below it.

C2. You resolved a conflict, committed, and javac now reports illegal start of type at a line that begins with <<<<<<<. What happened, and how do you repair it so the history stays clean?

أظهر الحل C2

C2. The markers were committed into the file. Open the file, keep the right text, remove the three marker lines, compile, then git add and git commit again with a message such as "Remove leftover merge markers". The earlier commit stays in history; that is acceptable here, since the fix is clearly recorded.

Mini Challenge

Build a small conflict with three different lines changed on both branches: two of them in separate places and one in the same line. Merge and observe which lines Git joins by itself and which it marks as a conflict. Resolve it, compile, and commit.

Check your work: only the same-line change produced markers; the file compiles; there are no marker lines left (search the file for <<<<<<<); and the log shows the merge commit.

Summary & Next Lesson

Key takeaways

  • git merge branch brings that branch into the one you are on; switch to the receiving branch first.
  • A fast-forward just moves the pointer; diverged branches get a merge commit.
  • A conflict means both branches changed the same lines. It is normal.
  • Markers show the current branch above ======= and the incoming branch below.
  • Resolve: edit to the right final text, remove markers, git add, git commit.
  • git merge --abort returns to before the merge.

Next lesson

Next is ".gitignore": how to keep compiled output, IDE folders, and secrets out of your repository.

Self-check

  1. What does Git need you to decide in a conflict?
  2. Which side is above =======?
  3. Which two commands finish a resolved conflict?
  4. What does a fast-forward merge create?
  5. Why can committed markers break the build?
أظهر الإجابات
  1. Which final text the file should have (keep one side, both, or something new).
  2. The current branch (HEAD).
  3. git add file and git commit.
  4. No new commit; it only moves the branch pointer forward.
  5. They are not valid Java, so the compiler reports errors.

References

  • Pro Git book, "Basic Branching and Merging". It supports fast-forward merges, merge commits from three-way merges, the conflict marker layout (current branch above =======, merged branch below), and the steps to resolve: edit, git add, git commit.
  • Not verified from an official page: the output text (Git 2.44, produced by running the commands), that git merge --abort restores the pre-merge state, and the claim that Git commits files that still contain markers; I observed that in a test but did not find it stated in the docs I fetched.

التطبيق

طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.

المختبر والتمارين الاختبار

تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.

اكتب للبحث في المستويات والمراحل والوحدات والدروس.