AgentSkillsCN

upstream

将上游模板的变更同步至您品牌化的分支。

SKILL.md
--- frontmatter
name: upstream
description: Sync upstream template changes into your branded fork

Upstream Skill

Merge upstream template improvements into your branded fork while preserving your project's branding.

Usage

code
/upstream [command]

Commands:

  • /upstream or /upstream sync — Merge latest upstream changes
  • /upstream status — Show upstream remote state and pending changes
  • /upstream remote [url] — Add or update the upstream remote URL

Core Concept

Branded files (listed in .claude/brand.json) are owned by the fork — upstream changes to those files are ignored. The skill merges upstream using git merge --no-commit, then restores branded files to the fork's version with git checkout --ours.

Commands

/upstream or /upstream sync

Merge the latest upstream template changes, skipping branded files.

Step 1: Check for brand.json

Read .claude/brand.json. If it doesn't exist, warn the user:

code
Warning: .claude/brand.json not found — /brand hasn't been run.
Upstream merge will proceed without branded-file protection.
You may need to resolve conflicts manually in files that contain your project name.

Ask if they want to continue or run /brand first.

Step 2: Check upstream remote

bash
git remote get-url upstream 2>&1

If no upstream remote exists, ask the user for the template repo URL and add it:

bash
git remote add upstream <url>

Step 3: Fetch upstream

bash
git fetch upstream 2>&1 | tail -n 5

Step 4: Preview changes

Show new upstream commits since last merge:

bash
git log HEAD..upstream/main --oneline --no-decorate 2>&1 | head -20

If there are no new commits, report that the fork is up to date and stop.

Step 5: Categorize changed files

Get the list of files changed upstream:

bash
git diff HEAD...upstream/main --name-only

Compare against brandedFiles from brand.json. Show two lists:

  • Branded (will be skipped): files in both the diff and brandedFiles
  • Clean (will be merged): files in the diff but not in brandedFiles

Step 6: Confirm

Ask the user to confirm the merge.

Step 7: Merge with --no-commit

bash
git merge upstream/main --no-commit --no-ff 2>&1

Step 8: Restore branded files

For each file in brand.json's brandedFiles array:

bash
git checkout --ours -- <file>

Also restore lock files (these should be regenerated, not merged):

bash
git checkout --ours -- backend/uv.lock 2>/dev/null
git checkout --ours -- frontend/pnpm-lock.yaml 2>/dev/null

Stage the restored files:

bash
git add <all restored files>

Step 9: Check for conflicts

bash
git diff --name-only --diff-filter=U

If there are conflicts in non-branded files, show them to the user and help resolve them. These are real conflicts where both sides modified the same non-branded file.

Step 10: Regenerate lock files

bash
cd backend && uv lock 2>&1 | tail -n 5
bash
cd frontend && pnpm install 2>&1 | tail -n 5

Step 11: Show merged changes

Show what's actually being merged (the non-branded changes):

bash
git diff --cached --stat

Step 12: Commit

Suggest a commit message and let the user confirm or edit:

code
Merge upstream template updates

Merged upstream/main, preserving branded files.
bash
git commit -m "<message>"

/upstream status

Show the state of the upstream remote.

Step 1: Check remote

bash
git remote get-url upstream 2>&1

If no remote, tell the user to run /upstream remote <url> first.

Step 2: Fetch and compare

bash
git fetch upstream 2>&1 | tail -n 5
git log HEAD..upstream/main --oneline --no-decorate 2>&1 | head -20

Step 3: Show summary

  • Upstream remote URL
  • Number of commits behind upstream/main
  • List of changed files, marked as branded or clean

/upstream remote [url]

Add or update the upstream remote.

If a URL is provided:

bash
# Check if upstream remote already exists
git remote get-url upstream 2>&1

If it exists, update it:

bash
git remote set-url upstream <url>

If it doesn't exist, add it:

bash
git remote add upstream <url>

Then verify:

bash
git remote get-url upstream

If no URL is provided, show the current upstream remote URL.

Edge Cases

  • No brand.json: Proceed with a warning. All files will be merged normally (no branded-file protection). Conflicts are resolved manually.
  • Merge conflicts in non-branded files: These are real conflicts. Show them and help the user resolve each one.
  • Lock files: Always restore to the fork's version and regenerate rather than trying to merge.
  • Dirty working tree: Check git status --short before merging and warn if dirty.

Important Notes

  • Always protect the context window — use | tail -n N and | head -N on git commands that could produce large output.
  • Never force-push or use destructive git operations.
  • The merge commit should clearly indicate it's an upstream sync.