From sync-repos
Synchronizes commits between two git remotes with unrelated histories via cherry-pick, preserving original authorship and committer metadata. Use when the user asks to sync repos, bring upstream changes, push to public, cherry-pick between remotes, or mentions syncing a fork. Also triggers on "sync from upstream", "push changes to public", "bring in latest changes", "pull from public repo", or any mention of keeping two repositories in sync.
How this skill is triggered — by the user, by Claude, or both
Slash command
/sync-repos:sync-reposThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Cherry-pick commits between two git remotes that have no shared history, preserving author and committer metadata. Designed for repos that diverged after a force-push or independent initialization.
Cherry-pick commits between two git remotes that have no shared history, preserving author and committer metadata. Designed for repos that diverged after a force-push or independent initialization.
Two files in .claude/sync/ control this skill:
.claude/sync/state.json (required)Tracks which remotes to sync and the last synced commit on each side. If this file doesn't exist, start with Initial Setup (below).
{
"remotes": {
"origin": { "url": "https://github.com/org-a/repo", "branch": "main" },
"upstream": { "url": "https://github.com/org-b/repo", "branch": "main" }
},
"last_sync": {
"origin_hash": "abc1234",
"upstream_hash": "def5678",
"synced_at": "2026-03-23T00:00:00Z"
}
}
.claude/sync/guide.md (optional)Natural-language guidelines for private-to-public sensitivity review. Read this file during Phase 2 to decide which commits need modification or exclusion. Without it, rely on general judgment and inform the user that this file can be created for more precise guidance.
This skill has 4 phases with 3 approval gates. The user must explicitly approve before any cherry-pick, push, or PR creation happens — because sync mistakes are hard to undo and can leak sensitive content.
Run this when .claude/sync/state.json doesn't exist.
git remote -v)..claude/sync/state.json after user confirms the contents..claude/sync/state.json and fetch both remotes. If the repo uses Git LFS, also run git lfs fetch <source-remote> --all — cherry-pick will fail with smudge errors if LFS objects aren't cached locally..claude/sync/guide.md doesn't exist, mention it: ".claude/sync/guide.md not found — this file can provide repo-specific guidelines for identifying sensitive content. Proceeding with general-purpose review."Wait for explicit confirmation before continuing.
git show --diff-merges=first-parent --stat. Merge commits with no unique diff are safe to skip (their child commits already cover the changes). Flag any with unique changes so the user can decide. See references/git-commands.md for details..claude/sync/guide.md (if present), then review each commit's diff and classify it:
git cherry-pick.cherry-pick --no-commit, apply edits, then commit with preserved metadata. See references/git-commands.md for the exact environment variable approach.The user approves the recommended plan, requests adjustments, or aborts.
After user approval:
sync/<source>-to-<target>/<YYYY-MM-DD>.references/git-commands.md. On conflict, stop and ask the user whether to resolve, skip, or abort. On empty commit (already applied), skip with a note.Wait for explicit approval before pushing.
Push the sync branch.
Create a PR targeting the target branch.
sync: <source> → <target> (<date>). Body: commit summary, files changed, modifications made.#<number> references (e.g. (#34)) that point to the source repo, not the target. In the PR body, qualify these with the full owner/repo#number format so readers aren't misled by bare #N links resolving to unrelated target-repo issues.Ask the user which merge strategy they will use. Recommend merge commit — squash and rebase rewrite commit hashes, which complicates state tracking.
Update .claude/sync/state.json based on the chosen strategy:
If merge commit — update state on the sync branch before the PR is merged:
If squash or rebase — update state after the user merges the PR:
.claude/sync/state.json on the target's main branch — set both hashes to their respective remote HEADs post-merge. Commit and push.Cherry-picking onto the target branch directly is risky — a sync branch with a PR gives the user a chance to review the full diff and revert cleanly if something goes wrong.
Merge commits can't be cherry-picked directly (git doesn't know which parent to diff against). Skipping them is usually correct because the individual commits already carry the changes, but merge commits sometimes contain conflict resolution code that exists nowhere else. That's why Phase 2 checks each one.
Sensitive content must never enter git history in private-to-public sync — once pushed, it's in the reflog even after force-push. The --no-commit approach ensures redaction happens before the commit is created.
Author and committer metadata (name, email, date) are preserved through environment variables when using --no-commit. This matters because cherry-pick normally handles this automatically, but --no-commit followed by a manual commit would default to the current user's identity.
Force-pushing is never appropriate in this workflow. If a push is rejected, ask the user rather than forcing.
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub milkclouds/my-dev-playbook --plugin sync-repos