惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Proofpoint News Feed
S
SegmentFault 最新的问题
The Last Watchdog
The Last Watchdog
人人都是产品经理
人人都是产品经理
C
Check Point Blog
O
OpenAI News
V
Visual Studio Blog
S
Security @ Cisco Blogs
I
InfoQ
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Troy Hunt's Blog
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
Attack and Defense Labs
Attack and Defense Labs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
SecWiki News
SecWiki News
月光博客
月光博客
U
Unit 42
博客园 - Franky
V2EX - 技术
V2EX - 技术
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
腾讯CDC
量子位
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic
Engineering at Meta
Engineering at Meta
PCI Perspectives
PCI Perspectives
Cisco Talos Blog
Cisco Talos Blog
Google DeepMind News
Google DeepMind News
博客园 - 司徒正美
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
TaoSecurity Blog
TaoSecurity Blog
Project Zero
Project Zero
WordPress大学
WordPress大学
A
Arctic Wolf
H
Help Net Security
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
Intezer
雷峰网
雷峰网
Security Latest
Security Latest
N
News and Events Feed by Topic
AI
AI
V
Vulnerabilities – Threatpost
S
Schneier on Security
Vercel News
Vercel News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Stop Wrestling with Merge Conflicts: Automate the Whole Workflow
pponali · 2026-05-13 · via DEV Community

It's 4:47 PM on a Friday. You've been coding all week on a feature you're proud of. You open a PR, and GitHub greets you with the one message that turns your stomach:

"This branch has conflicts that must be resolved."

You already know what's waiting. The pom.xml has diverged again. Someone on main bumped a YAML config. There are three Markdown docs with ugly <<<<<<< HEAD markers scattered through them. You're not shipping today.

Every software developer has lived this moment. And most of us keep solving it the same slow, error-prone, manual way — every single time.

This post is about why that's a problem, and how the /resolve-conflicts Claude Cowork skill fixes it — a first-class Claude skill you simply invoke in natural language, and Claude handles the entire workflow end to end.

🧩 The /resolve-conflicts skill is an installable Claude Cowork skill that automates your entire merge conflict workflow. The source code, shell script, and full documentation are open source on GitHub: github.com/pponali/claude_skills

The Real Pain Points Behind Merge Conflicts

Merge conflicts feel like a Git problem, but they're really a team coordination problem made visible. Here's what actually makes them brutal:

They always hit at the worst time. You finish a feature after days of work, go to merge, and suddenly you're debugging someone else's schema migration inside your application.yml. Context-switching mid-sprint to resolve config conflicts is a massive cognitive tax.

The same files conflict over and over. In any non-trivial project, you'll find the same suspects in your conflict list week after week: pom.xml, docker-compose.yml, *.properties, localization files, OpenAPI specs. These aren't complex logical conflicts — they're mechanical, repetitive, and boring. Yet they still demand your full attention.

Manual resolution is error-prone under pressure. When you're staring at a wall of ======= markers, it's easy to accidentally keep the wrong version, drop a dependency update, or smash together two configs in a way that silently breaks something. There's no guardrail — just you, your eyes, and your mouse.

The feedback loop is slow. You resolve conflicts, push, wait for CI, find out you introduced a bug in the config you just "fixed," fix it again, push again. The cycle can eat hours.

It doesn't scale with team size. On a small team, conflicts are annoying. On a team of 20+ engineers all merging into main frequently, they're a daily tax on every developer's time.

The Traditional Approach (And Why It Falls Short)

The standard workflow most of us follow looks like this:

git fetch origin
git merge origin/main
# ... open every conflicted file in VS Code ...
# ... manually choose ours / theirs / both ...
git add .
git commit -m "Merge branch 'main' into feature/my-thing"
git push

This works, but it has serious problems:

  • No consistency. Different developers make different choices for the same file types. One dev always keeps pom.xml from main; another always keeps the branch version. The merge history becomes unpredictable.
  • No documentation. The merge commit rarely explains why you resolved conflicts the way you did. Future you (and your teammates) have no idea.
  • No scalability. Every conflict requires a human to sit down and make individual decisions, even for files where the right answer is always the same.

Enter /resolve-conflicts: A Claude Cowork Skill That Does It All

The /resolve-conflicts skill is a Claude Cowork skill — meaning you don't run commands yourself. You just tell Claude what you want in plain English:

  • "Merge main into my branch and resolve conflicts"
  • "My PR shows conflicts — fix them"
  • "Sync my feature branch with origin/main"

