By Kedar Salunkhe  · Updated March 2026 Â
There is a specific kind of dread that hits when you run git merge or git pull and your terminal outputs this:
CONFLICT (content): Merge conflict in src/auth/login.js
Automatic merge failed; fix conflicts and then commit the result.
If you’re new to Git, this feels like you’ve broken something. Like Git is stuck and you don’t know how to unstick it. You open the file and see those angle brackets and equal signs and have no idea what to do next.
If you’ve been using Git for a while, conflicts are just Tuesday. They’re annoying, occasionally time-consuming, but completely routine.
The goal of this guide is to get you to the second state as fast as possible. We’ll start from the very beginning — why conflicts happen at all — and go all the way through every type of conflict you’ll encounter in real work, how to read what Git is telling you, how to resolve conflicts cleanly with different tools, and how to build habits that make conflicts smaller and rarer.
Table of Contents
1. Why Git Merge Conflicts Happen
Git is remarkably good at combining changes automatically. The vast majority of merges complete without any human involvement at all. So when a conflict does happen, it’s worth understanding exactly why Git threw its hands up.
A merge conflict happens when two branches have both modified the same part of the same file in different ways, and Git cannot determine which version to keep without human judgment. That’s the complete definition. Git isn’t broken. Git isn’t confused. Git is telling you: two people changed the same thing, and I need you to decide what the right answer is.
Here’s a concrete example. You and a colleague are both working on login.js. The file currently has this line:
const SESSION_TIMEOUT = 3600;
You change it to 7200 on your branch because you’re working on a “remember me” feature. Your colleague changes it to 1800 on their branch because they’re tightening security. Both changes are reasonable. Both come from different requirements. Neither of you knew the other was touching this line. When your branches merge, Git finds this situation and stops — it has no way to know whether the session timeout should be 7200 or 1800. Only a human can answer that.
Conflicts also happen in a few other situations beyond same-line edits:
- One branch deletes a file that another branch modifies
- One branch renames a file that another branch also renames differently
- Both branches add different content at the same location in a file
- Both branches modify the same function signature but in different ways
In all of these cases, the pattern is the same: two independent changes that can’t be automatically combined. Git stops and asks you to make the call.
2. What Git Is Actually Doing During a Merge
Understanding the mechanism makes conflict resolution feel less like guesswork. When you run git merge feature-branch, Git performs a three-way merge. It finds three versions of every file:
- The base — the most recent common ancestor commit of the two branches. This is the version of the file that existed before either branch made any changes.
- Ours — the version on your current branch (the branch you’re merging into).
- Theirs — the version on the branch being merged in.
Git’s logic is straightforward. For each section of each file:
- If only one branch changed a section, take that change. No conflict.
- If both branches changed a section in the same way, take the change once. No conflict.
- If both branches changed the same section differently, that’s a conflict. Stop and ask the human.
The three-way approach is smarter than just comparing two files directly. Without the base, Git couldn’t tell the difference between “both branches deleted this line” (which should result in the line being gone) and “one branch deleted this line while the other kept it” (which might be a conflict). The base gives Git the context to make most of these decisions automatically.
When a conflict is found, Git does several things. It marks the conflicted sections in the file with conflict markers. It stages the file with a special conflict status. And it halts the merge, leaving you in an intermediate state where the merge is started but not committed. Your job is to resolve the conflicts and complete the merge manually.
3. Reading Conflict Markers: What Every Symbol Means
This is the part most tutorials rush through. Let’s go slowly because it matters.
When Git writes conflict markers into a file, it looks like this:
function validateUser(email, password) {
if (!email || !password) {
return false;
}
<<<<<<< HEAD
const timeout = 7200;
const maxAttempts = 10;
=======
const timeout = 1800;
const maxAttempts = 3;
>>>>>>> feature/security-hardening
return authenticate(email, password, timeout, maxAttempts);
}
Let’s go through every part of this:
<<<<<<< HEAD
This marks the beginning of the conflict section. Everything between this line and the ======= divider is the version from your current branch — the branch you were on when you ran git merge. HEAD is wherever your branch pointer is right now. In most cases this is “your version” of the change.
=======
The divider between the two conflicting versions. Above this line is “ours.” Below this line is “theirs.”
>>>>>>> feature/security-hardening
This marks the end of the conflict section. The text after the angle brackets is the name of the branch being merged in. Everything between ======= and this line is the version from that branch — “their version.”
Everything outside the conflict markers — the lines above <<<<<<< HEAD and below >>>>>>> — was merged successfully and doesn’t need any attention. Those lines are already the correct, combined result.
The diff3 Format: Showing the Base Too
By default Git shows you two versions. But you can configure it to show three — including the base — which is often much more useful for understanding what each side actually changed:
$ git config --global merge.conflictstyle diff3
With diff3 enabled, the conflict looks like this:
<<<<<<< HEAD
const timeout = 7200;
const maxAttempts = 10;
||||||| merged common ancestors
const timeout = 3600;
const maxAttempts = 5;
=======
const timeout = 1800;
const maxAttempts = 3;
>>>>>>> feature/security-hardening
Now you can see all three states: what it was originally, what your branch changed it to, and what their branch changed it to. This makes it much easier to understand what each side was trying to accomplish. Set this globally — you’ll thank yourself later.
4. The Different Types of Merge Conflicts
Not all conflicts are the same. Recognizing the type helps you resolve it faster.
Content Conflict
The most common type. Both branches modified the same lines of the same file. You see the conflict markers in the file and choose which version to keep (or write a combination). This is what the example above shows.
Delete/Modify Conflict
One branch deleted a file. The other branch modified it. Git doesn’t know if the deletion should win (the file shouldn’t exist anymore) or if the modification should win (the file should exist with the new changes).
CONFLICT (modify/delete): config/legacy.js deleted in feature/cleanup
and modified in HEAD. Version HEAD of config/legacy.js left in tree.
Resolve this by deciding: should the file exist or not? If it should exist with the modifications, stage it with git add config/legacy.js. If it should be deleted, remove it with git rm config/legacy.js.
Add/Add Conflict
Both branches added a new file with the same name but different content. Git can’t know which version is correct since both files are new — there’s no base to compare against.
CONFLICT (add/add): Merge conflict in src/utils/formatter.js
Open the file, read both versions, and produce the correct combined result.
Rename/Rename Conflict
Both branches renamed the same file, but to different names. Git leaves both versions in your working directory and asks you to decide which name wins.
CONFLICT (rename/rename): Rename "utils.js" -> "helpers.js" in HEAD.
Rename "utils.js" -> "utilities.js" in feature/refactor
Pick the correct name, remove the other version with git rm, and stage the keeper with git add.
5. Step-by-Step: How to Resolve a Merge Conflict
Here is the complete process, from the moment a conflict appears to the moment it’s resolved. Follow this every time and it becomes mechanical.
Step 1: Don’t Panic — Understand What State You’re In
The moment you see a conflict message, run git status. This tells you exactly which files have conflicts and where you stand:
$ git status
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: src/auth/login.js
both modified: src/utils/validator.js
deleted by them: config/legacy.js
Read this carefully. “Both modified” means content conflicts. “Deleted by them” is a delete/modify conflict. You now have a complete list of everything that needs attention.
Step 2: Open Each Conflicted File and Read Both Versions
Open the first conflicted file. Find the conflict markers. Read both versions slowly. Don’t just pick one because it looks familiar — understand what each side was trying to do. If you wrote one side, you know your intent. You need to understand your colleague’s intent too before deciding.
Sometimes the right answer is one version or the other. Sometimes it’s a combination of both. Sometimes the conflict reveals that you need to have a conversation with whoever wrote the other version before you can resolve it correctly.
Step 3: Edit the File to Its Correct Final State
Remove all conflict markers. Leave only the code that should actually be there. Here’s the conflict from before:
<<<<<<< HEAD
const timeout = 7200;
const maxAttempts = 10;
=======
const timeout = 1800;
const maxAttempts = 3;
>>>>>>> feature/security-hardening
After resolution — say you agreed with your colleague’s security requirements but decided the timeout should be a compromise:
const timeout = 3600;
const maxAttempts = 3;
The file is now clean. No conflict markers anywhere. The code is what it should actually be.
Step 4: Verify the File Is Correct
Before staging, do a quick check. Search the file for <<<<<<< to make sure you didn’t miss a conflict marker. Read the surrounding code to make sure the resolution makes sense in context. If the file is code, make sure the syntax is still valid — it’s easy to accidentally delete a closing brace when cleaning up conflict markers.
Step 5: Stage the Resolved File
$ git add src/auth/login.js
Staging a previously conflicted file tells Git you’ve resolved it. Run git status after each file to see the remaining conflicts shrink. Move through all conflicted files the same way.
Step 6: Complete the Merge with a Commit
Once all conflicts are resolved and all files are staged:
$ git commit
Git will open your editor with a pre-filled merge commit message. The default is usually fine — it describes what was merged. Save and close the editor. The merge is complete.
[main f8b2e19] Merge branch 'feature/security-hardening'
That’s it. The conflict is resolved, the merge is committed, and the history is clean.
6. Resolving Conflicts in VS Code
VS Code has built-in conflict resolution that makes the process faster and harder to mess up. When you open a conflicted file in VS Code, it renders the conflict markers visually and gives you clickable options above each conflict.
Instead of seeing raw markers, you see the two versions highlighted in different colors with four action buttons above each conflict block:
- Accept Current Change — keeps your version (HEAD), discards theirs
- Accept Incoming Change — keeps their version, discards yours
- Accept Both Changes — keeps both versions, one after the other
- Compare Changes — opens a side-by-side diff view
For simple conflicts where one version is clearly right, click the appropriate button and move on. For more complex conflicts where you need a combination of both, click “Accept Both Changes” and then manually edit the result to remove what’s wrong and keep what’s right.
VS Code also shows a list of conflicted files in the Source Control panel (the branch icon on the left sidebar). Files with an exclamation mark have unresolved conflicts. Files with a checkmark have been staged. This gives you a visual progress tracker as you work through the resolution.
One important note: even after clicking the resolution buttons, you still need to stage the file and run git commit. VS Code handles the marker removal for you but doesn’t automatically stage or commit. Use the Source Control panel to stage files or run the git commands in the integrated terminal.
7. Resolving Conflicts in the Terminal
If you prefer the terminal or you’re working on a remote server without a GUI, here are the commands that make terminal-based resolution clean.
Finding All Conflict Markers
# Find all files with conflict markers
$ grep -rn "<<<<<<<" .
# Or use git's own listing
$ git diff --name-only --diff-filter=U
Choosing One Version Entirely
If you know you want to keep entirely your version or entirely their version for a specific file, you don’t have to edit the file manually:
# Keep your version (current branch) for a specific file
$ git checkout --ours src/auth/login.js
# Keep their version (incoming branch) for a specific file
$ git checkout --theirs src/auth/login.js
# Then stage it
$ git add src/auth/login.js
Use this when one version is clearly correct and the other is simply wrong in context. Don’t use it reflexively without reading both versions — you might be discarding changes that matter.
Verifying No Markers Remain
Before committing, confirm no conflict markers slipped through:
$ grep -rn "<<<<<<<" --include="*.js" --include="*.ts" --include="*.py" .
If this returns nothing, you’re clean. If it returns matches, open those files and finish the resolution.
8. Handling Conflicts During a Rebase
Rebase conflicts feel different from merge conflicts because of how rebase works. Instead of combining two branches in one operation, rebase replays your commits one by one on top of the target branch. This means you might hit a conflict, resolve it, continue — and then hit another conflict from the next commit being replayed.
The workflow for rebase conflicts is slightly different:
# You're rebasing your feature branch onto main
$ git rebase main
# A conflict appears
CONFLICT (content): Merge conflict in src/api/routes.js
error: could not apply b4e8d23... Add user profile endpoint
# Check status — notice it says "rebase in progress"
$ git status
interactive rebase in progress; onto f4d8a1b
Last command done (1 command done):
pick b4e8d23 Add user profile endpoint
Next commands to do (2 remaining commands):
pick c5f7e34 Add profile image upload
pick d6a8f45 Add profile settings
# Resolve the conflict in the file
$ vim src/api/routes.js
# Stage the resolved file
$ git add src/api/routes.js
# IMPORTANT: use --continue, not git commit
$ git rebase --continue
The key difference from a merge: after staging resolved files during a rebase, you use git rebase --continue instead of git commit. Git will open your editor to let you edit the commit message for the commit being replayed, then it moves on to the next commit. If that one also has a conflict, you’ll go through the same process again.
This means a rebase with many commits touching the same files can produce multiple rounds of conflicts. Each round is about one commit at a time though, which usually means the conflicts are smaller and more focused than a single big merge conflict would be.
If at any point you want to stop the rebase entirely and go back to how things were:
$ git rebase --abort
9. How to Abort a Merge or Rebase
Sometimes you start a merge, get into the conflicts, and realize this isn’t the right moment — you need to talk to your colleague first, or you merged the wrong branch, or you just want to think before proceeding. You can always back out cleanly.
# Abort a merge in progress — returns everything to pre-merge state
$ git merge --abort
# Abort a rebase in progress — returns to pre-rebase state
$ git rebase --abort
# If you accidentally staged some resolutions and want to start over
$ git checkout -m src/auth/login.js # restores conflict markers
git merge --abort is completely safe. It cancels the merge and restores your repository to exactly the state it was in before you ran the merge command. Uncommitted conflict resolutions are discarded. Nothing is lost that wasn’t already saved in a commit.
One scenario where git merge --abort won’t work cleanly: if you had uncommitted changes in your working directory before starting the merge. Git will warn you about this and may refuse to abort if the abort would overwrite those changes. In that case, commit or stash your changes first, then abort.
10. Using git mergetool for Visual Resolution
git mergetool launches a visual merge tool for each conflicted file. Several tools integrate with it, and the right choice depends on your environment and preference.
Setting Up a Merge Tool
# Use VS Code as the merge tool
$ git config --global merge.tool vscode
$ git config --global mergetool.vscode.cmd 'code --wait $MERGED'
# Or use vimdiff if you're comfortable in vim
$ git config --global merge.tool vimdiff
# Or use meld (popular on Linux)
$ git config --global merge.tool meld
Running the Merge Tool
$ git mergetool
Git opens each conflicted file in your configured tool, one at a time. Most tools show three panes: the base version in the middle, your version on the left, and their version on the right. A fourth pane at the bottom shows the result as you make decisions. You work through each conflict by choosing which sections to include in the result.
After you close the tool for each file, Git marks it as resolved and moves to the next one. When all files are done, stage everything and commit:
$ git add .
$ git commit
One nuisance: by default, git mergetool leaves behind .orig backup files for each conflicted file. These contain the original conflicted version. To prevent this:
$ git config --global mergetool.keepBackup false
11. Real-World Conflict Scenarios and How to Handle Them
Here are the specific conflict situations you’ll run into repeatedly in real projects and the cleanest way to handle each one.
Scenario 1: Your Pull Causes a Conflict
You run git pull in the morning and get a conflict. Someone pushed changes to main overnight that touched the same files you’ve been working on.
$ git pull
Auto-merging src/components/Header.jsx
CONFLICT (content): Merge conflict in src/components/Header.jsx
Automatic merge failed; fix conflicts and then commit the result.
This is a merge conflict inside a pull. git pull is git fetch plus git merge — you’re seeing the merge conflict from that merge step. Resolve it exactly as described in Section 5. This is the most common conflict situation and it’s completely routine.
If you’d prefer a rebase-based pull — which keeps your history linear — you can configure it:
# Pull with rebase instead of merge
$ git pull --rebase
# Or set it globally
$ git config --global pull.rebase true
Scenario 2: Conflict in a Generated File or Lock File
Lock files like package-lock.json, yarn.lock, or Pipfile.lock conflict constantly on active projects because they’re auto-generated and highly sensitive to any dependency change. Manually resolving lock file conflicts line by line is almost always wrong — the file has an internal structure that your manual edit will likely corrupt.
The right approach for lock files:
# Accept one version of the lock file (usually theirs)
$ git checkout --theirs package-lock.json
$ git add package-lock.json
# Then regenerate the lock file properly
$ npm install
# Stage the properly regenerated lock file
$ git add package-lock.json
Accept one side’s lock file to get out of conflict state, then regenerate it from the package.json (which should be cleanly merged) to get the correct combined result. This works for package-lock.json, yarn.lock, Pipfile.lock, Gemfile.lock, and equivalent files in other ecosystems.
Scenario 3: Conflict in a Configuration File
Config files — .eslintrc, tsconfig.json, webpack.config.js, database configs — often conflict when two developers are each setting up or modifying the project configuration simultaneously. These conflicts usually require understanding both sides’ intent rather than just picking one.
<<<<<<< HEAD
"rules": {
"no-console": "error",
"indent": ["error", 2]
}
=======
"rules": {
"no-console": "warn",
"semi": ["error", "always"]
}
>>>>>>> feature/linting-updates
In this case, neither version is wrong — both added or changed different rules. The correct resolution is usually to merge both sets of changes:
"rules": {
"no-console": "warn",
"indent": ["error", 2],
"semi": ["error", "always"]
}
For disputed values — like whether no-console should be error or warn — that’s a team decision, not a Git decision. Resolve the conflict in a way that creates a correct file, then have the team conversation separately.
Scenario 4: Massive Conflict After a Long-Running Branch Merges
A feature branch that lived for three weeks finally merges into main. There are conflicts across 23 files. This is a painful situation and there’s no magic fix — but here’s how to work through it systematically without losing your mind.
First, don’t try to resolve everything in one sitting. Start with the files you wrote yourself — you know the intent of both sides. Move to files where you have enough context to make good decisions. For files where you genuinely don’t understand one side’s changes, reach out to whoever wrote those changes before resolving. A five-minute conversation is worth more than a guess that introduces a subtle bug.
Second, run the tests after resolving each file, not just at the end. Catching a bad resolution early, while you still remember what you were doing, is much easier than finding a bug after resolving 23 files.
Third, learn from this. A conflict across 23 files is a symptom of a branch that lived too long. The fix is process, not better conflict resolution skills. Shorter branches, more frequent integration, feature flags for incomplete work — these eliminate the big conflict problem entirely.
12. Preventing Conflicts Before They Happen
Resolving conflicts is a skill worth having. Not needing to resolve them as often is better. Here are the practices that meaningfully reduce conflict frequency and severity.
Integrate Frequently
The single most effective prevention. The more often you merge or rebase from main onto your branch, the smaller the gap between your branch and the shared codebase. Small gaps produce small conflicts. Large gaps — weeks of divergence — produce large, complex conflicts. Make integrating from main a daily habit, not a pre-merge ritual.
# At the start of every work session on a feature branch
$ git fetch origin
$ git rebase origin/main
# or
$ git merge origin/main
Communicate Before Touching Shared Files
Most conflicts are predictable. If you’re about to make significant changes to a file that several people touch regularly — the main router, the database schema, a shared utility module — mention it in Slack or your team channel before you start. “I’m going to refactor auth/session.js today” gives your teammates the chance to merge their work first or coordinate with you.
Keep Functions and Modules Small and Focused
Conflicts happen when multiple people need to modify the same file. The more responsibilities a single file has, the more people will need to modify it simultaneously. Small, focused files with clear single responsibilities attract fewer concurrent changes. This is a software design principle (Single Responsibility Principle) that has a direct and measurable impact on Git conflict frequency.
Use Feature Flags for Long-Running Work
Instead of keeping a feature branch alive for weeks, merge incomplete features to main behind a feature flag. The flag keeps the feature invisible to users, but the code is integrated. This means your incomplete feature is getting tested against all the other changes landing in main continuously, and conflicts are caught and resolved incrementally rather than all at once at the end.
Configure a Good .gitattributes
For certain file types, you can tell Git which merge strategy to use automatically. Lock files, binary files, and auto-generated files can be configured to always use one version rather than trying to merge:
# .gitattributes
package-lock.json merge=ours
*.png binary
*.jpg binary
docs/generated/* merge=ours
This doesn’t eliminate the need to regenerate these files properly after a merge, but it prevents Git from creating impossible-to-resolve conflicts in files where automatic merging never produces a useful result anyway.
Frequently Asked Questions
Does a merge conflict mean someone made a mistake?
Not at all. Conflicts are a normal, expected part of collaborative development. They happen when two people work on the same code simultaneously — which is exactly what’s supposed to happen on a productive team. The conflict is Git telling you there’s a decision that needs human judgment. It’s not an error. It’s not evidence of bad process. The only thing that makes conflicts a problem is when they’re large and frequent, which is usually a sign that branches are living too long or that integration is happening too rarely — process issues, not individual mistakes.
What happens if I commit with conflict markers still in the file?
Git will let you do it — it won’t stop you. The conflict markers become literal text in your file. If it’s code, the file will almost certainly fail to parse or compile. If it’s a config file or text file, the markers will appear as literal content. This is why it’s worth doing a quick search for the marker string before committing. Many teams set up a pre-commit hook that checks for unresolved conflict markers and rejects the commit if any are found. That’s a worthwhile safeguard to add to any shared repository.
Can I prevent specific files from ever having merge conflicts?
You can configure merge strategies per file type in .gitattributes. The “ours” strategy always takes the current branch’s version, effectively preventing conflicts by never attempting to merge. This is appropriate for auto-generated files where manual merging produces incorrect results anyway. For files where content conflicts would be meaningful, you don’t want to suppress them — you want to resolve them correctly. There’s no general way to prevent content conflicts in files that multiple people legitimately need to edit simultaneously, and even if there were, it would hide real problems rather than solve them.
I resolved a conflict but now my tests are failing. What do I do?
This is actually the system working correctly. The conflict resolution produced code that compiles and passes Git’s checks, but the logic is wrong. Read the failing tests to understand what behavior they expect. Look at your conflict resolution and ask whether it actually makes semantic sense — syntactically valid code can still be logically wrong. You may need to revisit the resolution, understand the intent of both sides better, and produce a different result. If you’re unsure, this is the moment to pull in the person who wrote the other side of the conflict and work through it together. Failing tests after conflict resolution are much better than passing tests that hide a subtle bug.
What is the difference between git merge –abort and git reset –hard?
git merge –abort is the clean, intended way to cancel an in-progress merge. It returns the repository to its exact pre-merge state safely, including restoring your working directory. It only works while a merge is in progress. git reset –hard HEAD is a more forceful operation that resets your working directory and index to the last commit, discarding all uncommitted changes — including any conflict resolutions you’ve started. It works any time, not just during a merge. For canceling a merge, always use git merge –abort first. Use git reset –hard only when you specifically want to discard all uncommitted work and know exactly what you’re doing.
Why do I keep getting the same conflict every time I merge?
This usually means two things are happening. First, the same file is being modified in incompatible ways repeatedly — which is a signal that the code has a design problem. If two developers keep independently changing the same logic, the code might need to be restructured so their concerns are separated. Second, you might not be integrating frequently enough. If you resolve a conflict and then don’t merge for another two weeks, the same conflict will reappear when the next merge happens. Git has a feature called “rerere” (reuse recorded resolution) that can remember how you resolved a conflict and apply the same resolution automatically next time: git config –global rerere.enabled true.
Is it safe to use “Accept Incoming” or “Accept Current” for every conflict without reading them?
No, and this is one of the most common ways merge conflicts introduce bugs. Blindly accepting one side for every conflict means you’re almost certainly discarding work that matters. The whole point of the conflict is that both sides made changes that Git couldn’t automatically combine — each side changed something for a reason. Accepting one side without understanding what the other side changed means you’re making a decision without the information needed to make it correctly. Take the extra thirty seconds to read both versions and understand the intent before resolving. The time you spend understanding the conflict is almost always less than the time you’ll spend debugging the bug you introduced by not reading it.
Related Resources
For going deeper on merge conflicts and related topics:
- Pro Git — Advanced Merging — The authoritative reference on Git’s merge strategies, subtree merges, and advanced conflict resolution techniques.
- Git Internals Explained: How Git Works Behind the Scenes (Step-by-Step Guide) [2026]
- What is Git? Beginner Guide (With Real Examples) [2026]
- Git Branching Explained: Internals, Strategies, and Real-World Examples (2026 Guide)
Final Thoughts
Merge conflicts have a reputation they don’t deserve. They’re not a sign that something went wrong. They’re a sign that multiple people were working on the same codebase — which is exactly what you want on a productive team. Git couldn’t automatically decide how to combine their work, so it stopped and asked a human. That’s the system doing its job.
The skill of resolving conflicts well is really three separate skills. First, understanding what Git is telling you — reading the markers, identifying the type of conflict, knowing what three-way merging means. Second, making good decisions — understanding the intent of both sides before choosing how to combine them, not just accepting whichever version looks familiar. Third, preventing the big ones — keeping branches short, integrating frequently, communicating with teammates before touching heavily shared files.
All three improve with practice. The first time you resolve a conflict it takes fifteen minutes and feels uncertain. The fiftieth time it takes two minutes and feels routine. The hundredth time you’ve also developed the instincts to prevent many conflicts before they start.
Set merge.conflictstyle diff3 globally so you always see the base version. Configure a good merge tool. Turn on rerere if your team touches the same files repeatedly. And stop being afraid of the conflict message — it’s just Git asking you a question.
About the Author
Kedar Salunkhe
DevOps Engineer | Seven years of fixing things that break at 2am
Kubernetes • OpenShift • AWS • Coffee
I’ve spent almost 7 years keeping production systems running, often when everyone else is asleep. These days I’m working with Kubernetes and OpenShift deployments, automating everything that can be automated, and occasionally remembering to document the things I fix. When I’m not troubleshooting clusters, I’m probably trying out new DevOps tools or explaining to someone why we can’t just “restart everything” as a debugging strategy. You can usually find me where the coffee is strong and the error logs are confusing.