Best for
- Code writing or review (use php-coder or code-review skill)
- CI/CD pipeline changes (use github-ci skill)
event4u-app/agent-config/src/skills/git-workflow/SKILL.md
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.
Decision brief
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.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/event4u-app/agent-config --skill "src/skills/git-workflow"Inspect the Agent Skill "git-workflow" from https://github.com/event4u-app/agent-config/blob/0adf49a8ae84b0ff6e2de8759eea43257e020eff/src/skills/git-workflow/SKILL.md at commit 0adf49a8ae84b0ff6e2de8759eea43257e020eff. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Quality pipeline + tests — only when quality.localautorun: 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…
When implementation is complete and all tests pass:
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.
Fires when git rev-list --left-right --count HEAD...@{u} shows both sides non-zero on the current branch.
If a PR is open on this branch: bash gh pr view --json reviews,comments
Permission review
The documentation includes network, browsing, or remote request actions.
ABOUT THEIR STATE — QUERY THE LIVE REMOTE. NEVER FROM MEMORY ORThe documentation asks the agent to run terminal commands or scripts.
git fetch origin --quietThe documentation asks the agent to run terminal commands or scripts.
git checkout mainEvidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 92/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 7 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Use when preparing PRs, finishing branches, or following the team's Git workflow.
Do NOT use when:
php-coder or code-review skill)github-ci skill)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
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.state + mergeStateStatus in the
same turn; never merge on a status seen earlier in the conversation.git rev-list --count HEAD..origin/main (after git fetch); non-zero ⇒ the
branch is behind and is not current — merge main in before opening a PR
(see /create-pr § 1b).→ 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.
→ Use conventional-commits-writing skill for generating/reviewing commit messages.
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.main.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
quality.local_auto_run: true; default false → skip, remote CI is the gate).git push -u origin <branch>.gh pr create using PR template.Report: "Branch <name> preserved locally." — do nothing.
Confirm first — list branch name and commit count. Wait for explicit confirmation. Then:
git checkout main
git branch -D <feature-branch>
The project uses .github/pull_request_template.md:
main is default/production branch.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.
BRANCH=$(git branch --show-current)
DATE=$(date +%F)
git fetch origin
git tag "safe-squash-pre/${BRANCH}/${DATE}" HEAD
git tag "safe-squash-origin/${BRANCH}/${DATE}" "@{u}"
Two tags = two recoveries (local tip + origin tip). Do not skip the
tags — git reflog is TTL-bounded and unreliable across sessions.
git rev-list --left-right --count HEAD...@{u}
0 0 → aligned, proceed.N 0 (local ahead) → unpushed work, proceed.0 N (origin ahead) → git pull --ff-only first, then re-check.M N (both non-zero) → divergent. Abandon the squash and run
§ Divergent-State Recovery below.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 (.condensation-hashes.json, router projections)
per commit and conflicts on every replay.
FETCHED_SHA=$(git rev-parse "@{u}")
git push --force-with-lease="${BRANCH}:${FETCHED_SHA}" origin "${BRANCH}"
git fetch origin
[ "$(git rev-parse HEAD)" = "$(git rev-parse @{u})" ] \
&& echo "OK: origin matches HEAD" \
|| echo "MISMATCH — do not end session"
If the push fails (pre-push hook, network, token budget):
HEAD == @{u}.Report exactly:
Fires when git rev-list --left-right --count HEAD...@{u} shows
both sides non-zero on the current branch.
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.
TS=$(date +%FT%H%M)
git tag "diverged-local/${TS}" HEAD
git tag "diverged-origin/${TS}" "@{u}"
git log --oneline @{u}..HEAD # local-only commits
git log --oneline HEAD..@{u} # origin-only commits
git diff @{u}..HEAD --stat # shape of local-ahead work
Decision matrix:
| Pattern | Future | Action |
|---|---|---|
| Local has the same logical work as origin, just reshaped (squash/rebase) | Local | After PR-review check (step 4), git push --force-with-lease=<branch>:<origin-sha> |
| Origin has commits local does not reflect (another contributor pushed) | Origin | Tag any local-ahead work for cherry-pick, then git reset --hard @{u} |
| Both sides have genuine independent work | ask user | Never decide silently — surface the two commit lists and let the user pick |
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.
Use the tags from step 2 to restore either side if step 4 surfaces a
problem. After resolution, verify HEAD == @{u} and report both
SHAs plus the tags created.
git pull --rebase after detecting divergent state.git push --force without --force-with-lease=<branch>:<sha>.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):
git rebase --onto, git reset --hard <other-base>)
in a way that drops commits already on the branch;push <local>:<remote>-replacing) a branch that carries
commits you did not author;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.
Pre-rewrite stop. Before any squash / amend / rebase on a branch that is on origin: git fetch && git rev-list --left-right --count HEAD...@{u}. If either side is non-zero — STOP and run § Divergent-State Recovery. A blind git pull --rebase in this state is the documented failure mode. (§ Safe squash-after-push steps 1–2 implement this stop.)
Post-rewrite stop. After the rewrite, push in the same turn with --force-with-lease=<branch>:<fetched-sha> and verify git rev-parse origin/<branch> equals git rev-parse HEAD. 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 → tag the state (git tag local-rewritten-tip-<ISO-date>) and hand control back to the user. Do not let a new session inherit a dirty divergence.
git rebase -i (interactive)git rebase --autosquashgit commit --fixup / --squash (helpers that feed autosquash)git commit --amend on already-pushed commitsgit push --force / --force-with-lease (unless paired with the protocol)git reset --hard past unpushed work the user might want--amend on the current local commit before the first push is the narrow exception (treated as continuing to compose the commit, not rewriting history).
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:
git add).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.)
Interactive rebase + fixup loops generate disproportionate token cost on every iteration: re-running CI per replayed commit, resolving the same content conflict in three derived files (.condensation-hashes.json, 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.
chore: regenerate commits, ugly." → don't. They are honest checkpoints.fix(scope): … on top.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.git stash can lose work — prefer WIP commits.main.Alternatives
affaan-m/ECC
Git workflow patterns including branching strategies, commit conventions, merge vs rebase, conflict resolution, and collaborative development best practices for teams of all sizes.
affaan-m/ECC
Use it for code review and testing tasks; the detail page covers purpose, installation, and practical steps.
affaan-m/ECC
Turn ambiguous or high-impact product and engineering changes into scoped, verifiable acceptance criteria before or alongside implementation. Use when a user asks to clarify a feature, define acceptance criteria, de-risk a security/data/migration/integration change, prepare implementation requirements for another agent, or make a complex request testable. Do not trigger for trivial edits, straightforward fixes, active debugging, code review, or implementation requests whose acceptance conditions
JasonColapietro/suede-creator-skills
Umbrella workflow for 67 public skills: Full Send, copy, design, code review, SEO, launch packaging, MCP QA, iOS and Android app shipping, and creator workflows. Loads the full public skill pack.