sk-git
Git workflow orchestrator: worktree setup, clean commits, finish/PR creation across git-worktrees, git-commit, git-finish.
12 stars
Best use case
sk-git is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Git workflow orchestrator: worktree setup, clean commits, finish/PR creation across git-worktrees, git-commit, git-finish.
Teams using sk-git should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
$curl -o ~/.claude/skills/sk-git/SKILL.md --create-dirs "https://raw.githubusercontent.com/MichelKerkmeester/opencode--spec-kit-skilled-agent-orchestration/main/.opencode/skills/sk-git/SKILL.md"
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/sk-git/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How sk-git Compares
| Feature / Agent | sk-git | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Git workflow orchestrator: worktree setup, clean commits, finish/PR creation across git-worktrees, git-commit, git-finish.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
<!-- Keywords: git-workflow, git-worktree, conventional-commits, pull-request, commit-hygiene, workspace-isolation, version-control, github, issues, pr-review -->
# Git Workflows - Git Development Orchestrator
Unified workflow guidance across workspace isolation, commit hygiene, and work completion.
## 1. WHEN TO USE
### When to Use This Orchestrator
Use this orchestrator when:
- Starting new git-based work
- Unsure which git skill to use
- Following complete git workflow (setup → work → complete)
- Looking for git best practices (branch naming, commit conventions)
### When NOT to Use
- Simple `git status` or `git log` queries (use Bash directly)
- Non-git version control systems
### Keyword Triggers
`worktree`, `branch`, `commit`, `merge`, `pr`, `pull request`, `git workflow`, `conventional commits`, `finish work`, `integrate changes`, `github`, `issue`, `review`
---
## 2. SMART ROUTING
### Resource Loading Levels
| Level | When to Load | Resources |
| ----------- | ------------------------ | -------------------------- |
| ALWAYS | Every skill invocation | Quick reference baseline |
| CONDITIONAL | If intent signals match | Setup/commit/finish docs |
| ON_DEMAND | Only on explicit request | Extended patterns/templates|
### Smart Router Pseudocode
The authoritative routing logic for scoped loading, weighted intent scoring, and ambiguity handling.
```python
from pathlib import Path
SKILL_ROOT = Path(__file__).resolve().parent
RESOURCE_BASES = (SKILL_ROOT / "references", SKILL_ROOT / "assets")
DEFAULT_RESOURCE = "references/quick_reference.md"
INTENT_SIGNALS = {
"WORKSPACE_SETUP": {"weight": 4, "keywords": ["worktree", "workspace", "parallel work"]},
"COMMIT": {"weight": 4, "keywords": ["commit", "staged", "message", "conventional commit"]},
"FINISH": {"weight": 4, "keywords": ["finish", "merge", "pr", "pull request", "integrate"]},
"SHARED_PATTERNS": {"weight": 3, "keywords": ["convention", "pattern", "reference", "branch naming"]},
}
NOISY_SYNONYMS = {
"WORKSPACE_SETUP": {"dirty workspace": 2.2, "unclean": 1.4, "mixed changes": 1.5},
"COMMIT": {"half-staged": 2.0, "boundary": 1.4, "split commit": 1.4},
"FINISH": {"ship": 1.5, "hotfix": 1.6, "trunk": 1.8, "minimal risk": 1.4},
}
UNKNOWN_FALLBACK_CHECKLIST = [
"Confirm base branch (main/master/trunk)",
"Confirm whether staged/unstaged changes should be split",
"Provide required PR policy (squash, template fields, checks)",
"Confirm hotfix urgency versus cleanup tolerance",
]
RESOURCE_MAP = {
"WORKSPACE_SETUP": ["references/worktree_workflows.md", "assets/worktree_checklist.md"],
"COMMIT": ["references/commit_workflows.md", "assets/commit_message_template.md"],
"FINISH": ["references/finish_workflows.md", "assets/pr_template.md", "references/github_mcp_integration.md"],
"SHARED_PATTERNS": ["references/shared_patterns.md"],
}
LOADING_LEVELS = {
"ALWAYS": [DEFAULT_RESOURCE],
"ON_DEMAND_KEYWORDS": ["full git flow", "all templates", "full reference", "git worktree", "experiment branch", "clean experiment branch", "routing-hardening", "routing-accuracy experiment"],
"ON_DEMAND": ["references/shared_patterns.md", "assets/commit_message_template.md"],
}
def _task_text(task) -> str:
return " ".join([
str(getattr(task, "text", "")),
str(getattr(task, "query", "")),
" ".join(getattr(task, "keywords", []) or []),
]).lower()
def _guard_in_skill(relative_path: str) -> str:
resolved = (SKILL_ROOT / relative_path).resolve()
resolved.relative_to(SKILL_ROOT)
if resolved.suffix.lower() != ".md":
raise ValueError(f"Only markdown resources are routable: {relative_path}")
return resolved.relative_to(SKILL_ROOT).as_posix()
def discover_markdown_resources() -> set[str]:
docs = []
for base in RESOURCE_BASES:
if base.exists():
docs.extend(p for p in base.rglob("*.md") if p.is_file())
return {doc.relative_to(SKILL_ROOT).as_posix() for doc in docs}
def score_intents(task) -> dict[str, float]:
"""Weighted intent scoring from request text and workflow flags."""
text = _task_text(task)
scores = {intent: 0.0 for intent in INTENT_SIGNALS}
for intent, cfg in INTENT_SIGNALS.items():
for keyword in cfg["keywords"]:
if keyword in text:
scores[intent] += cfg["weight"]
for intent, synonyms in NOISY_SYNONYMS.items():
for term, weight in synonyms.items():
if term in text:
scores[intent] += weight
if getattr(task, "needs_isolated_workspace", False):
scores["WORKSPACE_SETUP"] += 4
if getattr(task, "has_staged_changes", False):
scores["COMMIT"] += 4
if getattr(task, "ready_to_integrate", False):
scores["FINISH"] += 4
return scores
def select_intents(scores: dict[str, float], task_text: str, ambiguity_delta: float = 1.0, base_max_intents: int = 2, adaptive_max_intents: int = 3) -> list[str]:
ranked = sorted(scores.items(), key=lambda item: item[1], reverse=True)
if not ranked or ranked[0][1] <= 0:
return ["SHARED_PATTERNS"]
noisy_hits = sum(1 for term in ["dirty workspace", "half-staged", "hotfix", "minimal risk", "trunk"] if term in (task_text or ""))
max_intents = adaptive_max_intents if noisy_hits >= 2 else base_max_intents
selected = [ranked[0][0]]
for intent, score in ranked[1:]:
if score <= 0:
continue
if (ranked[0][1] - score) <= ambiguity_delta:
selected.append(intent)
if len(selected) >= max_intents:
break
return selected[:max_intents]
def route_git_resources(task):
inventory = discover_markdown_resources()
task_text = _task_text(task)
scores = score_intents(task)
intents = select_intents(scores, task_text, ambiguity_delta=1.0)
loaded = []
seen = set()
def load_if_available(relative_path: str) -> None:
guarded = _guard_in_skill(relative_path)
if guarded in inventory and guarded not in seen:
load(guarded)
loaded.append(guarded)
seen.add(guarded)
for relative_path in LOADING_LEVELS["ALWAYS"]:
load_if_available(relative_path)
if sum(scores.values()) < 0.5:
load_if_available("references/shared_patterns.md")
return {
"intents": ["SHARED_PATTERNS"],
"intent_scores": scores,
"load_level": "UNKNOWN_FALLBACK",
"needs_disambiguation": True,
"disambiguation_checklist": UNKNOWN_FALLBACK_CHECKLIST,
"resources": loaded,
}
for intent in intents:
for relative_path in RESOURCE_MAP.get(intent, []):
load_if_available(relative_path)
text = _task_text(task)
if any(keyword in text for keyword in LOADING_LEVELS["ON_DEMAND_KEYWORDS"]):
for relative_path in LOADING_LEVELS["ON_DEMAND"]:
load_if_available(relative_path)
if not loaded:
load_if_available(DEFAULT_RESOURCE)
return {"intents": intents, "intent_scores": scores, "resources": loaded}
```
---
## 3. HOW IT WORKS
### Workspace Choice Enforcement
**MANDATORY**: The AI must NEVER autonomously decide between creating a git worktree or using the current branch.
The AI must NEVER create a new branch directly with `git branch`, `git checkout` plus `-b`, or `git switch` plus `-c`.
When git workspace triggers are detected (new feature, worktree, isolated workspace, etc.), the AI MUST ask the user to explicitly choose:
| Option | Description | Best For |
| ----------------------------- | ---------------------------------------- | ------------------------------- |
| **A) Create a git worktree** | Isolated workspace in separate directory | Parallel work, complex features |
| **B) Work on current branch** | No new worktree created | Trivial changes, exploration |
**AI Behavior**: ASK before proceeding, WAIT for explicit selection (A/B), NEVER assume, RESPECT choice throughout. Once chosen, reuse preference for the session unless the user requests a change. If a new branch is needed, create it only through `git worktree add -b ...`.
### Launch-Wrapper Worktrees vs the In-Session Ask-First Rule
The ask-first rule above governs **in-session** decisions: once an AI is running, it must not autonomously create a worktree. That is distinct from `.opencode/bin/worktree-session.sh`, a **launch wrapper** the operator opts into at the shell (e.g. `alias claude='bash /abs/.opencode/bin/worktree-session.sh claude'`). The wrapper runs *before* the AI starts and places each top-level session in its own worktree + branch + isolated MCP databases automatically; orchestrated children (`AI_SESSION_CHILD=1`, or already inside a linked worktree) exec in place. Because the wrapper acts pre-session at operator opt-in, it does not violate the in-session ask-first rule — the operator made the choice by aliasing the launch.
**Deliberate per-session deps override.** The wrapper **symlinks** the shared `node_modules`/`dist` from the main checkout into each worktree and gives each worktree its own MCP DBs (via `SPEC_KIT_DB_DIR` / `SPECKIT_CODE_GRAPH_DB_DIR` / `SPECKIT_IPC_SOCKET_DIR`). This is an intentional exception to the §4 "bare worktree lacks gitignored deps / DBs are a single global instance" guidance: that guidance is about *ad-hoc* worktrees for large reorgs, whereas the wrapper purpose-builds an isolated-but-runnable worktree. Strict-validate and memory reindex still run on `main`, never inside a wrapper worktree.
### Git Development Lifecycle Map
Git development flows through 3 phases:
**Phase 1: Workspace Setup** (Isolate your work)
- **git-worktrees** - Create isolated workspace with short-lived temp branches
- Prevents: Branch juggling, stash chaos, context switching
- Output: Clean workspace ready for focused development
- **See**: [worktree_workflows.md](./references/worktree_workflows.md)
**Phase 2: Work & Commit** (Make clean commits)
- **git-commit** - Analyze changes, filter artifacts, write Conventional Commits
- Prevents: Accidental artifact commits, unclear commit history
- Output: Professional commit history following conventions
- **See**: [commit_workflows.md](./references/commit_workflows.md)
**Phase 3: Complete & Integrate** (Finish the work)
- **git-finish** - Merge, create PR, or discard work (with tests gate)
- Prevents: Incomplete work merged, untested code integrated
- Output: Work successfully integrated or cleanly discarded
- **See**: [finish_workflows.md](./references/finish_workflows.md)
### Phase Transitions
- Setup → Work: Worktree created, ready to code
- Work → Complete: Changes committed, tests passing
- Complete → Setup: Work integrated, start next task
### Skill Selection Decision Tree
**Workspace Setup (Phase 1)**:
- Starting new feature/fix? → **git-worktrees** (isolated workspace)
- Quick fix on current branch? → Skip to Phase 2
**Work & Commit (Phase 2)**:
- Ready to commit? → **git-commit** (analyze, filter, write Conventional Commits)
- No changes yet? → Continue coding
**Complete & Integrate (Phase 3)**:
- Tests pass? → **git-finish** (merge, PR, keep, or discard)
- Tests failing? → Return to Phase 2
### Common Workflow Patterns
**Full Workflow** (new feature):
```
git-worktrees (create workspace) → Code → git-commit (commit changes) → git-finish (integrate)
```
**Quick Fix** (current branch):
```
Code → git-commit (commit fix) → git-finish (integrate)
```
**Parallel Work** (multiple features):
```
git-worktrees (feature A) → Code → git-commit
git-worktrees (feature B) → Code → git-commit
git-finish (feature A) → git-finish (feature B)
```
---
## 4. RULES
### ✅ ALWAYS
1. **Use deterministic conventional commit format** - All commits must follow `type(scope): description` using the commit-message logic defined below
2. **Create worktree for parallel work** - Never work on multiple features in the same worktree
3. **Verify branch is up-to-date** - Pull latest changes before creating PR
4. **Use descriptive worktree-created branch names** - Format: `type/short-description` (e.g., `feat/add-auth`, `fix/login-bug`)
5. **Reference spec folder in commits** - Include spec folder path in commit body when applicable
6. **Clean up after merge** - Delete local and remote feature branches after successful merge
7. **Squash commits for clean history** - Use squash merge for feature branches with many WIP commits
8. **Defer toolchain + DB work to main on large reorgs** - For large rename/reorg, do file/`git mv` ops in the worktree but run the spec-kit toolchain (strict validate, generators, metadata regen) and ALL memory reindex/re-embed on `main` AFTER merge. A bare worktree lacks gitignored deps (`node_modules`/`dist`) and the memory/vector DBs are a single global instance — never per-worktree. See [large_reorg_playbook.md](references/large_reorg_playbook.md).
9. **Scan for gitignored leftovers after a rename wave** - After `git mv` + merge, detect dirs with disk files but 0 tracked files (`git ls-files <dir>` empty and `git status --porcelain --untracked-files=all` clean) and `rm -rf` them — they are stale ignored cruft (`.DS_Store`, `*.log`, `*.pyc`) left behind by `git mv`.
10. **Verify rename history is preserved** - After a rename wave confirm `R`-status (not delete+add) before commit, and after merge confirm the tree has no old+new duplicate folders.
11. **Honor an authorized operator's explicit direct-push directive on a protected branch** - Protected-branch rules (PR-required, verified signatures, code scanning) primarily gate EXTERNAL contributors. When the operator holds bypass rights and explicitly asks to commit/push directly to a protected branch, do a direct `git push` — do NOT default to a PR detour, re-ask whether to use a PR, or frame the bypass / resulting unsigned commit as a problem. Still apply full commit hygiene: scope the commit to the intended files only (a shared or dirty tree may hold concurrent work — never blind `git add -A`), use Conventional Commits, and report plainly that the push bypassed protection. Whether a given operator/repo grants that bypass authority is recorded in operator memory, not in this codebase-agnostic skill.
### Commit Message Logic (AI-Scannable)
Use this logic whenever the AI writes or rewrites commit messages.
1. **Subject format (required)**: `type(scope): summary`
2. **Type selection order (first match wins)**:
- `merge`: merge commits (`Merge ...`)
- `release`: version or release subjects (`vX.Y.Z`, `release`)
- `docs`: docs-only changes or README/CHANGELOG-focused updates
- `fix`: bug/security/hotfix/error correction
- `feat`: new behavior, support, or capability
- `refactor`: internal restructuring without behavior change
- `test`: test-only updates
- `chore`: fallback for operational or mixed maintenance work
3. **Scope selection order (first match wins)**:
- `.opencode/skills/<name>/...` -> `<name>`
- `AGENTS.md` changes -> `agents`
- `README.md`-only changes -> `readme`
- `opencode.json` or `.utcp_config.json` -> `config`
- `.opencode/agents/...` -> `agents`
- `.opencode/commands/...` -> `commands`
- docs-only set -> `docs`
- fallback -> dominant top-level path or `repo`
4. **Summary normalization**:
- Keep concise and specific
- Remove duplicate prefixes like `feat(scope):` from legacy subjects
- Avoid trailing period
- Preserve key context tokens (version, skill name, issue id) when relevant
5. **Body format (optional)**:
- Add only when context is non-obvious
- Prefer:
- `Context: <why>`
- `Changes:` with 1-3 bullets
- `Refs: <spec-folder|issue|PR>` when available
6. **Determinism rule**:
- The same diff + metadata should produce the same commit subject every time.
### ❌ NEVER
1. **Force push to main/master** - Protected branches must never receive force pushes
2. **Never create branches directly** - Use `git worktree add -b ...`; never use `git branch`, `git checkout` plus `-b`, or `git switch` plus `-c`
3. **Commit directly to protected branches WITHOUT operator authorization** - Default to feature branches + PRs. EXCEPTION: when the operator has bypass authority on that branch and explicitly directs a direct commit/push, honor it (see ALWAYS #11) — do not force a PR detour.
4. **Leave worktrees uncleaned** - Remove worktree directories after merge
5. **Commit secrets or credentials** - Use environment variables or secret management
6. **Create PRs without description** - Always include context, changes, and testing notes
7. **Merge without CI passing** - Wait for all checks to complete
8. **Rebase public/shared branches** - Only rebase local, unpushed commits
### ⚠️ ESCALATE IF
1. **Merge conflicts cannot be auto-resolved** - Complex conflicts require human decision on which changes to keep
2. **GitHub MCP returns authentication errors** - Token may be expired or permissions insufficient
3. **Worktree directory is locked or corrupted** - May require manual cleanup with `git worktree prune`
4. **Force push to protected branch is requested** - This requires explicit approval and understanding of consequences
5. **CI/CD pipeline fails repeatedly** - May indicate infrastructure issues beyond code problems
6. **Branch divergence exceeds 50 commits** - Large divergence suggests need for incremental merging strategy
7. **Submodule conflicts detected** - Submodule updates require careful coordination
8. **Strict-validate run inside a bare worktree** - Its exit code is meaningless (missing gitignored deps may make it silently no-op on zero files). Re-run on `main` post-merge before trusting any result. See [large_reorg_playbook.md](references/large_reorg_playbook.md).
---
## 5. REFERENCES
### Core Workflows
| Document | Purpose | Key Insight |
|----------|---------|-------------|
| [worktree_workflows.md](references/worktree_workflows.md) | 7-step workspace creation | Directory selection, branch strategies, large-reorg caveats (§8b) |
| [large_reorg_playbook.md](references/large_reorg_playbook.md) | Step-ordered large rename/reorg runbook | Worktree-only renames; toolchain + DB run on main post-merge |
| [commit_workflows.md](references/commit_workflows.md) | 6-step commit workflow | Artifact filtering, Conventional Commits, scoped-staging discipline for a dirty tree / unrelated WIP (§3 Step 7) |
| [finish_workflows.md](references/finish_workflows.md) | 5-step completion flow | PR creation, cleanup, merge |
| [shared_patterns.md](references/shared_patterns.md) | Reusable git patterns | Error recovery, conflict resolution, rename-heavy / large-reorg merge verification (§10) |
| [quick_reference.md](references/quick_reference.md) | Command cheat sheet | Common operations |
| [github_mcp_integration.md](references/github_mcp_integration.md) | GitHub MCP remote ops | PRs, issues, CI/CD via Code Mode |
### Assets
| Asset | Purpose | Usage |
|-------|---------|-------|
| [worktree_checklist.md](assets/worktree_checklist.md) | Worktree creation checklist | Pre-flight verification |
| [commit_message_template.md](assets/commit_message_template.md) | Commit format guide | Conventional Commits |
| [pr_template.md](assets/pr_template.md) | PR description template | Consistent PR format |
---
## 6. SUCCESS CRITERIA
### Workspace Setup Complete
- Workspace prepared in the selected mode (`git worktree` or current branch)
- If a worktree was selected, it was created in the correct directory (`.worktrees/` or user-specified)
- Any worktree-created branch naming follows convention (`type/short-description`)
- User confirmed workspace choice (worktree/current branch)
### Commit Complete
- All changes reviewed and categorized
- Artifacts filtered out (build files, coverage, etc.)
- Commit message follows Conventional Commits format
- Only public-value files staged
### Integration Complete
- Tests pass before merge/PR
- PR description includes context, changes, and testing notes
- Branch up-to-date with base branch
- Worktree cleaned up after merge (if used)
- Local and remote feature branches deleted
### Quality Gates
| Gate | Criteria | Blocking |
|------|----------|----------|
| **Pre-commit** | Artifacts excluded, message formatted | Yes |
| **Pre-merge** | Tests pass, branch up-to-date | Yes |
| **Pre-PR** | Description complete, CI passing | Yes |
| **Post-merge** | Worktree removed, branches cleaned | No |
---
## 7. INTEGRATION POINTS
### Framework Integration
This skill operates within the behavioral framework defined in [AGENTS.md](../../../AGENTS.md).
Key integrations:
- **Gate 2**: Skill routing via `skill_advisor.py`
- **Gate 3**: File modifications require spec folder question per AGENTS.md Gate 3 (HARD BLOCK)
- **Tool Routing**: Per AGENTS.md Section 6 decision tree
- **Continuity**: `/speckit:resume` is the recovery surface; canonical packet context is read from `handover.md -> _memory.continuity -> spec docs`
### Continuity Integration
Use canonical packet continuity for context recovery first, then use Spec Kit Memory MCP only when packet-native sources are exhausted:
```text
// Recover the active packet before planning git work
/speckit:resume
// Recovery order: handover.md -> _memory.continuity -> spec docs
// If packet-native sources are exhausted, use Spec Kit Memory MCP for wider lookups
memory_search({ query: "branch strategy decisions", includeContent: true })
// After major commits or workflow completion
// Save context with: /memory:save or "save context to [spec-folder]"
```
**Best Practices**:
- Use `/speckit:resume` at session start to recover active packet context
- Prefer `handover.md`, `_memory.continuity`, and canonical spec docs before broader memory queries
- Save context after significant commits or before ending a session
- Reference spec folder in commit messages for traceability
---
## 8. REFERENCES AND RELATED RESOURCES
The router discovers reference, asset, and script docs dynamically. Start with `references/quick_reference.md`, `references/worktree_workflows.md`, `references/commit_workflows.md`, `references/finish_workflows.md`, `references/github_mcp_integration.md`, `references/shared_patterns.md`, `assets/commit_message_template.md`, then load task-specific resources from `references/`, templates from `assets/`, and automation from `scripts/` when present.
### Manual Testing Playbook
Manual testing scenarios for this skill live in `manual_testing_playbook/manual_testing_playbook.md` (root index) plus 22 per-feature sub-files under `manual_testing_playbook/<NN>--<topic>/<NNN>-<scenario>.md`. Run scenarios via `bash .opencode/skills/sk-doc/scripts/validate_document.py manual_testing_playbook/manual_testing_playbook.md` for structural validation; execute scenarios in opencode/Claude/Codex sessions for behavioral verification.
Related skills: `system-spec-kit` for packet recovery and continuity, and `sk-doc` for PR, release, and documentation quality.Related Skills
We are still matching the closest adjacent skills for this page. In the meantime, continue through the full directory.