Claude takes it from there. Under the hood it drives .claude/scripts/resolve-conflicts.sh — a shell script with codified heuristics for every file type in your project. The skill + script together are fully open source:

📦 github.com/pponali/claude_skills

The core idea: most conflicts in most projects follow predictable patterns. Once those patterns are encoded as a Claude skill, you never have to think about them again — just describe the problem and let Claude handle it.

Here's what Claude does behind the scenes when you invoke the skill:

# Step 1 — Claude runs a dry-run first and summarises what it found
.claude/scripts/resolve-conflicts.sh origin/main true

# Step 2 — After your confirmation, Claude runs for real
.claude/scripts/resolve-conflicts.sh origin/main false

Claude handles everything: stashing uncommitted changes, merging, resolving each conflict using the right heuristic, staging, creating an auditable commit, pushing, and optionally checking PR status via the gh CLI. You just review and confirm.

How the Resolution Heuristics Work

The script doesn't guess — it applies explicit, per-file-type rules:

File pattern Strategy Rationale
pom.xml, */pom.xml Keep branch (--ours) Feature branch usually holds newer or WIP dependencies
*.properties Keep branch Branch has local/feature-specific config values
*.yaml / *.yml Keep branch Same reasoning as properties
docker-compose.* Keep branch Preserves the current service topology
*.md Keep both (concatenated) Docs from both sides are usually additive, not contradictory
*.java Keep branch Active feature work lives on the branch
*.js, *.ts, *.tsx Keep branch Same as Java
anything else Keep branch + warning Safe default; flagged for manual review

"Keep branch" means the HEAD side of the merge — your feature branch. The strategy is opinionated by design. If your project has different conventions, you update the script once, and every future merge follows the new rules automatically.

The Markdown strategy is particularly clever: instead of picking one side, it concatenates both. Documentation is almost always additive — two sections from different branches are usually both worth keeping, so the merge result includes both and a human can clean it up later without losing information.

The Dry-Run Is Your Best Friend

Before running for real, always do a dry run:

.claude/scripts/resolve-conflicts.sh origin/main true

The output tells you:

  • Which files have conflicts
  • Which rule the script will apply to each one
  • Any files in the "unknown" bucket (these get --ours by default and a warning logged)

This is the moment to catch surprises. If main bumped a critical version in pom.xml that your branch must absorb, you'll see it here. You can let the script handle everything else and manually fix just that one file afterwards.

Verify, Don't Assume

After the script runs, always check:

# Should show your merge commit
git log --oneline -3

# MUST be empty — any output here means unresolved conflicts
git diff --name-only --diff-filter=U

# Quick overview of what changed
git show HEAD --stat

If your project has a fast smoke test — mvn -q -DskipTests verify, npm run typecheck, docker compose config — run it now. Heuristic resolutions are fast but not infallible.

If you're using the gh CLI:

gh pr view <number> --json mergeable,mergeStateStatus

Note: GitHub takes 1–2 minutes to recompute mergeability after a push. Don't panic if it shows conflicts for a moment after you push.

When NOT to Use the Script

The script is great for mechanical conflicts, but there are cases where you need a human in the loop:

Core business logic in .java / .ts / .js files where both sides have unique, non-overlapping changes. The script will keep the branch version and silently drop main's changes. If both sides implemented different parts of the same feature, you need to merge them manually.

A critical dependency update in pom.xml that your branch must consume. The script keeps your branch version. After it runs, manually edit the file, git add, and git commit --amend --no-edit.

Files in the "unknown" bucket (*.sql, *.proto, *.kt, etc.). The script flags these but defaults to --ours. Open them, check if main's changes matter, resolve manually, then fold into the merge commit:

# After manually editing the file:
git add path/to/file.sql
git commit --amend --no-edit
git push --force-with-lease origin your-branch

The pattern that works best: let the script handle the 80% of mechanical conflicts, then manually patch the 20% that need actual reasoning. You get speed and correctness.

Real-World Payoff

Once your team adopts this workflow, a few things change:

Merge commits become consistent and auditable. The commit message documents which strategy was applied to which files. Six months from now, you can look at a merge commit and understand exactly what happened.

Conflict resolution stops being a senior-developer task. The rules are encoded in a script, not in someone's head. A junior developer can merge safely without needing to ask "should I keep ours or theirs for the YAML?".

Friday afternoon PRs stop being feared. When conflict resolution is one command instead of a half-hour of careful manual editing, you stop dreading the merge.

