feat: make merge-conflicts more explicit
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Module 06: Merge Conflicts
|
||||
# Module 05: Merge Conflicts
|
||||
|
||||
## Learning Objectives
|
||||
|
||||
@@ -6,101 +6,476 @@ 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
|
||||
- Resolve merge conflicts manually step-by-step
|
||||
- Complete a merge after resolving conflicts
|
||||
|
||||
## Challenge Description
|
||||
## 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 task is to:
|
||||
**Your mission:**
|
||||
1. Attempt to merge the `update-config` branch into `main`
|
||||
2. Identify and understand the merge conflict
|
||||
3. Resolve the conflict by keeping both the timeout setting from `main` AND the debug setting from `update-config`
|
||||
4. Complete the merge with an appropriate commit message
|
||||
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
|
||||
|
||||
## Key Concepts
|
||||
**Steps to follow:**
|
||||
|
||||
### What Are Merge Conflicts?
|
||||
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
|
||||
|
||||
A merge conflict occurs when Git cannot automatically combine changes from two branches because they modify the same part of the same file in different ways. When this happens, Git pauses the merge and asks you to manually resolve the conflict.
|
||||
## What Are Merge Conflicts?
|
||||
|
||||
### Conflict Markers
|
||||
|
||||
When a conflict occurs, Git adds special markers to the affected files:
|
||||
A **merge conflict** occurs when Git cannot automatically combine changes because both branches modified the same lines in the same file.
|
||||
|
||||
**Example scenario:**
|
||||
```
|
||||
<<<<<<< HEAD
|
||||
Your current branch's changes
|
||||
=======
|
||||
The incoming branch's changes
|
||||
>>>>>>> branch-name
|
||||
main branch changes line 5: TIMEOUT = 30
|
||||
feature branch changes line 5: DEBUG = True
|
||||
```
|
||||
|
||||
- `<<<<<<< HEAD`: Marks the beginning of your current branch's version
|
||||
- `=======`: Separates the two versions
|
||||
- `>>>>>>> branch-name`: Marks the end of the incoming branch's version
|
||||
Git doesn't know which one you want! So it asks you to decide.
|
||||
|
||||
### Resolving Conflicts
|
||||
**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!)
|
||||
|
||||
To resolve a conflict:
|
||||
1. Open the conflicted file in your editor
|
||||
2. Look for the conflict markers
|
||||
3. Decide which changes to keep (you can keep one side, the other, or combine both)
|
||||
4. Remove the conflict markers
|
||||
5. Stage the resolved file with `git add`
|
||||
6. Complete the merge with `git commit`
|
||||
## Step-by-Step: Resolving Your First Conflict
|
||||
|
||||
## Useful Commands
|
||||
### Step 1: Attempt the Merge
|
||||
|
||||
```bash
|
||||
# Merge a branch (may result in conflicts)
|
||||
git merge <branch-name>
|
||||
|
||||
# Check the status during a conflict
|
||||
git status
|
||||
|
||||
# See which files have conflicts
|
||||
git diff --name-only --diff-filter=U
|
||||
|
||||
# View the conflict in detail
|
||||
git diff
|
||||
|
||||
# After resolving, stage the file
|
||||
git add <file>
|
||||
|
||||
# Complete the merge
|
||||
git commit
|
||||
|
||||
# If you want to abort the merge
|
||||
git merge --abort
|
||||
|
||||
# Visualize the branch history
|
||||
git log --oneline --graph --all
|
||||
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
|
||||
|
||||
Run the verification script to check your solution:
|
||||
Once you've resolved the conflict and completed the merge, verify your solution:
|
||||
|
||||
```bash
|
||||
```powershell
|
||||
.\verify.ps1
|
||||
```
|
||||
|
||||
The verification will check that:
|
||||
- The merge conflict was resolved
|
||||
- The merge was completed successfully
|
||||
- Both configuration settings were preserved correctly
|
||||
- The commit history shows the merge
|
||||
- ✅ 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
|
||||
|
||||
## Tips
|
||||
---
|
||||
|
||||
- Don't panic when you see a conflict - it's a normal part of working with Git
|
||||
- Read the conflict markers carefully to understand both versions
|
||||
- You can use `git status` to see which files have conflicts
|
||||
- Always test your code after resolving conflicts to ensure it still works
|
||||
- The conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) must be completely removed from the final file
|
||||
## Need to Start Over?
|
||||
|
||||
## What You'll Learn
|
||||
If you want to reset the challenge and start fresh:
|
||||
|
||||
Merge conflicts are inevitable when working on a team or even when working alone across multiple branches. Learning to resolve them confidently is an essential Git skill. This module teaches you the fundamentals of conflict resolution that you'll use throughout your development career.
|
||||
```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!
|
||||
|
||||
@@ -128,7 +128,8 @@ if ($parentCount -ne 2) {
|
||||
}
|
||||
|
||||
# Check that both branches are merged
|
||||
$branches = git branch --merged 2>$null
|
||||
$branches = git branch --merged update-config 2>$null
|
||||
Write-Host "$branches $($branches -notmatch 'update-config')"
|
||||
if ($branches -notmatch "update-config") {
|
||||
Write-Host "[FAIL] The 'update-config' branch was not merged." -ForegroundColor Red
|
||||
Set-Location ..
|
||||
|
||||
Reference in New Issue
Block a user