Project Merge
Two projects, A and B, grew from a similar baseline but diverged — each added different features, and one is generally better than the other. The goal is one project that contains the union of both projects' working features, built on the better base, with nothing from either side lost.
This is delicate work: a naive merge silently drops features or breaks the base. The whole point of this skill is to be deliberate — understand both sides first, pick the easier merge direction, integrate carefully, then prove nothing was lost.
The mental model
Think of it as a directed graph: you pick a base (the project you keep and build on) and a source (the project you pull features from). You're transplanting the source's unique features onto the base. "把 b 缝进 a" means base=A, source=B.
The base should almost always be the project that works better and/or has the cleaner architecture, because you keep its code largely intact and only graft additions onto it. Grafting onto a solid base is far easier than rebuilding a weak base's missing pieces.
Workflow
Work through these phases in order. Don't skip the understanding phases to rush into editing — a merge done without understanding both sides is the most common way features get silently lost.
Phase 1 — Locate both projects and ask the key questions
First find the two project roots (ask the user for the two paths if not obvious). Then ask the user up front — these answers shape everything:
- Which project works better in practice, and why? The "why" matters enormously — it tells you what to protect. ("B's output is more accurate", "A keeps crashing on large inputs", "B's UX is smoother".) If the user can be specific about what is better, capture it.
- Which project should be the merge base? If the user has a preference, honor it. If they don't, tell them you'll decide after analysis (Phase 4) and explain your choice.
- Any features from the worse project that must NOT be carried over? Sometimes the worse project has experiments the user wants dropped. Knowing this prevents wasted work.
- Where should the merge happen — on a safe working copy, or in place on the base project? Recommend the working copy (it keeps a pristine original for verification and rollback in Phase 7), but honor an in-place preference. Note that if the base is a git repo, a branch gives in-place editing with a recoverable original — the best of both. Details and setup are in Phase 5.
Ask these together (one round of questions), then proceed. Don't interrogate the user phase by phase.
Phase 2 — Understand both projects independently
Read enough of each project to genuinely understand it. For each project, build a picture of:
- Entry points & structure: how it's organized, where execution starts, the main modules.
- Dependencies & build/run setup: package manifests, build scripts, how tests run.
- Feature inventory: a concrete list of what this project does — user-facing capabilities and notable internal mechanisms.
For large projects, this is a good place to fan out: spawn one Explore/general-purpose subagent per project (or per major subsystem) so you can read breadth in parallel and get back structured inventories rather than reading everything yourself. Have each subagent return a feature list + file map.
Phase 3 — Diff the two: shared baseline vs. unique features
This is the heart of the analysis. Produce three explicit lists:
- Shared baseline — code/structure common to both (the original starting point, possibly drifted on each side). This is what you don't need to merge; it's the common ground. Note where the two sides have diverged on shared files — those are your real conflict zones.
- A-only features — capabilities present in A but not B.
- B-only features — capabilities present in B but not A.
For each unique feature, note which files implement it and what it touches (so you know its blast radius when transplanting). Where both sides modified the same baseline file differently, flag it explicitly — these are the spots that need careful manual merging rather than copy-paste.
Then answer the user's "why is X better" with evidence from the code: is it a better algorithm? more robust error handling? a fix the other side never made? This analysis directly informs what to protect during the merge.
Present this analysis to the user before moving on — a short, readable summary (shared baseline, A-only, B-only, why-better). This is cheap insurance: the user can correct a misunderstanding before you write a line of code.
Phase 4 — Decide the merge direction (if the user didn't)
If the user already chose the base, use it. Otherwise decide, and explain your reasoning. Pick the base by asking: which direction transplants fewer / less-entangled features?
Strong signals for choosing a base:
- It works better / is more correct. Keep the code that already behaves well; don't risk regressing it.
- It has the cleaner or more modular architecture. Easier to graft onto.
- It would receive fewer or more self-contained features. If A's unique features are 3 tidy modules and B's are scattered across the whole codebase, make B the base and graft A's 3 modules in — less surface area to disturb.
These can conflict (the better-working project might have the messier code). When they do, prefer the better-working project as base — correctness is harder to recover than cleanliness. State the tradeoff to the user.
Phase 5 — Set up a safe working copy
Act on the user's Phase 1 answer about where the merge should happen. If for some reason it wasn't settled there, ask now before editing — but normally you already have the answer and just execute it.
- On a working copy (recommended). Make a copy of the base project to merge into, so both originals stay pristine. This is what Phase 7 relies on: it lets you diff the merged result against the untouched originals to prove nothing was lost.
- In place, on the original base. Faster and avoids a duplicate directory, but it sacrifices the pristine base as a verification/rollback reference. Only safe when there's another safety net — see the git note below.
How to set it up depending on the choice and the VCS situation:
- Base is a git repo: create a new branch (e.g.
git switch -c merge/from-<source>). This is the best of both worlds — edits are "in place" in the same directory, but the original base stays recoverable on its branch andgit diffgives you the comparison Phase 7 needs. Prefer this when git is available, whichever option the user picked. (Commit or stash any pending changes first so the pre-merge state is captured.) - Working copy, no git: copy the base project directory to a new location (e.g.
<base>-merged/) and edit there. - In place, no git: discouraged. If the user insists, at minimum take a one-time backup copy of the base first so rollback and the Phase 7 diff are still possible, and tell the user that's what you're doing.
Tell the user the exact path/branch where edits will happen. Keep the source project untouched regardless, so the verification phase can diff against it.
Phase 6 — Transplant the source's unique features
Now graft each source-only feature onto the base, one feature at a time (smallest/most-isolated first builds confidence and reduces churn). For each feature:
- Bring over its implementation files; wire them into the base's entry points, routing, config, and dependency manifests.
- Reconcile shared-but-diverged files by hand — merge the two versions so both the base's behavior and the source's feature survive. Don't blindly overwrite; that's how base features get clobbered.
- Add any new dependencies the feature needs to the base's manifest.
- Resolve naming/namespace collisions between the two projects.
Work in small, verifiable increments. After each feature (or small group), do a quick build/sanity check rather than transplanting everything and debugging a giant pile at the end.
Phase 7 — Verify: both feature sets present, nothing lost
This is non-negotiable — the merge isn't done until verified. Verify in three complementary ways:
- Run the tests. Run the base's test suite and port over the source project's tests for the features you transplanted, then run those too. A transplanted feature with its original tests passing is strong evidence it survived the move. Report actual results — if tests fail, say so with the output.
- Build it. Run the build/compile/lint step for the merged project. It must build cleanly. Fix what the build surfaces.
- Code-level feature audit. Go back to the Phase 3 lists (A-only + B-only) and check each feature off against the merged codebase: is its implementation present and wired in? This catches features that "merged" as dead code — copied in but never actually reachable. For anything you can't confirm by reading, note it explicitly rather than claiming success.
Produce a completion checklist mapping every unique feature from both projects to its status in the merged project (present & tested / present but untested / not yet merged / intentionally dropped). Plus the test and build results. Be honest about gaps — a checklist that hides a missing feature is worse than no checklist.
If anything is missing or broken, loop back to Phase 6 for that feature.
Output
At the end, give the user:
- The location of the merged working copy (path/branch).
- The completion checklist (every feature from A and B → status in the merged project).
- Test results and build status, stated plainly.
- Any features intentionally dropped (per the Phase 1 answer) or any gaps you couldn't resolve, called out explicitly.
Principles
- Understand before editing. Phases 2–4 exist so the merge is deliberate, not a hopeful copy-paste.
- Protect the base. You chose the base because it works; don't regress it while grafting features on.
- Preserve a ground truth. A pristine reference (working copy, git branch, or backup) is what verification and rollback depend on. The source project always stays untouched; let the user decide how to protect the base, but never edit it with no safety net.
- Prove it, don't claim it. "Merged" means tests pass, it builds, and every feature is accounted for on the checklist — not "I copied the files over."