本文へ移動
cccskills
無料GitHub で公開

git-workflow

Use when working with Git — branch naming, commit messages, PR creation, rebasing, or the code review process — even when the user says 'push this' or 'merge the branch' without naming Git.

インストール方法を見る

含まれるファイル(5)

  • SKILL.md20.2 KB
  • evals/triggers.json1.7 KB
  • references/branch-update.md20.9 KB
  • references/commit-subject.md12.8 KB
  • references/push-closes-its-loop.md10.4 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

git-workflow

When to use

Use when preparing PRs, finishing branches, or following the team's Git workflow.

Do NOT use when:

  • Code writing or review (use php-coder or code-review skill)
  • CI/CD pipeline changes (use github-ci skill)

Live remote state first — never from memory

BEFORE ANY MERGE / PUSH / PR / BRANCH ACTION — OR ANY CLAIM OR QUESTION
ABOUT THEIR STATE — QUERY THE LIVE REMOTE. NEVER FROM MEMORY OR
CONVERSATION HISTORY. A PR MAY ALREADY BE MERGED OR CLOSED REMOTELY.
ASKING WHAT `gh pr view` ANSWERS IS A CHEAP QUESTION — CHECK, DON'T ASK.

The local branch view and the conversation's memory both go stale the moment anyone else — a maintainer, a parallel agent, an auto-merge rule — acts on the remote. Acting or asking on stale state is the recurring failure this section kills (canonical: asking "shall I merge these 4 PRs?" when all four were already merged remotely). Run first, every time:

git fetch origin --quiet
gh pr view <number> --json number,state,mergeStateStatus,mergedAt,baseRefName
# state: OPEN | MERGED | CLOSED — act only on the live value
  • A state question is self-answering — never ask the user "is it merged?", "is it mergeable?", "did it get pushed?", "is it still open?". gh pr view / git fetch answers it. Asking is a cheap question (per no-cheap-questions).
  • MERGED / CLOSED → there is nothing to merge or push; report the live state and stop — do not attempt the action.
  • Before merging → re-fetch and re-read state + mergeStateStatus in the same turn; never merge on a status seen earlier in the conversation.
  • "Based on main" / "current" → prove it with npx tsx node_modules/@event4u/agent-config/src/scripts/check_branch_freshness.ts; exit 1 ⇒ the branch is behind and is not current (or the named base does not exist on the remote; the message says which) — update it from the base per git.update_strategy (references/branch-update.md), regenerate the derived files, then open the PR (see /create-pr § 1b). Exit 0 means only that the gate did not refuse: read the line. branch is current is the pass; NOT VERIFIED means the base could not be reached and freshness is unknown — the gate exits 0 there on purpose so an offline push is not blocked, which makes reporting it as "current" the one misread it cannot catch. Exit 0 also covers the paths with nothing to check — a no-op in CI, a detached HEAD, standing on the base itself — and under --quiet a genuine pass prints nothing, so run it without the flag when you need a verdict to read. Prefer it over git rev-list --count HEAD..origin/main, which is wrong twice over: it pins main as the base for a branch whose PR may target something else, and it reads the local tracking ref — a fetch from earlier in the session, which is memory rather than a check. The gate asks the remote and resolves the base from the open PR.

Conventions

→ See guideline docs/guidelines/php/git.md for branch naming, commit messages, PR conventions. → See commit-conventions rule for commit format, types, and scope rules; a team convention is declared in the git: settings (commit_format, branch_pattern, update_strategy). → Use conventional-commits-writing skill for generating/reviewing commit messages.

Procedure: Before opening a PR

  1. Quality pipeline + tests — only when quality.local_auto_run: true (see quality-tools § Execution policy): type-checker → auto-fixer → linter → type-checker, then the project's test command (detect from manifest: php artisan test / vendor/bin/phpunit (PHP), npm test / pnpm test / vitest / jest (JS-TS), pytest (Python), cargo test (Rust), go test ./... (Go)). Under the default (false / missing) skip both — remote CI on the PR is the gate; say so instead of claiming they passed.
  2. Update the branch from its base — references/branch-update.md.
  3. Fill in PR template completely.

