Files
git-workshop/01_essentials/05-merge-conflicts/README.md
2026-01-07 23:03:18 +01:00

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!