# Module 04: Merge Conflicts ## Learning Objectives By the end of this module, you will: - Understand what merge conflicts are and why they occur - Use `git diff` to discover changes between branches - Identify merge conflicts in your repository - Read and interpret conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) - Resolve merge conflicts manually - Complete a merge after resolving conflicts ## Setup Create the challenge environment: ```bash .\setup.ps1 ``` This creates a repository with two feature branches that have conflicting changes. ## Overview A **merge conflict** occurs when Git cannot automatically combine changes because both branches modified the same part of the same file in different ways. **When do conflicts happen?** - ✅ Two branches modify the same lines in a file - ✅ One branch deletes a file that another branch modifies - ✅ Complex changes Git can't merge automatically - ❌ Different files are changed (no conflict!) - ❌ Different parts of the same file are changed (no conflict!) **Don't fear conflicts!** They're a normal part of collaborative development. Git just needs your help to decide what the final code should look like. ## Your Task ### Part 1: Discover the Changes Before merging, it's good practice to see what each branch changed: ```bash cd challenge # Check which branch you're on git branch # View all branches git branch --all ``` You'll see three branches: `main`, `add-timeout`, and `add-debug`. **Discover what each branch changed:** ```bash # Compare main with add-timeout git diff main add-timeout # Compare main with add-debug git diff main add-debug # Compare the two feature branches directly git diff add-timeout add-debug ``` **What did you discover?** - Both branches modified `config.json` - They both added a line in the same location (after `"port": 3000`) - One adds `"timeout": 5000` - The other adds `"debug": true` This is a recipe for a conflict! ### Part 2: Merge the First Branch (No Conflict) Let's merge `add-timeout` first: ```bash # Make sure you're on main git switch main # Merge the first branch git merge add-timeout ``` ✅ **Success!** This merge works because main hasn't changed since add-timeout was created. ```bash # View the updated config cat config.json # Check the history git log --oneline --graph --all ``` ### Part 3: Try to Merge the Second Branch (Conflict!) Now let's try to merge `add-debug`: ```bash # Still on main git merge add-debug ``` 💥 **Boom!** You'll see: ``` Auto-merging config.json CONFLICT (content): Merge conflict in config.json Automatic merge failed; fix conflicts and then commit the result. ``` **Don't panic!** This is expected. Git is asking for your help. ### Part 4: Check the Status ```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 ..." to mark resolution) both modified: config.json ``` This tells you that `config.json` needs your attention! ### Part 5: Open and Examine the Conflicted File Open `config.json` in your text editor: ```bash # On Windows notepad config.json # Or use VS Code code config.json ``` You'll see special **conflict markers**: ```json { "app": { "name": "MyApp", "version": "1.0.0", "port": 3000, <<<<<<< HEAD "timeout": 5000 ======= "debug": true >>>>>>> add-debug } } ``` ### Part 6: Understand the Conflict Markers Let's break down what you're seeing: ``` <<<<<<< HEAD "timeout": 5000 ← Your current branch (main, which has add-timeout merged) ======= "debug": true ← The branch you're merging (add-debug) >>>>>>> add-debug ``` **What each marker means:** - `<<<<<<< HEAD` - Start of your changes (current branch) - `=======` - Separator between the two versions - `>>>>>>> add-debug` - End of their changes (branch being merged) ### Part 7: Resolve the Conflict You have three options: **Option 1: Keep ONLY your changes (timeout)** ```json "timeout": 5000 ``` **Option 2: Keep ONLY their changes (debug)** ```json "debug": true ``` **Option 3: Keep BOTH changes** ← **Do this!** ```json "timeout": 5000, "debug": true ``` ### Part 8: Edit the File For this challenge, we want **both settings**, so: 1. Delete ALL the conflict markers: - Remove `<<<<<<< HEAD` - Remove `=======` - Remove `>>>>>>> add-debug` 2. Keep both settings: **Before (with conflict markers):** ```json { "app": { "name": "MyApp", "version": "1.0.0", "port": 3000, <<<<<<< HEAD "timeout": 5000 ======= "debug": true >>>>>>> add-debug } } ``` **After (resolved):** ```json { "app": { "name": "MyApp", "version": "1.0.0", "port": 3000, "timeout": 5000, "debug": true } } ``` **Important:** - Remove ALL markers - Add a comma after `"timeout": 5000` (for valid JSON) - Ensure the file is valid JSON 3. Save the file ### Part 9: Mark the Conflict as Resolved Tell Git you've resolved the conflict: ```bash # Stage the resolved file git add config.json # Check status git status ``` You should see: ``` On branch main All conflicts fixed but you are still merging. (use "git commit" to conclude merge) ``` Perfect! Git confirms the conflict is resolved. ### Part 10: Complete the Merge Commit the merge: ```bash git commit ``` Git will open an editor with a default merge message. You can accept it or customize it, then save and close. **Done!** Your merge is complete! ```bash # View the final result cat config.json # View the history git log --oneline --graph --all ``` You should see both `timeout` and `debug` in the config! ### Part 11: Verify Your Solution From the module directory (not inside challenge/): ```bash .\verify.ps1 ``` ## Understanding Conflict Markers ### Anatomy of a Conflict ``` <<<<<<< HEAD ← Marker: Start of your version Your changes here ======= ← Marker: Separator Their changes here >>>>>>> branch-name ← Marker: End of their version ``` ### Common Conflict Patterns **Simple conflict:** ``` <<<<<<< HEAD print("Hello") ======= print("Hi") >>>>>>> feature ``` Decision: Which greeting do you want? **Both are needed:** ``` <<<<<<< HEAD timeout: 5000 ======= debug: true >>>>>>> feature ``` Decision: Keep both (add comma)! **Deletion conflict:** ``` <<<<<<< HEAD # Function deleted on your branch ======= def old_function(): pass >>>>>>> feature ``` Decision: Delete or keep the function? ## Common Mistakes to Avoid ❌ **Forgetting to remove conflict markers** ```json <<<<<<< HEAD ← Don't leave these in! "timeout": 5000, "debug": true >>>>>>> add-debug ← Don't leave these in! ``` This breaks your code! Always remove ALL markers. ❌ **Committing without staging** ```bash git commit # Error! You didn't add the file ``` Always `git add` the resolved file first! ❌ **Keeping only one side when both are needed** If you delete one setting, you lose that work! ❌ **Breaking syntax** ```json "timeout": 5000 ← Missing comma! "debug": true ``` Always verify your file is valid after resolving! ❌ **Not testing the result** Always check that your resolved code works! ## Aborting a Merge Changed your mind? You can abort the merge anytime before committing: ```bash git merge --abort ``` This returns your repository to the state before you started the merge. No harm done! ## Key Commands ```bash # Discover changes before merging git diff branch1 branch2 # Attempt a merge git merge # Check which files have conflicts git status # Abort the merge and start over git merge --abort # After resolving conflicts: git add git commit # View conflicts in a different style git diff --ours # Your changes git diff --theirs # Their changes git diff --base # Original version ``` ## Pro Tips 💡 **Use `git diff` first** Always compare branches before merging: ```bash git diff main..feature-branch ``` 💡 **Prevent conflicts** - Pull changes frequently - Communicate with your team about who's working on what - Keep branches short-lived and merge often 💡 **Make conflicts easier** - Work on different files when possible - Make small, focused commits - If editing the same file, coordinate with teammates 💡 **When stuck** - Read the conflict markers carefully - Look at `git log` to understand what each side changed - Use `git diff` to see the changes - Ask a teammate to review your resolution - Use a merge tool: `git mergetool` ## Merge Tools Git supports visual merge tools that make resolving conflicts easier: ```bash # Configure a merge tool (one-time setup) git config --global merge.tool vscode # or meld, kdiff3, etc. # Use the merge tool during a conflict git mergetool ``` This opens a visual interface showing both versions side-by-side. ## Real-World Scenario This exercise simulates a common real-world situation: **Scenario:** Two developers working on the same file - Alice adds a timeout configuration - Bob adds debug mode configuration - Both push their changes - When Bob tries to merge, he gets a conflict - Bob resolves it by keeping both changes - Everyone's work is preserved! This happens all the time in team development. Conflicts are normal! ## What You've Learned After completing this module, you understand: - ✅ Merge conflicts happen when the same lines are changed differently - ✅ `git diff` helps you discover changes before merging - ✅ Conflict markers show both versions - ✅ You decide what the final code should look like - ✅ Remove all markers before committing - ✅ Test your resolution to ensure it works - ✅ Conflicts are normal and easy to resolve with practice ## Next Steps Ready to continue? The next module covers **cherry-picking** - selectively applying specific commits from one branch to another. To start over: ```bash .\reset.ps1 .\setup.ps1 ``` **Need help?** Review the steps above, or run `git status` to see what Git suggests!