merge-conflict-resolver

📁 cesar-rodriguez/skills 📅 9 days ago
2
总安装量
2
周安装量
#72699
全站排名
安装命令
npx skills add https://github.com/cesar-rodriguez/skills --skill merge-conflict-resolver

Agent 安装分布

opencode 2
gemini-cli 2
antigravity 2
claude-code 2
codex 2
kiro-cli 2

Skill 文档

Merge Conflict Resolver

Resolves merge conflicts on GitHub PRs autonomously. Clones, rebases, resolves, tests, pushes.

Usage

Given: repo=owner/repo pr=96
1. Resolve merge conflicts on PR #96
2. Run tests to verify
3. Push if clean, bail if uncertain

Workflow

# 1. Setup
WORKDIR=$(mktemp -d)
cd "$WORKDIR"
gh repo clone "$REPO" . -- --depth=100
gh pr checkout "$PR"
PR_BRANCH=$(git branch --show-current)
TARGET_BRANCH=$(gh pr view "$PR" --json baseRefName -q .baseRefName)

# 2. Rebase
git fetch origin "$TARGET_BRANCH"
git rebase "origin/$TARGET_BRANCH" 2>&1 || true
# If no conflicts, we're done — push and exit

# 3. Detect & resolve conflicts (loop until rebase complete)
# For each conflicted file, classify and resolve (see Decision Tree)
# After resolving: git add <file> && git rebase --continue

# 4. Post-resolution fixups
# Go: go mod tidy (regenerates go.sum)
# Node: npm install (regenerates package-lock.json)

# 5. Test
# Auto-detect: go test ./... | npm test | make test
# Override with test_cmd input

# 6. Push or bail
# Success: git push --force-with-lease origin "$PR_BRANCH"
# Failure: report what happened, don't push

Conflict Decision Tree

Classify each conflicted file, then apply the matching strategy:

1. go.sum → AUTO-RESOLVE

  • Accept either side (doesn’t matter which)
  • Run go mod tidy after all conflicts resolved
  • Always safe — go.sum is deterministically regenerated

2. go.mod → AUTO-RESOLVE (careful)

  • Keep both sides’ dependency additions
  • Run go mod tidy after to clean up
  • Bail if: conflicting version constraints on same dependency

3. package-lock.json → AUTO-RESOLVE

  • Accept either side
  • Run npm install after all conflicts resolved
  • Always safe — regenerated from package.json

4. Go import blocks → AUTO-RESOLVE

  • Use scripts/resolve_go_imports.sh on the file
  • Strategy: keep all imports from both sides, sort alphabetically within groups
  • Preserves blank-line grouping (stdlib / external / internal)
  • Always safe — duplicate imports cause compile errors caught by tests

5. Registration/init files (blank imports, init() calls) → AUTO-RESOLVE

  • Pattern: _ "github.com/org/repo/pkg" imports or Register("name", ...) calls
  • Keep both sides’ additions, sort alphabetically
  • Common in: cmd/*/main.go, *_test.go TestMain, plugin registrations
  • Always safe — duplicates caught by compiler/tests

6. Generated files (.pb.go, *_gen.go, mock_*.go) → SKIP

  • Accept theirs (target branch version)
  • Will be regenerated by build if needed
  • Bail if: no generation step available

7. Content conflicts → ANALYZE OR BAIL

This is the hard case. Analyze using merge base:

MERGE_BASE=$(git merge-base HEAD REBASE_HEAD)
git show "$MERGE_BASE:path/to/file" > /tmp/base.txt
# Compare: what did each side change relative to base?

Auto-resolve when:

  • Changes are in non-overlapping sections that git failed to merge (adjacent lines)
  • One side only added/removed whitespace
  • One side is a strict superset of the other (keep the superset)
  • Both sides made the identical change (keep either)

Bail when:

  • Both sides modified the same logic differently
  • Conflict involves control flow changes (if/else, switch cases)
  • Conflict is in test assertions (changing expected values)
  • You can’t determine intent from the diff alone
  • More than 3 content conflicts in a single file

Bail-Out Protocol

When bailing:

  1. git rebase --abort
  2. Clean up temp dir
  3. Report:
    • Which files had conflicts
    • Which were auto-resolvable vs not
    • For non-resolvable: show the conflict markers with context
    • Suggested resolution if you have one (but don’t apply it)

Principle: Never push code you’re not confident about.

Language Detection

# Go project
[[ -f go.mod ]] && LANG="go"

# Node project  
[[ -f package.json ]] && LANG="node"

# Both possible — check conflicted files to decide

Go-Specific Fixups

# After all conflicts resolved:
go mod tidy
goimports -w .  # if available, otherwise gofmt -w .
go build ./...  # quick sanity check
go test ./...   # full test

Node-Specific Fixups

npm install          # regenerate lockfile
npm run build        # if build script exists
npm test

Real-World Patterns

These patterns come from actual sprint conflicts (sg-policy):

Pattern: Parallel imports

Scenario: Two PRs both add imports to the same file. PR-A adds "sort", PR-B adds "strings". Resolution: Keep both, sort alphabetically. Mechanical.

Pattern: Parallel registrations

Scenario: Two PRs both add adapter registrations (blank imports + init code). PR-A adds k8s adapter, PR-B adds GHA adapter. Resolution: Keep both registrations, sort imports, merge any shared code (help text, auto-detect arrays) by combining entries.

Pattern: Lock file divergence

Scenario: Two PRs both ran go mod tidy or npm install, creating different lock files. Resolution: Accept either, re-run the lock command.

Integration with sprint-runner

When called from sprint-runner:

Input: repo, pr number, lane context (what the PR is doing)
Output: { resolved: bool, conflicts: [...], test_result: pass/fail, pushed: bool, bail_reason?: string }

Auto-Invocation Protocol

The sprint-runner automatically invokes this skill when:

  1. A PR’s mergeable status is CONFLICTING (checked after each merge in the sprint)
  2. A git merge or gh pr merge fails with conflict errors
  3. A rebase attempt fails during lane execution

Detection loop (sprint-runner runs this after each PR merge):

for pr in $(remaining_open_prs); do
  mergeable=$(gh pr view $pr --repo $REPO --json mergeable -q .mergeable)
  if [[ "$mergeable" == "CONFLICTING" ]]; then
    # Invoke merge-conflict-resolver with: repo, pr, test_cmd
  fi
done

Retry Policy

  1. First attempt: Auto-invoke this skill with full context
  2. If bail (semantic conflict): Sprint-runner tries cherry-pick-to-new-PR:
    • Create new branch from main
    • Cherry-pick the PR’s commits
    • Open replacement PR, close old one (pattern: PR #119 → #122 in sg-policy)
  3. If cherry-pick also fails: Escalate to human with:
    • Which files conflict
    • What each side changed
    • Suggested resolution (if available)
    • The lane is paused until resolution

Post-Merge Conflict Scan

After resolving a conflict, re-check all remaining open PRs — fixing one conflict can cascade (especially with shared import blocks or go.sum).

Lessons from Production

sg-policy Epic #114

  • PR #119 had import block conflicts after parallel lane merges
  • Auto-rebase failed → cherry-picked to replacement PR #122
  • Lesson: Always re-scan all open PRs after merging any PR that touches shared files

Common Conflict Hotspots

  • go.sum / package-lock.json — always auto-resolvable, always regenerate
  • Import blocks in Go files — keep both sides, sort, run goimports
  • Registration/init files (blank imports) — keep both, sort alphabetically
  • Hot files (high churn) — flag these in the execution plan for lane serialization