|
| 1 | +# Resolving Merge Conflicts |
| 2 | + |
| 3 | +Merge conflicts are caused by working on outdated versions of the codebase, or another developer merging a change involving similar parts of the codebase to you. |
| 4 | + |
| 5 | +> [!IMPORTANT] |
| 6 | +> **Avoid Merge Conflicts** by syncing your branch regularly [Sync Guide](rebasing.md). |
| 7 | +
|
| 8 | +## Step-by-Step Guide |
| 9 | + |
| 10 | +### 1. See which files are conflicted |
| 11 | +```bash |
| 12 | +git status |
| 13 | +``` |
| 14 | + |
| 15 | +### 2. Understand the conflict markers |
| 16 | +You will see sections like: |
| 17 | + |
| 18 | +```text |
| 19 | +<<<<<<< HEAD |
| 20 | +code from main |
| 21 | +======= |
| 22 | +your branch’s code |
| 23 | +>>>>>>> mybranch |
| 24 | +``` |
| 25 | + |
| 26 | +### 3. Decide what the final code should be |
| 27 | + |
| 28 | +Have a vision of what you'd like the final code to look like, given what is currently on main and what you'd like to propose. |
| 29 | + |
| 30 | +> [!WARNING] |
| 31 | +> - Do not blindly accept both changes |
| 32 | +> - Do not blindly accept incoming |
| 33 | +> - Do not blindly accept existing |
| 34 | +
|
| 35 | +Merge conflicts require: ✅ Human interpretation |
| 36 | + |
| 37 | +Sometimes you'll be: |
| 38 | +- Accepting both incoming and current |
| 39 | +- Accepting only incoming |
| 40 | +- Accepting only current |
| 41 | +- Accepting **parts** of both incoming and current |
| 42 | + |
| 43 | +Generally, you want to keep all changes that were merged to main, but additionally, layer on your changes. |
| 44 | + |
| 45 | +### 4. Resolve conflicts in VS Code (recommended): |
| 46 | +Once you understand you have a merge conflict and have a vision of the final document, we recommend using VS Code. |
| 47 | + |
| 48 | + |
| 49 | +VS Code makes solving merge-conflicts easier with a 3-pane interface for resolving conflicts: |
| 50 | + |
| 51 | +- Incoming Change → code from main (left/top) |
| 52 | +- Current Change → code from your branch (right/top) |
| 53 | +- Result → the lower/third pane, where you create the final merged file. |
| 54 | + |
| 55 | +You want to accept or reject content from the top left and top right panes, and edit the final pane in the bottom so the final code submission reasonably resolves the issue while respecting the work of others. |
| 56 | + |
| 57 | +#### Steps to resolve in VS Code |
| 58 | + |
| 59 | +1. Open the conflicted file in VS Code. |
| 60 | + |
| 61 | +2. Look at both the Incoming Change (left) and Current Change (right) panels. |
| 62 | + |
| 63 | +3. In the Result (lower pane), edit the file so it contains the correct final version. |
| 64 | + - Sometimes keep Incoming (main) |
| 65 | + - Sometimes keep Current (your branch) |
| 66 | + - Often, combine both parts and edit the code manually. |
| 67 | + |
| 68 | + If the conflict is resolved correctly, VS Code will mark it as fixed. |
| 69 | + |
| 70 | +4. Save the lower pane file once there are no more merge conflicts to resolve in this file. |
| 71 | + |
| 72 | +5. Click the add button next to the file to resolve conflicts or: |
| 73 | + ```bash |
| 74 | + git add <file> |
| 75 | + ``` |
| 76 | + |
| 77 | +6. Continue the rebase: |
| 78 | + ```bash |
| 79 | + git rebase --continue |
| 80 | + ``` |
| 81 | + |
| 82 | +7. If there are more conflicts in other files, VS Code will automatically move you to the next one. Repeat until no conflicts remain. |
| 83 | + |
| 84 | + > [!WARNING] |
| 85 | + > Do not just click “Accept All Incoming” or “Accept All Current” — that usually **deletes** or **corrupts** important code. |
| 86 | +
|
| 87 | + Once the rebase operation completes, your commits will be layered on top of main. It means your commit history will look “different” and you may even see changes to commits from other authors — this is expected, since rebase rewrites history. |
| 88 | + |
| 89 | +8. Push changes. If you already have an open Pull Request, you will need to update it with a **force push**. Before pushing, double-check that your commits are both DCO signed and GPG verified: |
| 90 | + ```bash |
| 91 | + git log -n 10 --pretty=format:'%h %an %G? %s' |
| 92 | + ``` |
| 93 | + Ensure you see: `G` = Good (valid signature) |
| 94 | + |
| 95 | + Then: |
| 96 | + ```bash |
| 97 | + git push --force-with-lease |
| 98 | + ``` |
| 99 | + |
| 100 | +> [!TIP] |
| 101 | +> To be safe, create a backup branch before force pushing. |
| 102 | +
|
| 103 | +## Common Issues |
| 104 | + |
| 105 | +#### 1. Message: *“No changes – did you forget to use git add?”* |
| 106 | +- **What it means:** You resolved the conflicts but forgot to stage the files. |
| 107 | +- **Solution:** Run `git add <file>` and try again. |
| 108 | + |
| 109 | +#### 2. Message: *“Are you sure you want to continue with conflicts?”* |
| 110 | +- **What it means:** Some conflicts are still unresolved or the files were not saved properly. |
| 111 | +- **Solution:** Double-check your files in VS Code, make sure they are saved, and resolve any remaining conflict markers: |
| 112 | + |
| 113 | +### If you need to stop |
| 114 | +```bash |
| 115 | +git rebase --abort |
| 116 | +``` |
| 117 | + |
| 118 | +> [!TIP] |
| 119 | +> At each conflict: resolve → save → stage → continue. Repeat until all conflicts are gone. |
| 120 | +
|
| 121 | +### What NOT to do |
| 122 | +1. ❌ Do not run git merge main |
| 123 | + → This creates messy merge commits. Always rebase instead. |
| 124 | + |
| 125 | +2. ❌ Do not merge into your local main |
| 126 | + → Keep main as a clean mirror of upstream/main. |
| 127 | + |
| 128 | +3. ❌ Do not open PRs from your fork’s main |
| 129 | + → Always create a feature branch for your changes. |
| 130 | + |
| 131 | +At each conflict instance, you'll have to repeat: fix the conflict, stage the files and continue rebasing. |
| 132 | + |
| 133 | +## Recovery Tips |
| 134 | + |
| 135 | +Undo the last rebase commit, but keep changes staged (while still in rebase): |
| 136 | + If you are in the middle of a rebase and realize the last step went wrong, you can undo it while keeping changes staged: |
| 137 | +```bash |
| 138 | +git reset --soft HEAD~i |
| 139 | +``` |
| 140 | + |
| 141 | +> [!NOTE] |
| 142 | +> The number after HEAD~ refers to how many commits you want to go back. |
| 143 | +
|
| 144 | +For example: |
| 145 | +- HEAD~1 → go back 1 commit |
| 146 | +- HEAD~3 → go back 3 commits |
| 147 | +- HEAD~5 → go back 5 commits |
| 148 | + |
| 149 | +### If you are completely stuck |
| 150 | +Sometimes a rebase can get too messy to fix conflict by conflict. In that case, it’s often easier to start fresh: |
| 151 | + |
| 152 | +1. Abort the rebase to stop where you are: |
| 153 | +```bash |
| 154 | +git rebase --abort |
| 155 | +``` |
| 156 | + |
| 157 | +2. Reset your fork's main to the upstream main and layer your commits on top of that: |
| 158 | +``` bash |
| 159 | +git checkout main |
| 160 | +git reset --hard upstream/main |
| 161 | +git push origin main --force-with-lease |
| 162 | +git checkout mybranch |
| 163 | +git rebase upstream/main -S |
| 164 | +``` |
| 165 | + |
| 166 | +> [!WARNING] |
| 167 | +> Use git stash only if you really want to save some local changes that aren’t yet committed. In most cases, if the rebase is failing, it’s safer to abort or reset rather than reapplying a stash of broken work. |
0 commit comments