482 lines
10 KiB
Markdown
482 lines
10 KiB
Markdown
# Module 05: Merge Conflicts
|
|
|
|
## Learning Objectives
|
|
|
|
By the end of this module, you will:
|
|
- Understand what merge conflicts are and why they occur
|
|
- Identify merge conflicts in your repository
|
|
- Read and interpret conflict markers
|
|
- Resolve merge conflicts manually step-by-step
|
|
- Complete a merge after resolving conflicts
|
|
|
|
## Challenge
|
|
|
|
### Setup
|
|
|
|
Run the setup script to create your challenge environment:
|
|
|
|
```powershell
|
|
.\setup.ps1
|
|
```
|
|
|
|
This will create a `challenge/` directory with a repository that has a merge conflict waiting to happen!
|
|
|
|
### Your Task
|
|
|
|
You have a repository with a main branch and a feature branch called `update-config`. Both branches have modified the same configuration file in different ways, creating a merge conflict.
|
|
|
|
**Your mission:**
|
|
1. Attempt to merge the `update-config` branch into `main`
|
|
2. Git will tell you there's a conflict - don't panic!
|
|
3. Resolve the conflict by keeping BOTH settings (timeout AND debug)
|
|
4. Complete the merge
|
|
|
|
**Steps to follow:**
|
|
|
|
1. Navigate to the challenge directory: `cd challenge`
|
|
2. Make sure you're on main: `git branch`
|
|
3. Try to merge: `git merge update-config`
|
|
4. Git will report a conflict!
|
|
5. Open `config.py` in your text editor
|
|
6. Follow the step-by-step guide below to resolve it
|
|
7. Save the file, stage it, and commit
|
|
|
|
## What Are Merge Conflicts?
|
|
|
|
A **merge conflict** occurs when Git cannot automatically combine changes because both branches modified the same lines in the same file.
|
|
|
|
**Example scenario:**
|
|
```
|
|
main branch changes line 5: TIMEOUT = 30
|
|
feature branch changes line 5: DEBUG = True
|
|
```
|
|
|
|
Git doesn't know which one you want! So it asks you to decide.
|
|
|
|
**When do conflicts happen?**
|
|
- ✅ Two branches modify the same line(s)
|
|
- ✅ One branch deletes a file that another branch modifies
|
|
- ❌ Different files are changed (no conflict!)
|
|
- ❌ Different lines in the same file are changed (no conflict!)
|
|
|
|
## Step-by-Step: Resolving Your First Conflict
|
|
|
|
### Step 1: Attempt the Merge
|
|
|
|
```bash
|
|
cd challenge
|
|
git merge update-config
|
|
```
|
|
|
|
**You'll see:**
|
|
```
|
|
Auto-merging config.py
|
|
CONFLICT (content): Merge conflict in config.py
|
|
Automatic merge failed; fix conflicts and then commit the result.
|
|
```
|
|
|
|
**Don't panic!** This is normal. Git is just asking for your help.
|
|
|
|
---
|
|
|
|
### Step 2: Check What Happened
|
|
|
|
```bash
|
|
git status
|
|
```
|
|
|
|
**You'll see:**
|
|
```
|
|
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: config.py
|
|
```
|
|
|
|
This tells you that `config.py` needs your attention!
|
|
|
|
---
|
|
|
|
### Step 3: Open the Conflicted File
|
|
|
|
Open `config.py` in your text editor. You'll see something like this:
|
|
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
<<<<<<< HEAD
|
|
TIMEOUT = 30
|
|
=======
|
|
DEBUG = True
|
|
>>>>>>> update-config
|
|
```
|
|
|
|
**Let's break down what you're seeing:**
|
|
|
|
---
|
|
|
|
## Understanding Conflict Markers
|
|
|
|
Git has added special markers to show you both versions:
|
|
|
|
```python
|
|
<<<<<<< HEAD ← Start of YOUR version (current branch)
|
|
TIMEOUT = 30 ← What YOU have on main
|
|
======= ← Divider between versions
|
|
DEBUG = True ← What THEY have on update-config
|
|
>>>>>>> update-config ← End of THEIR version
|
|
```
|
|
|
|
**The three parts:**
|
|
|
|
1. **`<<<<<<< HEAD`** - Everything between here and `=======` is YOUR current branch's version
|
|
2. **`=======`** - This separates the two versions
|
|
3. **`>>>>>>> update-config`** - Everything between `=======` and here is the INCOMING branch's version
|
|
|
|
---
|
|
|
|
## Step 4: Decide What to Keep
|
|
|
|
You have three options:
|
|
|
|
**Option A: Keep YOUR version (main)**
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
TIMEOUT = 30
|
|
```
|
|
|
|
**Option B: Keep THEIR version (update-config)**
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
DEBUG = True
|
|
```
|
|
|
|
**Option C: Keep BOTH (this is what we want!)**
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
TIMEOUT = 30
|
|
DEBUG = True
|
|
```
|
|
|
|
---
|
|
|
|
## Step 5: Edit the File to Resolve the Conflict
|
|
|
|
**What the file looks like NOW (with conflict markers):**
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
<<<<<<< HEAD
|
|
TIMEOUT = 30
|
|
=======
|
|
DEBUG = True
|
|
>>>>>>> update-config
|
|
```
|
|
|
|
**What you need to do:**
|
|
|
|
1. **Delete** the line `<<<<<<< HEAD`
|
|
2. **Keep** the line `TIMEOUT = 30`
|
|
3. **Delete** the line `=======`
|
|
4. **Keep** the line `DEBUG = True`
|
|
5. **Delete** the line `>>>>>>> update-config`
|
|
|
|
**What the file should look like AFTER (conflict resolved):**
|
|
```python
|
|
# config.py - Application configuration
|
|
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
TIMEOUT = 30
|
|
DEBUG = True
|
|
```
|
|
|
|
**Save the file!**
|
|
|
|
---
|
|
|
|
## Step 6: Mark the Conflict as Resolved
|
|
|
|
Tell Git you've fixed the conflict by staging the file:
|
|
|
|
```bash
|
|
git add config.py
|
|
```
|
|
|
|
This tells Git: "I've resolved the conflict in this file, it's ready to be committed."
|
|
|
|
---
|
|
|
|
## Step 7: Check Your Status
|
|
|
|
```bash
|
|
git status
|
|
```
|
|
|
|
**You should see:**
|
|
```
|
|
On branch main
|
|
All conflicts fixed but you are still merging.
|
|
(use "git commit" to conclude merge)
|
|
|
|
Changes to be committed:
|
|
modified: config.py
|
|
```
|
|
|
|
Great! Git knows the conflict is resolved and is ready for you to complete the merge.
|
|
|
|
---
|
|
|
|
## Step 8: Complete the Merge
|
|
|
|
```bash
|
|
git commit
|
|
```
|
|
|
|
Git will open your editor with a default merge message:
|
|
```
|
|
Merge branch 'update-config'
|
|
|
|
# Conflicts:
|
|
# config.py
|
|
```
|
|
|
|
You can keep this message or customize it. Save and close the editor.
|
|
|
|
**Or use a one-liner:**
|
|
```bash
|
|
git commit -m "Merge update-config: resolve config conflict"
|
|
```
|
|
|
|
---
|
|
|
|
## Step 9: Verify the Merge
|
|
|
|
```bash
|
|
git log --oneline --graph
|
|
```
|
|
|
|
You should see your merge commit!
|
|
|
|
```bash
|
|
cat config.py
|
|
```
|
|
|
|
Verify the file has BOTH settings and NO conflict markers!
|
|
|
|
---
|
|
|
|
## Visual Summary: Before and After
|
|
|
|
### Before Resolution (WRONG ❌)
|
|
```python
|
|
# config.py
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
<<<<<<< HEAD
|
|
TIMEOUT = 30
|
|
=======
|
|
DEBUG = True
|
|
>>>>>>> update-config
|
|
```
|
|
**This will NOT run! Conflict markers are syntax errors!**
|
|
|
|
### After Resolution (CORRECT ✅)
|
|
```python
|
|
# config.py
|
|
APP_NAME = "My Application"
|
|
VERSION = "1.0.0"
|
|
TIMEOUT = 30
|
|
DEBUG = True
|
|
```
|
|
**Clean code, no markers, both settings preserved!**
|
|
|
|
---
|
|
|
|
## Common Mistakes to Avoid
|
|
|
|
### ❌ Mistake 1: Forgetting to Remove Conflict Markers
|
|
```python
|
|
TIMEOUT = 30
|
|
======= ← Still has conflict marker!
|
|
DEBUG = True
|
|
```
|
|
**This is invalid Python code and will crash!**
|
|
|
|
### ❌ Mistake 2: Committing Without Staging
|
|
```bash
|
|
# Wrong order:
|
|
git commit # Error! File not staged
|
|
|
|
# Correct order:
|
|
git add config.py # Stage first
|
|
git commit # Then commit
|
|
```
|
|
|
|
### ❌ Mistake 3: Only Keeping One Side When You Need Both
|
|
```python
|
|
# If the task asks for BOTH settings, this is wrong:
|
|
TIMEOUT = 30
|
|
# Missing DEBUG = True
|
|
```
|
|
|
|
---
|
|
|
|
## Useful Commands Reference
|
|
|
|
```bash
|
|
# During a conflict
|
|
git status # See which files have conflicts
|
|
git diff # See the conflict in detail
|
|
|
|
# Resolving
|
|
git add <file> # Mark file as resolved
|
|
git commit # Complete the merge
|
|
|
|
# If you want to start over
|
|
git merge --abort # Cancel the merge, go back to before
|
|
|
|
# After resolving
|
|
git log --oneline --graph # See the merge commit
|
|
```
|
|
|
|
---
|
|
|
|
## Real-World Conflict Resolution Workflow
|
|
|
|
**Here's what you'll do every time you have a conflict:**
|
|
|
|
```bash
|
|
# 1. Attempt the merge
|
|
git merge feature-branch
|
|
# → Git says: "CONFLICT! Fix it!"
|
|
|
|
# 2. Check what's wrong
|
|
git status
|
|
# → Shows which files have conflicts
|
|
|
|
# 3. Open the file, find the markers
|
|
# <<<<<<< HEAD
|
|
# your version
|
|
# =======
|
|
# their version
|
|
# >>>>>>> branch
|
|
|
|
# 4. Edit the file to resolve
|
|
# Remove the markers, keep what you need
|
|
|
|
# 5. Stage the resolved file
|
|
git add config.py
|
|
|
|
# 6. Complete the merge
|
|
git commit -m "Resolve conflict in config.py"
|
|
|
|
# 7. Celebrate! 🎉
|
|
```
|
|
|
|
---
|
|
|
|
## What If You Get Stuck?
|
|
|
|
### Option 1: Abort the Merge
|
|
```bash
|
|
git merge --abort
|
|
```
|
|
This puts everything back to how it was before the merge. You can try again!
|
|
|
|
### Option 2: Ask for Help
|
|
```bash
|
|
git status # See what's going on
|
|
git diff # See the conflict details
|
|
```
|
|
|
|
---
|
|
|
|
## Pro Tips
|
|
|
|
✅ **Use `git status` constantly** - It tells you exactly what to do next
|
|
|
|
✅ **Search for `<<<<<<<`** - Your editor's search function can find all conflicts quickly
|
|
|
|
✅ **Test after resolving** - Make sure your code still works!
|
|
|
|
✅ **Read both sides carefully** - Sometimes you need parts from each version
|
|
|
|
✅ **Take your time** - Conflicts are not a race. Understand what changed and why.
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
Once you've resolved the conflict and completed the merge, verify your solution:
|
|
|
|
```powershell
|
|
.\verify.ps1
|
|
```
|
|
|
|
The verification will check that:
|
|
- ✅ The merge conflict was resolved
|
|
- ✅ The merge was completed successfully
|
|
- ✅ BOTH settings are in the config file (TIMEOUT and DEBUG)
|
|
- ✅ NO conflict markers remain
|
|
- ✅ The merge commit exists in history
|
|
|
|
---
|
|
|
|
## Need to Start Over?
|
|
|
|
If you want to reset the challenge and start fresh:
|
|
|
|
```powershell
|
|
.\reset.ps1
|
|
```
|
|
|
|
---
|
|
|
|
## What You've Learned
|
|
|
|
🎉 **Congratulations!** You can now:
|
|
- Recognize when a merge conflict occurs
|
|
- Read and understand conflict markers
|
|
- Edit files to resolve conflicts
|
|
- Stage resolved files with `git add`
|
|
- Complete a merge with `git commit`
|
|
|
|
**This is a critical skill!** Every developer encounters merge conflicts. Now you know exactly what to do when they happen.
|
|
|
|
---
|
|
|
|
## Quick Reference Card
|
|
|
|
**When you see a conflict:**
|
|
|
|
1. **Don't panic** ✅
|
|
2. **Run `git status`** to see which files
|
|
3. **Open the file** in your editor
|
|
4. **Find the markers** (`<<<<<<<`, `=======`, `>>>>>>>`)
|
|
5. **Decide what to keep** (one side, other side, or both)
|
|
6. **Remove ALL markers** (the `<<<<<<<`, `=======`, `>>>>>>>` lines)
|
|
7. **Save the file**
|
|
8. **Stage it** (`git add filename`)
|
|
9. **Commit** (`git commit`)
|
|
10. **Verify** (`git status`, `git log --oneline --graph`)
|
|
|
|
**Remember:** The conflict markers are NOT valid code - they MUST be removed!
|