본문으로 건너뛰기
cccskills
무료GitHub에 공개

merge-conflicts

How to bring a branch up to date and resolve git merge conflicts the way this repo expects — merge (never rebase or force-push), understand each side's intent before choosing, ask when a resolution isn't clear-cut, keep the merge commit to just the merge, and audit what merged *cleanly* before committing. Trigger whenever you're about to run `git merge`/`git pull`, sync a branch with `main`, "update from main", or resolve conflict markers left by a merge, cherry-pick, or interrupted pull — including bare phrasings like "fix the conflicts", "merge main in", or "this branch is behind". Not for merging data/files (PDFs, CSVs) or algorithms (merge sort) — this is strictly about git branch integration.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index스타 308(GitHub 308 + cccskills 0)
연동 도구GitHub

실행 점수 미검증

설치 방법 보기

포함된 파일(1)

  • SKILL.md12.5 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Resolving merge conflicts

Determine the base branch first — don't assume main

Re-read git branch --show-current rather than trusting the branch from earlier in the session. Conductor runs sessions concurrently, so another one can check this worktree out onto a different branch and commit to it while your conversation is open — and the base you resolved for the branch you were on is then the wrong base, merged into work you haven't read.

"Update from base", "sync with main", "this branch is behind", "merge the base in" all need a base branch to merge from. Don't default to main. A branch is often stacked on another feature branch, and merging main instead silently pulls the wrong history — the diff looks "already up to date" against main while the real base has commits you're missing. Resolve the base in this order:

  1. A branch the user names — "update from X" / "base is X" wins outright.
  2. An open PR's base — gh pr view <branch> --json baseRefName. Also check the base of any feature branch you recently merged into this one (gh pr view <that-branch> --json baseRefName); a stack's branches usually share the same base.
  3. The upstream tracking ref, if it names a branch other than this one's own remote mirror (git rev-parse --abbrev-ref @{u}).
  4. The Conductor workspace target branch (from the workspace/system instructions) — a default hint, not the last word.

Re-resolve the base every time — it moves. When a base branch's PR merges, GitHub retargets the child PR (usually to main), so what you merged from last time may no longer be the base. Check gh pr view <branch> --json baseRefName, and gh pr list for whether the old base still has an open PR. A base whose PR has merged often keeps accumulating commits behind no PR at all; those aren't yours to integrate.

If 1–3 turn up nothing and the branch clearly builds on another feature branch — it was created by merging one in, was cut from main but layers work that lives on an unmerged branch, or the user talks about it as part of a stack — ask which branch to update from (offer the likely candidate) rather than merging main. Confirm before running the merge; a wrong base is expensive to unwind.