Getting Started: Install the Claude Skill

Everything — the skill definition, the shell script, and full documentation — is in the open source repo:

📦 github.com/pponali/claude_skills

# Add the script to your project
mkdir -p .claude/scripts
curl -o .claude/scripts/resolve-conflicts.sh \
  https://raw.githubusercontent.com/pponali/claude_skills/master/.claude/scripts/resolve-conflicts.sh
chmod +x .claude/scripts/resolve-conflicts.sh

Once installed, just open Claude in Cowork mode and describe the problem. Claude will:

  1. Run pre-flight checks (detects if you're already mid-merge)
  2. Do a dry run and summarise exactly which files it will touch and how
  3. Ask for your confirmation before committing anything
  4. Merge, resolve, commit, push — and report back

You're always in control. Claude handles the mechanical parts, you handle the judgment calls.

Running the script directly (without Claude) is also supported:

# Dry run first — always
.claude/scripts/resolve-conflicts.sh origin/main true

# Then for real
.claude/scripts/resolve-conflicts.sh origin/main false

# Merge a different branch
.claude/scripts/resolve-conflicts.sh origin/feat/payment false

The Full Script

Drop this into .claude/scripts/resolve-conflicts.sh in your repo and make it executable (chmod +x). It's self-contained — no external dependencies beyond bash, git, and optionally the gh CLI for PR status checks.

#!/usr/bin/env bash
# =============================================================================
# resolve-conflicts.sh
# Automated merge-conflict resolution with per-file-type heuristics.
#
# Usage:
#   .claude/scripts/resolve-conflicts.sh [target-branch] [dry-run]
#
# Arguments:
#   target-branch  Branch to merge in. Default: origin/main
#   dry-run        true|false. Default: false
#
# Examples:
#   .claude/scripts/resolve-conflicts.sh                          # merge origin/main, for real
#   .claude/scripts/resolve-conflicts.sh origin/main true        # dry-run first
#   .claude/scripts/resolve-conflicts.sh origin/feat/payment false
# =============================================================================

set -euo pipefail

TARGET_BRANCH="${1:-origin/main}"
DRY_RUN="${2:-false}"

# Colour helpers
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; NC='\033[0m'
info()    { echo -e "${CYAN}[resolve-conflicts]${NC} $*"; }
success() { echo -e "${GREEN}[resolve-conflicts]${NC} $*"; }
warn()    { echo -e "${YELLOW}[resolve-conflicts] WARN:${NC} $*"; }
error()   { echo -e "${RED}[resolve-conflicts] ERROR:${NC} $*" >&2; }

# ---------------------------------------------------------------------------
# Pre-flight
# ---------------------------------------------------------------------------
if git rev-parse --verify MERGE_HEAD &>/dev/null; then
  error "Repo is already mid-merge (MERGE_HEAD exists)."
  error "Run 'git merge --abort' to cancel the previous merge, then retry."
  exit 1
fi

CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
info "Current branch : $CURRENT_BRANCH"
info "Target branch  : $TARGET_BRANCH"
info "Dry run        : $DRY_RUN"

info "Fetching origin..."
git fetch origin --quiet

# ---------------------------------------------------------------------------
# Stash any uncommitted changes
# ---------------------------------------------------------------------------
STASHED=false
if ! git diff --quiet || ! git diff --cached --quiet; then
  info "Stashing local changes..."
  git stash push -m "resolve-conflicts auto-stash $(date +%s)"
  STASHED=true
fi

# ---------------------------------------------------------------------------
# Attempt the merge
# ---------------------------------------------------------------------------
info "Merging $TARGET_BRANCH into $CURRENT_BRANCH..."
if git merge "$TARGET_BRANCH" --no-edit --no-commit 2>/dev/null; then
  success "Merge completed with no conflicts. Committing..."
  if [ "$DRY_RUN" = "false" ]; then
    git commit --no-edit -m "Merge $TARGET_BRANCH into $CURRENT_BRANCH (no conflicts)"
    git push origin "$CURRENT_BRANCH"
    success "Pushed."
  else
    git merge --abort 2>/dev/null || true
    info "[DRY RUN] No conflicts — merge would succeed cleanly."
  fi
  $STASHED && git stash pop || true
  exit 0
fi

CONFLICTED_FILES="$(git diff --name-only --diff-filter=U)"

if [ -z "$CONFLICTED_FILES" ]; then
  warn "Merge stopped but no conflict markers found. Check git status."
  git merge --abort 2>/dev/null || true
  $STASHED && git stash pop || true
  exit 1
fi

info "Conflicted files:"
echo "$CONFLICTED_FILES" | while read -r f; do echo "  - $f"; done

# ---------------------------------------------------------------------------
# Resolution heuristics
# ---------------------------------------------------------------------------
resolve_file() {
  local file="$1"
  local strategy="" reason=""

  case "$file" in
    pom.xml|*/pom.xml)
      strategy="ours";  reason="pom.xml — keep branch (feature deps)" ;;
    *.properties)
      strategy="ours";  reason="*.properties — keep branch (feature config)" ;;
    *.yaml|*.yml)
      strategy="ours";  reason="*.yaml/yml — keep branch (feature config)" ;;
    docker-compose*|*/docker-compose*)
      strategy="ours";  reason="docker-compose — keep branch (feature topology)" ;;
    *.md)
      strategy="union"; reason="*.md — keep both (documentation is additive)" ;;
    *.java)
      strategy="ours";  reason="*.java — keep branch (active feature work)" ;;
    *.js|*.ts|*.tsx|*.jsx)
      strategy="ours";  reason="*.js/ts — keep branch (active feature work)" ;;
    *)
      strategy="ours"
      reason="unknown type — defaulting to branch; MANUAL REVIEW RECOMMENDED"
      warn "No rule for: $file — keeping branch version. Please verify manually." ;;
  esac

  if [ "$DRY_RUN" = "true" ]; then
    info "[DRY RUN] $file$strategy  ($reason)"
    return
  fi

  info "Resolving: $file$strategy  ($reason)"

  if [ "$strategy" = "ours" ]; then
    git checkout --ours -- "$file"
    git add "$file"
  elif [ "$strategy" = "union" ]; then
    local ours theirs
    ours="$(git show :2:"$file" 2>/dev/null || true)"
    theirs="$(git show :3:"$file" 2>/dev/null || echo "")"
    { echo "$ours"; echo ""; echo "---"; echo "<!-- merged from $TARGET_BRANCH -->"; echo ""; echo "$theirs"; } > "$file"
    git add "$file"
  fi
}

