Code Sync
Batch sync all git repos under a base directory — push (end-of-day) or pull (start-of-day).
Default base directory: ~/code. Configurable via ~/.config/nini-skill/code-sync/config.md.
Prerequisites
| Tool |
Type |
Required |
Install |
| git |
cli |
Yes |
brew install git or git-scm.com |
| git-workflow |
skill |
Yes |
Included in npx skills add niracler/skill — must be invoked via Skill tool for all commits |
Do NOT proactively verify these tools on skill load. If a command fails due to a missing tool, directly guide the user through installation and configuration step by step.
First-Time Setup
On first use, check for config at ~/.config/nini-skill/code-sync/config.md.
If not found, ask the user:
- "Where do you keep your git repos?" (default:
~/code)
- "What's the directory structure?" — explain the expected pattern:
<base-dir>/*/ for top-level repos and <base-dir>/*/repos/*/ for monorepo sub-repos
- Save to
~/.config/nini-skill/code-sync/config.md:
base_dir: ~/code
Mode Selection
| User says |
Mode |
| 「下班同步」or "push" |
Push |
| 「上班更新」or "pull" |
Pull |
| 「同步代码」「code-sync」 |
Ask user |
Workflow (shared by both modes)
- Scan → 2. Categorize → 3. Batch action (auto, no confirmation) → 4. Handle exceptions (interactive) → 5. Summary
If all repos are up-to-date, report that and stop.
Scan
bash scripts/scan.sh # Push: local data only (default ~/code)
bash scripts/scan.sh --fetch # Pull: fetch remote first (10s timeout/repo)
bash scripts/scan.sh --base-dir /path/to/dir # Custom base directory
Output: JSON array with fields path, name, branch, remote, remote_url, dirty_count, has_upstream, ahead, behind, and fetch_error (only on --fetch failure).
Categorize
Push mode:
| Category |
Condition |
Action |
| up-to-date |
dirty_count == 0 && ahead == 0 |
Report |
| needs-push |
dirty_count == 0 && ahead > 0 |
Auto git push |
| dirty |
dirty_count > 0 |
Interactive |
| no-upstream |
has_upstream == false |
Ask user |
Pull mode:
| Category |
Condition |
Action |
| up-to-date |
dirty_count == 0 && behind == 0 |
Report |
| needs-pull |
dirty_count == 0 && behind > 0 |
Auto git pull --ff-only |
| dirty+behind |
dirty_count > 0 && behind > 0 |
Interactive |
| fetch-error |
fetch_error == true |
Report, skip |
Exception Handling
| Situation |
Steps |
| Dirty repo (push) |
git diff --stat + git status → describe to user → ask: commit, stash, or skip. If commit, MUST invoke git-workflow skill via Skill tool — never run git commit directly. |
| No upstream (push) |
Report → ask: set upstream and push (git push -u origin <branch>), or skip |
| ff-only fails (pull) |
git log --oneline HEAD..@{u} + @{u}..HEAD → explain divergence → suggest: rebase, merge, or skip |
| Dirty + behind (pull) |
Report both issues → ask: stash and pull (stash, pull --ff-only, pop), or skip |
Summary
Group repos by outcome after all operations complete:
## {Push|Pull} Summary
{Pushed|Updated} (N):
- repo-name (branch, N commits)
Already up-to-date (N):
- repo-a, repo-b, ...
Resolved (N):
- repo-c: action taken
Skipped (N):
- repo-d: reason
Common Issues
| Issue |
Fix |
scan.sh finds 0 repos |
Check ~/code/*/ has git repos |
fetch_error |
Check network, SSH keys |
| ff-only fails |
Rebase or merge manually |
| Push rejected |
Pull first, then push |
1---2name: code-sync-43description: Use this skill to batch-sync all git repos across machines — pushing uncommitted changes at end of day or pulling latest at start of day. Invoke when the user wants to sync all repos (not just one), mentions 「下班同步」「上班更新」 「code-sync」, or describes end-of-day push / morning pull across ~/code. Triggers on: "sync all my repos", "end of day sync", "morning update", "push all dirty repos", "pull all projects", 「同步代码」「下班同步」「上班更新」. Do NOT trigger for: single-repo git operations, committing specific files (use git-workflow), general git push/pull questions, or workspace template updates.4---56# Code Sync78Batch sync all git repos under a base directory — push (end-of-day) or pull (start-of-day).9Default base directory: `~/code`. Configurable via `~/.config/nini-skill/code-sync/config.md`.1011## Prerequisites1213| Tool | Type | Required | Install |14|------|------|----------|---------|15| git | cli | Yes | `brew install git` or [git-scm.com](https://git-scm.com/) |16| git-workflow | skill | Yes | Included in `npx skills add niracler/skill` — **must** be invoked via `Skill` tool for all commits |1718> Do NOT proactively verify these tools on skill load. If a command fails due to a missing tool, directly guide the user through installation and configuration step by step.1920## First-Time Setup2122On first use, check for config at `~/.config/nini-skill/code-sync/config.md`.23If not found, ask the user:24251. "Where do you keep your git repos?" (default: `~/code`)262. "What's the directory structure?" — explain the expected pattern:27 `<base-dir>/*/` for top-level repos and `<base-dir>/*/repos/*/` for monorepo sub-repos283. Save to `~/.config/nini-skill/code-sync/config.md`:2930```yaml31base_dir: ~/code32```3334## Mode Selection3536| User says | Mode |37|-----------|------|38| 「下班同步」or "push" | Push |39| 「上班更新」or "pull" | Pull |40| 「同步代码」「code-sync」 | Ask user |4142## Workflow (shared by both modes)43441. **Scan** → 2. **Categorize** → 3. **Batch action** (auto, no confirmation) → 4. **Handle exceptions** (interactive) → 5. **Summary**4546If all repos are up-to-date, report that and stop.4748### Scan4950```bash51bash scripts/scan.sh # Push: local data only (default ~/code)52bash scripts/scan.sh --fetch # Pull: fetch remote first (10s timeout/repo)53bash scripts/scan.sh --base-dir /path/to/dir # Custom base directory54```5556Output: JSON array with fields `path`, `name`, `branch`, `remote`, `remote_url`, `dirty_count`, `has_upstream`, `ahead`, `behind`, and `fetch_error` (only on `--fetch` failure).5758### Categorize5960**Push mode:**6162| Category | Condition | Action |63|----------|-----------|--------|64| up-to-date | `dirty_count == 0 && ahead == 0` | Report |65| needs-push | `dirty_count == 0 && ahead > 0` | Auto `git push` |66| dirty | `dirty_count > 0` | Interactive |67| no-upstream | `has_upstream == false` | Ask user |6869**Pull mode:**7071| Category | Condition | Action |72|----------|-----------|--------|73| up-to-date | `dirty_count == 0 && behind == 0` | Report |74| needs-pull | `dirty_count == 0 && behind > 0` | Auto `git pull --ff-only` |75| dirty+behind | `dirty_count > 0 && behind > 0` | Interactive |76| fetch-error | `fetch_error == true` | Report, skip |7778### Exception Handling7980| Situation | Steps |81|-----------|-------|82| **Dirty repo** (push) | `git diff --stat` + `git status` → describe to user → ask: **commit**, **stash**, or **skip**. If commit, **MUST invoke `git-workflow` skill via `Skill` tool** — never run `git commit` directly. |83| **No upstream** (push) | Report → ask: **set upstream and push** (`git push -u origin <branch>`), or **skip** |84| **ff-only fails** (pull) | `git log --oneline HEAD..@{u}` + `@{u}..HEAD` → explain divergence → suggest: **rebase**, **merge**, or **skip** |85| **Dirty + behind** (pull) | Report both issues → ask: **stash and pull** (stash, pull --ff-only, pop), or **skip** |8687### Summary8889Group repos by outcome after all operations complete:9091```text92## {Push|Pull} Summary9394{Pushed|Updated} (N):95 - repo-name (branch, N commits)96Already up-to-date (N):97 - repo-a, repo-b, ...98Resolved (N):99 - repo-c: action taken100Skipped (N):101 - repo-d: reason102```103104## Common Issues105106| Issue | Fix |107|-------|-----|108| `scan.sh` finds 0 repos | Check `~/code/*/` has git repos |109| `fetch_error` | Check network, SSH keys |110| ff-only fails | Rebase or merge manually |111| Push rejected | Pull first, then push |