Git Commit
Create commits through the dot git-commit gateway, never raw git commit. The
gateway enforces the maintainer's style guards; this skill covers scope,
staging, and message authoring around it.
1. Authorisation and posture
- Only commit when the user asked to commit the current reviewed changeset (a
/commitor/commit-pushinvocation, or an explicit "commit this" instruction). Drafting a message is not permission. - One request authorises the coherent commit series needed for that changeset. It does not authorise a later change, a second changeset, or another push. Ask or stop unless the user explicitly requests that follow-up work.
- Run in a build agent. Raw
git commitis denied in the OpenCode permission config;dot git-commitis the allowed path. Ifdot git-commitis denied, stop and report that this needs a build agent, do not fall back togit commit. - Amend only when the user explicitly requests it and follow the guarded amend flow below. Never rebase or otherwise rewrite existing commits here. Never disturb a set the user staged without asking.
2. Read the working tree
- For
/commitand/commit-push, use the injected<commit-context>first. It combines branch metadata, candidate and excluded paths, a compact diff stat, and recent subject evidence with paths touched by the session tree. - Candidate paths are attribution evidence, not authorisation. The active user request and conversation determine which candidates belong to the changeset. A complete block means only that attribution collection succeeded.
- When the block contains several
<repository-scope>sections, treat each as an independent changeset. Run itsdot git-commitcommands from the listed repository root, and push that repository only once on its final commit. - Refresh with the Context MCP server's
git_contexttool when the block is absent, stale, partial, or does not cover an explicitly requested repository. In OpenCode this is exposed ascontext_git_context; setdiff: truewhen subject selection needs content. Do not reconstruct this with rawgit status/git diff.
3. Decide the scope (confirm before staging)
- Prefer several small, coherent commits over one large one. Commit per change, step, or phase so each commit is concise and self-contained; do not lump an entire task into a single commit. This trades some rebase friction for a cleaner, non-conflicting history, which is the preferred tradeoff.
- Make a single commit only when the user explicitly requests one or the reviewed changeset contains only one coherent change.
- A staged set still requires relevance to the current request. Do not commit unrelated staged paths; ask before disturbing or partially committing a set the user staged.
- Filter candidate paths against the current request before staging. Never
commit a path merely because it is listed, staged, session-touched, or forms
a separate coherent change. Exclude unrelated paths; ask when relevance is
ambiguous. Never use
git add -A. - Session attribution is path-level, not hunk-level. If a candidate file may contain pre-existing or concurrent hunks, ask rather than treating the whole file as owned by this session.
- Include untracked files you created for this work; ask before adding anything unexpected.
- Keep formatter-only churn (files reformatted but not part of the change) out of the main commit. Offer a separate follow-up commit for it unless the user says otherwise.
- Prefer
--path <file>(repeatable) to scope the commit to exact files; it commits only those and leaves any other staged files untouched. This is also how you make several scoped commits from one working tree.
4. Write the subject
- Author in the maintainer's voice: imperative, verb-first, sentence case, no
trailing full stop, no Conventional Commit prefix, single line. Mirror recent
subjects from the injected context,
git_context, orgit log. - The gateway enforces: single line, no em/en-dash (use a hyphen), no trailing full stop, no tabs/control characters. It warns over 60 characters and rejects over 120. Aim for roughly 60 or fewer.
5. Commit
dot git-commit -m "<subject>" # commit the staged set
dot git-commit -m "<subject>" --path src/x.ts # commit only these files
dot git-commit --amend # fold staged changes into HEAD, keep its message
dot git-commit --amend -m "<subject>" # rewrite HEAD's subject (reword)
dot git-commit -m "<subject>" --dry-run # preview, change nothing
- Skip
--dry-runwhen you already know what is staged and are safe to commit;git_context(step 2) is the check for that, and the preview adds little beyond it. Reserve--dry-runfor when you are genuinely unsure what is staged. - Use
--amendonly to fix up the previous commit the user just made, and only when they ask for an amend. Without--messageit keeps HEAD's message; pass--messageto reword. An amend with nothing staged is allowed, so--amend -m "<subject>"is how you reword the last commit. Do not amend a commit someone else may have based work on. - If the gateway rejects the subject, fix it and rerun; do not work around it.
- The gateway refuses to commit to the base branch of a repo you do not own
(owners in
git config dot.owner), so you do not commit to, say,devonhome-assistant/frontend. This also applies to a fork kept for upstream PRs (foreignupstreamremote): work on a feature branch, not the fork's base branch. A takeover fork with no foreign remote, and every non-base branch, are fine. The base branch is resolved fromorigin/HEAD, not assumed. Move to a feature branch and open a PR; do not try to work around the guard.
6. Push (only when asked)
dot git-commit -m "<subject>" --push
--pushpulls with--rebase(autostashing local edits) before pushing so a moved-ahead remote fast-forwards, sets the upstream when missing, and never force-pushes. On a rebase conflict it aborts and keeps your commit for manual integration. Only push when the user asked for this specific push (a/commit-pushinvocation, or explicit "push").- For a split changeset, omit
--pushfrom every preceding commit and pass it only to the final commit so the complete series is pushed once. - Combining
--amend --pushforce-pushes with--force-with-lease(never a plain force): it overwrites the remote branch only when it still matches the ref last seen, so a teammate's or bot's newer commit blocks the push instead of being clobbered. Only do this on a branch that is safe to rewrite.
7. Report
- Report the commit subject, the files committed, any separate formatting commit, and the push result.