while IFS= read -r file; do
  [ -n "$file" ] && resolve_file "$file"
done <<< "$CONFLICTED_FILES"

# ---------------------------------------------------------------------------
# Commit and push
# ---------------------------------------------------------------------------
if [ "$DRY_RUN" = "true" ]; then
  info "[DRY RUN] Complete. No files were changed."
  git merge --abort 2>/dev/null || true
  $STASHED && git stash pop || true
  exit 0
fi

STILL_CONFLICTED="$(git diff --name-only --diff-filter=U 2>/dev/null || true)"
if [ -n "$STILL_CONFLICTED" ]; then
  error "Some files are still unresolved — resolve manually, 'git add', then 'git commit'."
  echo "$STILL_CONFLICTED"
  $STASHED && git stash pop || true
  exit 1
fi

COMMIT_MSG="Merge $TARGET_BRANCH into $CURRENT_BRANCH (auto-resolved)

Heuristics applied:
$(echo "$CONFLICTED_FILES" | while read -r f; do echo "  - $f"; done)

Generated by resolve-conflicts.sh"

git commit -m "$COMMIT_MSG"
success "Merge commit created."

git push origin "$CURRENT_BRANCH"
success "Pushed to origin/$CURRENT_BRANCH."

if $STASHED; then
  info "Restoring stashed changes..."
  git stash pop || warn "Stash pop failed — run 'git stash list' to inspect."
fi

if command -v gh &>/dev/null; then
  info "Checking PR status (GitHub may take ~2 min to recompute)..."
  gh pr view --json mergeable,mergeStateStatus 2>/dev/null \
    | python3 -c "import json,sys; d=json.load(sys.stdin); print(f'  mergeable={d[\"mergeable\"]}  state={d[\"mergeStateStatus\"]}')" \
    || true
fi

success "Done. Run 'git log --oneline -3' to verify the merge commit."

Save it, make it executable, and you're ready:

mkdir -p .claude/scripts
# paste the script above into .claude/scripts/resolve-conflicts.sh
chmod +x .claude/scripts/resolve-conflicts.sh


Merge conflicts aren't going away. As long as multiple people work on the same codebase, there will be divergence. But the amount of manual, repetitive work they require is entirely within your control. Codify your team's conventions, automate the mechanics, and save the human judgment for the conflicts that actually need it.

Your future Friday self will thank you.