Procedure: Finish a branch

When implementation is complete and all tests pass:

Work complete. What would you like to do?

1. Push and create a Pull Request
2. Keep the branch as-is (I'll handle it later)
3. Discard this work

Option 1: Push and create PR

  1. Run quality pipeline + tests (only when quality.local_auto_run: true; default false → skip, remote CI is the gate).
  2. The push-ready sequence — fetch → integrate the base SET (per git.update_strategy, references/branch-update.md) → regenerate → verify → re-check freshness (this repo wires it as a push-ready task target; a consumer wires its own). Not optional housekeeping: see § A push closes its own loop. A stale push is refused, so skipping this buys the refusal.
  3. git push -u origin "<branch>" (a rendered name is always quoted) — after a rebase of a pushed branch, --force-with-lease per references/branch-update.md.
  4. gh pr create using PR template.
  5. Settle it — the turn is not over at step 4: npx tsx node_modules/@event4u/agent-config/src/scripts/ci_settle.ts <pr>

A push closes its own loop

A PUSH IS NOT A DELIVERY. THE EVIDENCE FOR A PUSH IS THE CI VERDICT,
NEVER THE PUSH'S OWN EXIT CODE.
BEHIND THE BASE → INTEGRATE BEFORE PUSHING, NEVER AFTER THE PR IS RED.
RED AFTER PUSHING → FIX IT IN THE SAME TURN, OR SAY PLAINLY THAT YOU DID NOT.
NEVER HAND THE USER A RED PR WITH ITS CAUSE NAMED AND UNFIXED.

Two halves, failing differently, over the 30 sessions and 50 PRs before 2026-09-04. Stale base: 25 of 50 PRs carried a Merge branch 'main' into … commit (52 in total), and the three most-failing workflows are the base-relative ones — a branch pushed behind its base was verified against a base it no longer merges into. Unsettled push: 22 of 30 sessions ran gh run view --log-failed, and 20 of 50 PRs carried a follow-up fix(ci|gates|budget) commit. Only 19 of 50 landed with neither. Each half now has a deterministic carrier — the pre-push hook refuses a verified-behind branch and points at the push-ready sequence; the push-settle PostToolUse concern fires the moment git reports a ref advanced. Neither replaces the discipline: the hook is skippable with AGENT_CONFIG_SKIP_PREPUSH_FRESHNESS=1 for a genuine WIP push, and the settle reminder is advisory, because leaving a push deliberately unsettled is legitimate — ending the turn silently on one is not.

ci_settle non-zero → read only the failing part (gh run view --job <id> --log-failed | grep -E '×|FAIL|Error'), fix, push again; the author of the red is irrelevant (fix-what-you-see). Three failed attempts on one target trigger autonomous-execution's mandatory strategy shift. Exit 2 is not a verdict — the wait timed out or the API could not be read. Counts, carrier limits and the honest cost: references/push-closes-its-loop.md.

PR template

The project uses .github/pull_request_template.md:

  1. Jira ticket link (badge)
  2. Description — what and why
  3. Type of change
  4. Checklist (docs, rebase, quality, review, tests, QA)
  5. Links + screenshots

Default branch

  • main is default/production branch.
  • Merge method: read from the forge (/pr:merge § 9), never assumed; rebase-and-merge keeps every commit, so each subject must follow the convention.

Procedure: Safe squash-after-push

Use ONLY when the user explicitly authorized a squash on a branch that is already on origin. The whole sequence runs in one turn — never end the session between rewrite and push.

Trigger context: git-history-discipline rule routed here.

1. Snapshot before touching anything

REMOTE/RB: the published ref, from the resolve block of references/branch-update.md § The rebase sequence — never @{u}; unresolved → no squash.

DATE=$(date +%F)
PUBLISHED=$(git ls-remote "$REMOTE" "refs/heads/$RB") || { echo "STOP: could not read $REMOTE/$RB — nothing was rewritten" >&2; exit 1; }; EXPECTED=$(cut -f1 <<<"$PUBLISHED")
git fetch -q "$REMOTE" "refs/heads/$RB"
SNAP="refs/agent-config/rewrites/squash-${DATE}-$$"
git update-ref "$SNAP/before" HEAD
git update-ref "$SNAP/published" "$EXPECTED"

Two refs = two recoveries (local tip + published tip), private — git push --tags cannot publish them; git reflog is TTL-bounded and unreliable across sessions.

2. Verify aligned starting state

git rev-list --left-right --count "HEAD...$EXPECTED"
  • 0 0 → aligned, proceed.
  • N 0 (local ahead) → unpushed work, proceed.
  • 0 N (published ref ahead) → git merge --ff-only "$EXPECTED" first, then re-check.
  • M N (both non-zero) → divergent. Abandon the squash and run § Divergent-State Recovery below.

3. Perform the squash

Default — soft-reset path (single token-cheap rewrite):

git reset --soft "$(git merge-base HEAD <base>)"
git commit -m "<conventional commit message>"

Interactive rebase only when the user wants per-commit control — it replays derived files (dist/agent-src/, router projections) and conflicts on every replay.

4. Re-push in the SAME turn

# $EXPECTED is the SHA pinned in step 1 — re-reading it would lease a collaborator's push
git push --force-with-lease="refs/heads/$RB:$EXPECTED" "$REMOTE" "HEAD:refs/heads/$RB"
[ "$(git ls-remote "$REMOTE" "refs/heads/$RB" | cut -f1)" = "$(git rev-parse HEAD)" ] \
  && echo "OK: the published ref matches HEAD" \
  || echo "MISMATCH — do not end session"

If the push fails (pre-push hook, network, token budget):

  • Fix the underlying cause now.
  • Re-push immediately.
  • Do not commit new work on top of the squashed-but-unpushed tip.
  • Do not end the session until the published ref equals HEAD.

5. Hand off only with verified parity

Report exactly:

  • pre-squash tip SHA (from step 1)
  • the recovery refs under $SNAP — removed with git update-ref -d once step 4 verified parity; kept, with git reset --keep "$SNAP/before" printed, if anything failed
  • post-squash tip SHA == origin SHA (verified in step 4)
  • PR number, if any, and confirm it picked up the new tip

Procedure: Divergent-State Recovery

Fires when git rev-list --left-right --count "HEAD...$EXPECTED" (the published ref's SHA, pinned as in § Safe squash-after-push step 1) shows both sides non-zero.

1. Stop. Do not pull.

A blind git pull --rebase here replays remote commits on top of a local history that may already represent the same work in a different shape — guaranteed conflict storm in derived files, possible double-application of the same change. This is the documented failure mode behind git-history-discipline.

2. Record both sides immediately

SNAP="refs/agent-config/rewrites/diverged-$(date +%Y%m%dT%H%M)"
git update-ref "$SNAP/before" HEAD
git update-ref "$SNAP/published" "$EXPECTED"

3. Diagnose: which side is the correct future?

git log --oneline "$EXPECTED..HEAD"   # local-only commits
git log --oneline "HEAD..$EXPECTED"   # published-only commits
git diff "$EXPECTED..HEAD" --stat     # shape of local-ahead work

Decision matrix:

PatternFutureAction
Local has the same logical work as origin, just reshaped (squash/rebase)LocalAfter PR-review check (step 4), git push --force-with-lease=refs/heads/<b>:<sha> <remote> HEAD:refs/heads/<b>
Origin has commits local does not reflect (another contributor pushed)OriginKeep any local-ahead work at the step-2 refs for cherry-pick, then git reset --hard "$EXPECTED"
Both sides have genuine independent workask userNever decide silently — surface the two commit lists and let the user pick

4. PR review-comment check (mandatory before any force-push)

If a PR is open on this branch:

gh pr view --json reviews,comments
# or via GitHub API: /repos/<owner>/<repo>/pulls/<num>/{reviews,comments}

If review comments are anchored to commits that the force-push will erase → STOP, ask the user how to preserve them. A force-push that destroys live review feedback is unrecoverable from the agent side.

5. Recover or proceed

Use the refs from step 2 to restore either side if step 4 surfaces a problem. After resolution, verify the published ref equals HEAD and report both SHAs plus the refs recorded.

Hard prohibitions on a pushed branch

  • No git pull --rebase after detecting divergent state.
  • No git push --force, and no --force-with-lease without its fully qualified refs/heads/<b>:<sha>.
  • No squash-then-end-session — the push must complete in the same turn.
  • No reflog-only recovery — always record the state under refs/agent-config/rewrites/ first.

Shared-branch & inherited commits — ask-before-drop protocol

Depth for the git-history-discipline Iron Law on inherited & shared-branch commits (migrated here per P4 of road-to-kernel-and-router.md).

The user often works in parallel with the agent, and multiple agents may share one PR branch. A commit that looks "unrelated" or "stray" may be deliberate in-flight work the user expects to keep. Reseating a branch onto a different base, git reset --hard-ing away inherited commits, force-pushing over a branch you did not create, or branching from a base with unexpected commits and then "cleaning" them out all silently discard work — the exact failure that law prevents.

Before ANY of these, STOP and ask (one numbered-options prompt per user-interaction):

  • reseating a branch's base (git rebase --onto, git reset --hard <other-base>) in a way that drops commits already on the branch;
  • excluding / not-carrying-forward commits that were on the branch when you started this session;
  • force-pushing (or push <local>:<remote>-replacing) a branch that carries commits you did not author;
  • branching from a base with unexpected commits, then resetting them away.

Preserve-first is necessary but not sufficient. Even when you keep the commits reachable (a save-branch / tag), you still ask before the branch the user sees loses them — "I preserved them locally" is not a substitute for the question, because the user may be mid-edit on the shared branch and a force-push would clobber their in-flight work regardless of your local backup.

Two protective stops (for the protocol phase)

  1. Pre-rewrite stop. Before any squash / amend / rebase of a pushed branch: resolve the ref it publishes (@{push}, or the pull request's head repository — references/branch-update.md § The rebase sequence; never @{u}, which is the base for a branch pushed without -u), pin its SHA once, then git rev-list --left-right --count "HEAD...$EXPECTED". An unresolved target is no rewrite. Squash / amend: if either side is non-zero — STOP and run § Divergent-State Recovery. Rebase: the pinned SHA must already be in HEAD — your own unpushed commits travel with the rebase. A blind git pull --rebase in this state is the documented failure mode. (§ Safe squash-after-push steps 1–2 implement this stop.)

  2. Post-rewrite stop. After the rewrite, push in the same turn with git push --force-with-lease=refs/heads/<b>:<pinned-sha> <remote> HEAD:refs/heads/<b> and verify git ls-remote <remote> refs/heads/<b> equals git rev-parse HEAD. A rejected lease is a stop — refetch and report, never a bare --force-with-lease, never --force. If the push fails (hook, network, token budget) — fix the cause and re-push before ending the session, committing new work, or handing off. (§ Safe squash-after-push step 4 implements this stop.)

If either stop fires and resolution is not immediate → record the state (git update-ref refs/agent-config/rewrites/<tx>/before HEAD) and hand control back to the user. Do not let a new session inherit a dirty divergence.

Equivalents that are also forbidden by default

  • git rebase -i (interactive)
  • git rebase --autosquash
  • git commit --fixup / --squash (helpers that feed autosquash)
  • git commit --amend on already-pushed commits
  • git push --force / --force-with-lease (unless paired with the protocol)
  • git reset --hard past unpushed work the user might want
  • Squash-merge of a PR via API or CLI when the user has not picked the merge strategy
  • Cherry-pick rewriting that drops or reorders commits

--amend on the current local commit before the first push is the narrow exception (treated as continuing to compose the commit, not rewriting history).

Amend-after-hook-failure trap (data-loss)

When a pre-commit hook fails, the commit did NOT happen — no new commit object was created. A reflexive git commit --amend at that point does not "retry the commit"; it rewrites the previous, already-good commit, destroying that work. This is the one place the narrow --amend exception above turns into data loss.

Recovery — never amend after a hook failure:

  1. Read the hook output and fix the cause (the lint/test/format failure).
  2. Re-stage the fix (git add).
  3. Create a NEW commit (git commit, not --amend) — the prior commit was never overwritten and must stay intact.

(Migrated here from git-history-discipline — recovery now lives next to the mechanism it protects.)

Why history discipline exists

Interactive rebase + fixup loops generate disproportionate token cost on every iteration: re-running CI per replayed commit, resolving the same content conflict in two derived files (dist/router.json, .windsurfrules), losing the working tree to a stash that silently re-introduces older state. A single conflict can burn the budget of an entire feature.

A previous session squashed a pushed branch, the push hook failed at the token boundary, the session ended — and the next session saw local and origin pointing at different SHAs for the same logical work. A blind git pull --rebase cascaded into conflicts across every derived file. Recovery required forensic SHA-archaeology. The pre/post-rewrite stops make that sequence structurally impossible.

When you'd be tempted

  • "I want commit 3 to come before commit 2 because the topic flows better." → don't. Reviewers read the PR diff.
  • "There are two chore: regenerate commits, ugly." → don't. They are honest checkpoints.
  • "A linter caught an issue in commit 2 — let me fold the fix in." → don't. Add fix(scope): … on top.
  • "I want to drop the WIP commit before pushing." → ask the user first.
  • "Squash-merge when I open the PR will clean it anyway." → also true, also irrelevant — let the merge strategy do that work, not you.
  • "My branch inherited some unrelated commits — I'll reseat it on origin/main so my PR is clean." → don't, ask first. They may be the user's parallel work or another agent's. Preserve them and ask which base the user wants.
  • "The remote branch has commits I didn't author and no PR — I'll just force-push over it." → don't. No-PR is not no-owner; ask before replacing a branch you did not create.

Output format

  1. Commits following conventional commit format
  2. PR description with structured sections (if creating PR)

Gotcha

  • Never commit/push/merge without explicit user permission.
  • Keep subject line under 72 chars.
  • Don't rebase shared branches.
  • git stash can lose work — prefer WIP commits.

Do NOT

  • Do NOT commit directly to main.
  • Do NOT push without running quality tools first.
  • Do NOT force-push to shared branches.

Auto-trigger keywords

  • Git workflow
  • branch naming
  • commit message
  • PR convention

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when reviewing UI for accessibility — WCAG 2.2 AA, keyboard nav, focus, ARIA, contrast, screen-reader semantics — even on 'is this a11y-OK?' or 'mach das barrierefrei'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

Use when defining or auditing the activation event — aha-moment selection, retention correlation, falsifiable definition. Triggers on 'what is our aha moment', 'redefine activation'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

Use when capturing an architectural decision — file naming, next ADR number, Status / Context / Decision / Consequences, index regen; fires even without saying 'ADR'.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

Adversarial critique — devil's advocate, stress-test, honest teardown ('poke holes', 'be brutal', 'was hältst du davon'); explicit request only. Routine code or design review → code-review.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

Use when reading, creating, or updating agent documentation, module docs, roadmaps, or AGENTS.md. Understands the full .augment/, agents/, and copilot-instructions structure.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

Use for an adversarial red-team / blue-team / auditor review of an AI agent's CONFIG + behaviour (rules, skills, MCP, hooks, permissions) — attack-chain → defensive-gap list, not a code audit.

日本語の概要は準備中です。原文の説明を表示しています。

event4u-app/agent-config112026年10月11日 更新

event4u-app のスキルをすべて見る

このスキルの問題を報告する