|
| 1 | +[**Up**](concepts.md) | |
| 2 | +[**Content**](../index.md) | |
| 3 | +[**Intro**](../01-Introduction/introduction.md) | |
| 4 | +[**Concepts**](../02-Concepts/concepts.md) | |
| 5 | +[**Operations**](../03-Operations/operations.md) | |
| 6 | +[**Dictionary**](../04-Appendix/dictionary.md) |
| 7 | + |
| 8 | +------------------------------------------------------------------------------- |
| 9 | +## Conflicts |
| 10 | + |
| 11 | +A merge conflict occurs when Git cannot automatically combine changes from |
| 12 | +two branches. This happens when both branches modify the same lines in the |
| 13 | +same file, or when one branch deletes a file that the other branch modifies. |
| 14 | +Git stops the merge and asks the user to resolve the conflict manually. |
| 15 | + |
| 16 | +Conflicts are a normal part of collaborative development. They do not |
| 17 | +indicate an error — they simply mean that Git needs human judgement to |
| 18 | +decide which changes to keep. |
| 19 | + |
| 20 | +------------------------------------------------------------------------------- |
| 21 | +### When conflicts occur |
| 22 | + |
| 23 | +Conflicts can arise during any operation that combines work from different |
| 24 | +sources: |
| 25 | + |
| 26 | + - **Merging** — `git merge` combines two branches and finds overlapping |
| 27 | + changes in the same file region |
| 28 | + - **Rebasing** — `git rebase` replays commits on top of another branch, |
| 29 | + and a replayed commit touches the same lines as an existing commit |
| 30 | + - **Cherry-picking** — `git cherry-pick` applies a single commit from |
| 31 | + another branch that conflicts with the current state |
| 32 | + - **Pulling** — `git pull` fetches and merges remote changes that overlap |
| 33 | + with local changes |
| 34 | + - **Stash application** — `git stash pop` or `git stash apply` restores |
| 35 | + stashed changes that conflict with the current working tree |
| 36 | + |
| 37 | +------------------------------------------------------------------------------- |
| 38 | +### How Git marks conflicts |
| 39 | + |
| 40 | +When Git detects a conflict it inserts conflict markers directly into the |
| 41 | +affected file. The markers divide the conflicting sections into two parts: |
| 42 | + |
| 43 | +``` |
| 44 | +<<<<<<< HEAD |
| 45 | +This is the content from the current branch (ours). |
| 46 | +======= |
| 47 | +This is the content from the incoming branch (theirs). |
| 48 | +>>>>>>> feature-branch |
| 49 | +``` |
| 50 | + |
| 51 | +| Marker | Meaning | |
| 52 | +|--------|---------| |
| 53 | +| `<<<<<<< HEAD` | Start of the current branch content | |
| 54 | +| `=======` | Separator between the two versions | |
| 55 | +| `>>>>>>> feature-branch` | End of the incoming branch content | |
| 56 | + |
| 57 | +The text between `<<<<<<< HEAD` and `=======` is what exists on the |
| 58 | +current branch. The text between `=======` and `>>>>>>>` is what the |
| 59 | +incoming branch wants to introduce. The label after `>>>>>>>` shows the |
| 60 | +name of the branch or commit being merged in. |
| 61 | + |
| 62 | +A single file can contain multiple conflict blocks if several regions |
| 63 | +of the file were changed by both branches. |
| 64 | + |
| 65 | +------------------------------------------------------------------------------- |
| 66 | +### Step-by-step resolution workflow |
| 67 | + |
| 68 | +Resolving a conflict follows a predictable sequence: |
| 69 | + |
| 70 | +**1. Identify the conflicting files** |
| 71 | + |
| 72 | +After a failed merge, `git status` lists every file that needs attention: |
| 73 | + |
| 74 | +``` |
| 75 | +$ git status |
| 76 | +On branch main |
| 77 | +You have unmerged paths. |
| 78 | +
|
| 79 | +Unmerged paths: |
| 80 | + (use "git add <file>..." to mark resolution) |
| 81 | + both modified: src/config.yaml |
| 82 | + both modified: src/main.py |
| 83 | +``` |
| 84 | + |
| 85 | +Files marked as `both modified` contain conflict markers. |
| 86 | + |
| 87 | +**2. Open and understand the conflict markers** |
| 88 | + |
| 89 | +Open each conflicting file in an editor. Read both versions carefully. |
| 90 | +Understand what each branch intended before deciding how to resolve the |
| 91 | +conflict. Look at the surrounding context — the unchanged lines above and |
| 92 | +below the markers often clarify the intent of each change. |
| 93 | + |
| 94 | +**3. Edit to resolve** |
| 95 | + |
| 96 | +There are three common resolution strategies: |
| 97 | + |
| 98 | + - **Keep one side** — delete the markers and the content from the side |
| 99 | + you do not want |
| 100 | + - **Combine both** — merge the two versions into a single coherent result |
| 101 | + and remove all markers |
| 102 | + - **Rewrite** — discard both versions and write something entirely new |
| 103 | + that satisfies the intent of both changes |
| 104 | + |
| 105 | +After editing the file must not contain any conflict markers. Any remaining |
| 106 | +`<<<<<<<`, `=======`, or `>>>>>>>` lines will cause problems. |
| 107 | + |
| 108 | +**4. Stage resolved files** |
| 109 | + |
| 110 | +Once a file is resolved, stage it to tell Git the conflict is handled: |
| 111 | + |
| 112 | +``` |
| 113 | +git add src/config.yaml |
| 114 | +git add src/main.py |
| 115 | +``` |
| 116 | + |
| 117 | +**5. Complete the merge** |
| 118 | + |
| 119 | +After all conflicts are staged, finalize the merge with a commit: |
| 120 | + |
| 121 | +``` |
| 122 | +git commit |
| 123 | +``` |
| 124 | + |
| 125 | +Git pre-fills the commit message with merge information. You can accept |
| 126 | +the default or edit it to describe how the conflicts were resolved. |
| 127 | + |
| 128 | +------------------------------------------------------------------------------- |
| 129 | +### Aborting a conflicted merge |
| 130 | + |
| 131 | +If the conflicts are too complex or the merge was started by mistake, |
| 132 | +you can abandon it entirely: |
| 133 | + |
| 134 | +``` |
| 135 | +git merge --abort |
| 136 | +``` |
| 137 | + |
| 138 | +This restores the repository to the state it was in before the merge |
| 139 | +began. All conflict markers and staged resolutions are discarded. The |
| 140 | +working tree and index return to the pre-merge state. |
| 141 | + |
| 142 | +This command is safe — it does not delete any commits or branches. |
| 143 | + |
| 144 | +------------------------------------------------------------------------------- |
| 145 | +### Conflicts during rebase |
| 146 | + |
| 147 | +Rebasing replays commits one at a time, so conflicts can occur at each |
| 148 | +step. The workflow differs slightly from a merge conflict: |
| 149 | + |
| 150 | +``` |
| 151 | +$ git rebase main |
| 152 | +CONFLICT (content): Merge conflict in src/main.py |
| 153 | +error: could not apply abc1234... Add feature X |
| 154 | +``` |
| 155 | + |
| 156 | +**1.** Resolve the conflict in the file as described above. |
| 157 | + |
| 158 | +**2.** Stage the resolved file: |
| 159 | + |
| 160 | +``` |
| 161 | +git add src/main.py |
| 162 | +``` |
| 163 | + |
| 164 | +**3.** Continue the rebase to process the next commit: |
| 165 | + |
| 166 | +``` |
| 167 | +git rebase --continue |
| 168 | +``` |
| 169 | + |
| 170 | +If more commits produce conflicts, Git stops again and the process |
| 171 | +repeats. To abandon the entire rebase and return to the original state: |
| 172 | + |
| 173 | +``` |
| 174 | +git rebase --abort |
| 175 | +``` |
| 176 | + |
| 177 | +To skip the current conflicting commit entirely (dropping its changes): |
| 178 | + |
| 179 | +``` |
| 180 | +git rebase --skip |
| 181 | +``` |
| 182 | + |
| 183 | +------------------------------------------------------------------------------- |
| 184 | +### Using merge tools |
| 185 | + |
| 186 | +Git can launch a graphical or terminal-based merge tool to help resolve |
| 187 | +conflicts visually: |
| 188 | + |
| 189 | +``` |
| 190 | +git mergetool |
| 191 | +``` |
| 192 | + |
| 193 | +This opens each conflicting file in the configured tool. Popular merge |
| 194 | +tools include **vimdiff**, **meld**, **kdiff3**, **Beyond Compare**, and |
| 195 | +**VS Code**. To set a default tool: |
| 196 | + |
| 197 | +``` |
| 198 | +git config --global merge.tool meld |
| 199 | +``` |
| 200 | + |
| 201 | +Most merge tools display three panes — the base version (common ancestor), |
| 202 | +the current branch version, and the incoming branch version — alongside a |
| 203 | +result pane where you build the final output. |
| 204 | + |
| 205 | +After the tool saves the resolved file, Git marks it as resolved. Some |
| 206 | +tools create `.orig` backup files. To disable these: |
| 207 | + |
| 208 | +``` |
| 209 | +git config --global mergetool.keepBackup false |
| 210 | +``` |
| 211 | + |
| 212 | +------------------------------------------------------------------------------- |
| 213 | +### Preventing conflicts |
| 214 | + |
| 215 | +Conflicts cannot be eliminated entirely, but their frequency and severity |
| 216 | +can be reduced: |
| 217 | + |
| 218 | + - **Communicate** — coordinate with team members about who is working on |
| 219 | + which files to avoid overlapping changes |
| 220 | + - **Keep branches short-lived** — the longer a branch diverges from the |
| 221 | + main line, the higher the chance of conflicts |
| 222 | + - **Pull frequently** — regularly integrate upstream changes into your |
| 223 | + branch with `git pull` or `git rebase` to stay close to the latest state |
| 224 | + - **Make small, focused commits** — smaller changes are easier to merge |
| 225 | + and produce simpler conflicts when they do occur |
| 226 | + - **Avoid reformatting entire files** — whitespace-only or style-only |
| 227 | + changes across a whole file create conflicts with every other branch |
| 228 | + that touches that file |
| 229 | + - **Use `.gitattributes`** — define merge strategies for specific file |
| 230 | + types (e.g., always accept ours for generated lock files) |
| 231 | + |
| 232 | +------------------------------------------------------------------------------- |
| 233 | +### Practical example |
| 234 | + |
| 235 | +Two developers work on the same file. Alice changes a greeting on the |
| 236 | +`main` branch, and Bob changes it on a `feature` branch. |
| 237 | + |
| 238 | +**Initial file (`greeting.txt`) on both branches:** |
| 239 | +``` |
| 240 | +Hello, welcome to the project. |
| 241 | +``` |
| 242 | + |
| 243 | +**Alice's change on `main`:** |
| 244 | +``` |
| 245 | +Hello, welcome to the project! We are glad you are here. |
| 246 | +``` |
| 247 | + |
| 248 | +**Bob's change on `feature`:** |
| 249 | +``` |
| 250 | +Hi there, welcome to the project. |
| 251 | +``` |
| 252 | + |
| 253 | +When Bob merges `main` into his branch, Git produces a conflict: |
| 254 | + |
| 255 | +``` |
| 256 | +$ git merge main |
| 257 | +Auto-merging greeting.txt |
| 258 | +CONFLICT (content): Merge conflict in greeting.txt |
| 259 | +Automatic merge failed; fix conflicts and then commit the result. |
| 260 | +``` |
| 261 | + |
| 262 | +The file now contains: |
| 263 | + |
| 264 | +``` |
| 265 | +<<<<<<< HEAD |
| 266 | +Hi there, welcome to the project. |
| 267 | +======= |
| 268 | +Hello, welcome to the project! We are glad you are here. |
| 269 | +>>>>>>> main |
| 270 | +``` |
| 271 | + |
| 272 | +Bob decides to combine both changes: |
| 273 | + |
| 274 | +``` |
| 275 | +Hi there, welcome to the project! We are glad you are here. |
| 276 | +``` |
| 277 | + |
| 278 | +He removes all conflict markers, stages the file, and completes the merge: |
| 279 | + |
| 280 | +``` |
| 281 | +git add greeting.txt |
| 282 | +git commit -m "Merge main into feature, combine greeting changes" |
| 283 | +``` |
| 284 | + |
| 285 | +The conflict is resolved and the repository history records the merge. |
0 commit comments