Conflict Resolution (Java/Gradle)
Overview
Handle merge/rebase conflicts systematically to maintain code integrity.
Core principle: Conflicts require careful resolution, not just picking one side.
Workspace facts:
- Repos are Java + Gradle (Spring Boot), branched off
master(notmain) unless the repo uses another trunk. - Shell may be Windows PowerShell. Run Gradle with
.\gradlew(or./gradlewin git-bash). - Build/verify command is
./gradlew clean build. spotlessmay reformat code on build (spotlessApply); expect formatting/import-order changes.- A library module is verified via build +
publishToMavenLocal. - A runnable Spring Boot app is verified via
bootRun(clean startup).
Announce at start: "I'm using conflict-resolution to handle these merge conflicts."
When Conflicts Occur
| Situation | Example |
|---|---|
| Rebasing on updated master | git rebase origin/master |
| Merging master into branch | git merge origin/master |
| Cherry-picking commits | git cherry-pick <sha> |
| Pulling with local changes | git pull |
The Resolution Process
Conflict Detected
│
▼
┌─────────────────┐
│ 0. SAFETY NET │ ← Create backup branch (revertable)
└────────┬────────┘
▼
┌─────────────────┐
│ 1. UNDERSTAND │ ← What's conflicting and why?
└────────┬────────┘
▼
┌─────────────────┐
│ 2. ANALYZE │ ← Review both versions
└────────┬────────┘
▼
┌─────────────────┐
│ 3. RESOLVE │ ← Make informed decision
└────────┬────────┘
▼
┌─────────────────┐
│ 4. VERIFY │ ← Build passes, app runs
└────────┬────────┘
▼
┌─────────────────┐
│ 5. CONTINUE │ ← Complete the operation
└─────────────────┘
Step 0: Create a Safety Net (do this FIRST)
Before starting any rebase/merge or touching conflicts, make the state revertable.
- Confirm a clean working tree (commit or stash local changes first):
git status
- Record the current commit and create a backup branch that points at it:
# Record where you are (copy the SHA somewhere)
git rev-parse HEAD
# Create a backup branch at current HEAD (does not switch branches)
git branch backup/<current-branch>-pre-merge
Use a clear, unique name, e.g. backup/feature-PROJ-1234-pre-rebase. If one exists, add a numeric suffix.
- Only now start the operation (
git rebase origin/master,git merge origin/master, etc.).
To revert to the old state at any point:
# Abort the in-progress operation
git rebase --abort # or: git merge --abort
# If already past the point of abort, hard-reset back to the backup
git reset --hard backup/<current-branch>-pre-merge
# Last resort: find the pre-conflict commit
git reflog
git reset --hard <good-sha>
Delete the backup branch only after the build passes, the app runs, and the change is pushed:
git branch -D backup/<current-branch>-pre-merge
Step 1: Understand the Conflict
# List files with conflicts
git status
# See the conflict markers in a file
git diff <path>
<<<<<<< HEAD
// Your changes (current branch)
public User createUser(UserData data) {
return new User(data, generateId());
}
=======
// Their changes (master)
public User createUser(UserData data) {
return repository.save(new User(data, generateId()));
}
>>>>>>> origin/master
# See what changed on each side
git log --oneline --left-right HEAD...origin/master -- <path>
git diff HEAD...origin/master -- <path>
Step 2: Analyze Both Versions
| Question | Consider |
|---|---|
| What was the intent of your change? | Your feature/fix |
| What was the intent of their change? | Their feature/fix |
| Are they mutually exclusive? | Can both coexist? |
| Which is more recent/correct? | Check issue references |
| Do both need to be kept? | Merge the logic |
Step 3: Resolve the Conflict
Keep Theirs (master)
git checkout --theirs <path>
git add <path>
Keep Ours (your branch)
git checkout --ours <path>
git add <path>
Note: during a rebase,
--ours/--theirsare inverted (ours = master, theirs = your commit). Readgit statusheader to confirm.
Manual Merge (both)
Remove ALL conflict markers and combine logic intentionally:
public User createUser(UserData data) {
validateUserData(data); // your addition
return repository.save(new User(data, generateId())); // their change
}
git add <path>
The final file must have NO <<<<<<<, =======, or >>>>>>> markers.
Step 4: Verify Resolution
No leftover markers
git diff --check
git grep -nE "^(<<<<<<<|=======|>>>>>>>)" -- src
Both should return nothing.
Build (required)
./gradlew clean build
- If it fails on checkstyle/spotless, fix, save, and re-run — spotless may rearrange imports/formatting.
- If it fails after 3 attempts, stop and ask the user for guidance before continuing.
The application must run (required)
After the build passes, confirm the artifact actually works:
- Spring Boot app: start it and confirm clean startup, then stop it.
./gradlew bootRun
# Wait for "Started ...Application in N seconds", confirm no startup errors, then stop (Ctrl+C).
- Library module: publish locally so downstream can consume it.
./gradlew publishToMavenLocal
Do not consider the conflict resolved until the build passes and the app starts / the library publishes cleanly.
Step 5: Continue the Operation
After Rebase
git rebase --continue
# repeat resolution for further conflicts
git push --force-with-lease
After Merge
git commit # completes the merge (keep default merge message or a clear one)
git push
If resolution goes wrong
git rebase --abort # or: git merge --abort
git reset --hard backup/<current-branch>-pre-merge
Complex Conflicts
Multiple files
Resolve one file at a time: edit → git add <file> → next. When all are staged, git rebase --continue (or commit the merge).
Semantic conflicts
Code can merge cleanly but still be broken (e.g. a caller uses an old method signature). This is why ./gradlew clean build and running the app are mandatory after resolution.
Generated sources
If the project regenerates sources from OpenAPI/config on build, do not hand-resolve conflicts in generated folders — resolve the inputs, then ./gradlew clean build regenerates them.
Dependency conflicts (build.gradle / gradle.properties)
<<<<<<< HEAD
libraryVersion = "0.32.0"
=======
libraryVersion = "0.31.0"
>>>>>>> origin/master
- Choose the correct version (usually the higher/newer unless there is a reason not to).
- Re-run
./gradlew clean buildso dependency resolution and locks update.
Checklist
- Working tree clean; backup branch
backup/<branch>-pre-mergecreated - All conflicting files identified
- Each conflict analyzed (both sides understood)
- Conflict markers removed; files staged (
git add) -
git diff --checkand marker grep are clean -
./gradlew clean buildsucceeds - Application runs (
bootRunfor app) / library publishes (publishToMavenLocal) - Operation completed (
git rebase --continue/ merge commit) - Backup branch deleted only after push succeeds
Integration
Called when git rebase, git merge, or a PR/MR shows conflicts. Ensures a revertable safety net, clean resolution, a passing ./gradlew clean build, and a working application.