Bring a branch up to date

  • git fetch origin, then git merge --no-edit origin/<base> (the base resolved above, not reflexively main).
  • Read what the merge brought in from the merge itself, not from an earlier ahead/behind count — git log --oneline <pre-merge-HEAD>..<merge-commit>^2. Conductor worktrees share one .git, so refs/remotes/origin/* is shared too: another session's git fetch advances your base mid-conversation, and a count taken before the merge under-reports it. Telling the user "1 commit behind" and then merging 2 is how that surfaces.
  • Merge, never rebase. Republishing a rebased branch needs a force-push, and we never force-push.
  • If uncommitted work blocks the merge, commit that work first (it belongs to the branch anyway), then merge.
  • Already up to date → nothing to do.

Base already merged? Merge its final commit before main

This repo squash-merges, so a merged base lands on main as one commit sharing no ancestry with the base's real commits. Merge main straight into the stacked branch and every file the base added comes back as an add/add conflict — git has no common ancestor to three-way merge against, so it hands you files you never touched.

Merge the base's tip first, then main:

gh pr view <base-pr> --json headRefOid --jq .headRefOid  # tip survives branch deletion
git fetch origin <sha>                                   # or refs/pull/<base-pr>/head
git merge --no-edit <sha>
git merge --no-edit origin/main

That makes your side byte-identical to what the squash put on main, so the add/add conflicts collapse and you're left only with files this branch actually changed.

The branch is usually deleted locally and on the remote by then, so don't look for origin/<base>; headRefOid and refs/pull/<n>/head are how you reach the commit.

Part of this branch already shipped as its own PR

Same cause the other way round: work split off this branch into its own PR lands on main as one squash commit, so every file both touched conflicts. main's side is the reviewed version of your own change — take it, then check that git diff origin/main lists only the work that PR left out.

Keep the merge commit to just the merge

A merge commit should contain only the reconciliation of the two histories — nothing else. Don't fold in lint fixes, refactors, renames, or "while I'm here" cleanups; buried inside a merge they're invisible in most diff views. Land them as separate commits after the merge.

Resolving conflicts

When git leaves <<<<<<< / ======= / >>>>>>> markers:

  • Understand each side before choosing. The version on main and the version on the branch each exist for a reason. Read enough of both to know what each is trying to do — don't mechanically keep "ours" or "theirs." The correct resolution is often a combination, not one side wholesale.
  • Consider the branch's purpose. What is this branch trying to accomplish? A conflict resolution that quietly drops the branch's intent (or reverts something main deliberately changed) is a bug, even if it compiles.
  • Ask when it isn't clear-cut. If you can't confidently tell which side should win, or the two changes are semantically entangled, stop and ask the user rather than guessing. A wrong silent resolution is worse than a question.
  • Both sides added at the same spot? Order matters. Keeping both isn't enough when either block has side effects. If the incoming block ends by reloading the page, anything of yours that depends on unsaved state has to come after it — concatenated the other way it still passes while testing nothing.
  • Taking one side resolves the marked blocks, not the file. git checkout --ours/--theirs replaces the whole file, discarding the other side's hunks that merged cleanly around the conflict. Delete the unwanted half of each <<<<<<< block instead; git checkout -m -- <file> restores the markers if you already reached for it.
  • Don't blanket-replace a renamed string. Two call sites that shared a string can have legitimately diverged; sed-ing the whole file changes the one that shouldn't move.
  • A conflicted schema_migrations list takes both versions. Each side appended its own migration, so keep both lines in descending order — in db/structure.sql and db/primary_replica_structure.sql alike — then bin/rails db:migrate to re-dump. Never hand-edit the structure files.
  • After resolving, verify the result actually makes sense — the merged code should reflect both intents, not just parse. Run the relevant tests if the conflict touched logic.

The dangerous part is what merged cleanly

Conflict markers are the easy case — git is asking for help. The silent breakages come from hunks it merged without asking, because a three-way merge keeps your side of any line it can't attribute to a common ancestor. A base that arrived as a squash-merge has history unrelated to yours, so git will cheerfully resurrect code that base deliberately deleted, in files it reports as auto-merged.

After every merge, before committing:

git diff origin/<base> -- app/ lib/ config/   # then account for every file listed

Every differing file must be explainable as this branch's work (or a sibling branch you're intentionally stacked on). Anything else is a resurrection or a stray. For a file that's mostly wrong, don't hand-patch hunks — git checkout origin/<base> -- <file> and re-apply your change on top.

Reverting a file to the base's version before you've merged that base takes whatever the base has gained since — commits your branch doesn't have, landing in your diff as your own work, and breaking against the code around them. git checkout $(git merge-base origin/main HEAD) -- <file> is the version your branch actually forked from.

Resolving two files to opposite sides breaks the interface between them, and neither looks wrong on its own. Taking the base's version of a component while the helper that calls it auto-merges keeping your argument is an unknown-keyword error on every render, past an audit that reports both files as expected. Whenever you reset a file that has callers, grep the arguments you dropped: git grep -n '<kwarg>' -- app should come back empty, or only where the base still accepts it.

What it catches:

  • Deleted code coming back. A constant, predicate, or callback the base removed reappears, along with the call sites that reference it — reintroducing behavior the base decided against.
  • Another branch's change riding along. A retention window, a flag, a tweak that came in when you merged a sibling branch and the base never took. Not yours to carry; reset it.
  • Committed churn in generated files. git checkout -- reverts to HEAD, not to the base — so once churn is committed it survives every later revert. Check VCR cassettes and lockfiles specifically; a diff that's only timestamps/nonces should be reset to the base.
  • Your side calling an API the base deleted. Nothing conflicts: your file is untouched by the merge and the base's deletion lands cleanly, so the break is a NoMethodError at load. Fix it in the commit after the merge, never in it.

Extracting a slice of another branch: git checkout <branch> -- <file> overwrites, it doesn't merge

Pulling part of a feature branch into a fresh one takes the file whole, so for anything main has moved since that branch last merged, you silently revert the newer work — no conflict, no warning. List the overlap first, and hand-apply those hunks:

MB=$(git merge-base origin/main origin/<branch>)
comm -12 <(git diff --name-only $MB origin/main | sort) <(git diff --name-only $MB origin/<branch> | sort)

A merged Gemfile.lock needs bundle install before anything else runs

A dependency bump arriving in the merge leaves the lockfile ahead of what's installed, and every bin/ script and spec then dies at boot with Could not find <gem> in locally installed gems (Bundler::GemNotFound). That reads like a broken script rather than a missing gem — bundle install is the whole fix, and it should leave the lockfile untouched (if it rewrites it, the merge resolved it wrong). A bin/dev already running keeps its old gems until it restarts — bin/rails restart is enough, and leaves its watchers up.

Run the linter, not just the specs

bin/lint after every merge. A bad auto-merge that duplicates a method or strands a constant parses fine and passes its specs — Lint/DuplicateMethods is what catches it.

Then run specs for the merged area, including the browser ones. The base renaming or moving something your branch calls produces no conflict marker at all: a method that moved to a service, a route reshaped into a query param, copy your specs assert on. Those only surface at runtime.

bin/rails db:migrate too, when the merge brought migrations — the test database is maintained from the schema, so the specs stay green while every page in the browser is an ActiveRecord::PendingMigrationError.

bin/rails tailwindcss:build when the merge brought app/assets/tailwind/**, before the browser specs — they read app/assets/builds/tailwind.css, so a rule the base added is missing until it's rebuilt and the failure names the assertion (a border width, a radius) rather than the build.

Never force-push

No exceptions, even on a personal branch. If history has already diverged from the remote and you're tempted to force-push, stop and merge origin/<branch> back in — then add follow-up work as new commits and push normally.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Read live production data from Bike Index through the admin OAuth token — Sidekiq and PgHero status, and the user-submitted bug reports — the same data as the cookie-gated dashboards, but agent-friendly JSON. Trigger when the user asks about production queue depth, job backlog, retries/dead jobs, running Sidekiq processes, or Postgres health (slow/blocked queries, index usage, unused/invalid indexes, connection counts, table/db sizes, vacuum/transaction-id danger) — and wants the *live* answer from production rather than logs or Honeybadger. Also trigger for anything about bug reports users have emailed in: what's been reported, searching/filtering them by status, tag or membership, or tagging one / linking it to the PR that fixes it. Also trigger when a request returns 401/expired and the AdminData token needs refreshing/re-authorizing. Not for reading log files (use production-log-inspection) or aggregated exception triage (bin/binx_hb).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

How to fix a test that fails intermittently in Bike Index — one that passes locally but fails on CI, fails on one shard, passes on re-run, or is already tagged `:flaky`. **Read this before touching any spec that is failing intermittently, and before adding, raising, or relying on a `flaky:` tag or a `wait:` bump.** Trigger on a CI failure the user calls flaky, unreliable, intermittent, "green locally", "passes on retry", "fix CI", or a pasted `gh run`/Actions URL whose failure isn't reproducible; also whenever you catch yourself about to delete, skip, loosen, or retry an assertion to make a red build go green. **Equally: any spec that fails intermittently while you verify your own work** — deciding whether your change caused a flake, or whether to ship past one, is this skill's problem too, and it arrives with no CI run, no `:flaky` tag, and nobody but you calling it flaky.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Bike Index's frontend conventions — Tailwind class prefixing (`tw:`), the standard `twinput`/`twlabel`/`twlink` form/link classes, the `number_display` helper for numbers, `Counts` for site-wide figures (bikes registered, recoveries, organizations), the UI component library rule (every button is `UI::Button`/`UI::ButtonLink`, every typeahead/autocomplete is `UI::Forms::Combobox`, every FAQ is `UI::Accordion`, never hand-rolled markup), that **helpers are deprecated — render a view component taking full keyword arguments instead of adding or extending one**, ViewComponent rules (when to write a partial instead, keyword arguments, instance variables, `helpers.` prefix in templates), and `UI::Time::Component` for every date/time. Trigger when adding or modifying views (`.html.erb`), view components, Stimulus controllers, Tailwind classes, image or icon files under `app/assets/images` (which usually already exist), or any frontend code that touches styling or interactivity — including admin screens, whose unlayered legacy CSS inverts several of these rules. Stimulus.js is the JavaScript framework; SCSS and CoffeeScript files exist but are deprecated.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Capture desktop+mobile screenshots of Bike Index pages from the local `bin/dev` server via Playwright MCP, with a seeded-user identity gate that keeps PII out of uploaded images. Use whenever a task needs screenshots of local pages — PR documentation, bug repros, before/after comparisons across branches, design review, demos — including mid-interaction states like an open dropdown, a modal showing, a form mid-fill, or a hover. Use it even when the user just says "grab a screenshot" or "show me what this looks like" without naming Playwright. For a component that only renders under an env var / feature flag / hard-to-reach state (e.g. the review-app banner), screenshot its ViewComponent/Lookbook preview URL instead of a full page. **Also read the filename rule here before any `mcp__playwright__browser_take_screenshot` call**, including a one-off capture of some other site — it's what keeps PNGs out of the working tree.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Embed a local image file into an existing GitHub PR — either in the PR body or as a comment. Trigger when a request pairs a local image (screenshot, .png/.jpg, CleanShot capture, before/after) with an existing PR (by #number, URL, branch name, or "the open PR"), regardless of verb — attach, embed, add, put, post, drop, show, document. Also covers visually documenting test runs, bug repros, UI states, or CI failures on an existing PR. Uploads through `gh`'s `--attach` flag — except in the Claude Code web sandbox, which has no `gh` and hosts images through the PR branch's history instead. It also owns the PR's one `## Screenshots` comment — finding, creating, editing and verifying it — so other workflows (the `pr` skill's screenshot phase) hand it a composed body that references local image paths, and it posts it.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

Investigate and fix a specific Honeybadger exception in the Bike Index app — pull the fault, read its backtrace, find the offending code, write the fix. Trigger whenever a request names one Honeybadger error: a pasted fault URL (`app.honeybadger.io/projects/…/faults/…`), a fault ID, an error class plus "in production" (`Vips::Error`, `NoMethodError in AfterStolenRecordSaveJob`), or phrasings like "fix this Honeybadger error", "why is this erroring in prod", "what's causing this exception", "look at this HB fault". Use `bin/binx_hb` for fault and notice detail; it is the only Honeybadger reader this repo uses. Not for a broad production health sweep across many sources, and not for reading raw log files (that's production-log-inspection).

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

bikeindex/bike_index3082026년 10월 29일 업데이트

bikeindex의 스킬 모두 보기

이 스킬의 문제 신고