Git Workflow
History is documentation that cannot be faked. A commit explains one change, to a reader who was not there.
1. Author identity
Every commit carries a real person, taken from the suite configuration:
identity.author_name
identity.author_email
Both are required and neither has a default. Resolve them, then verify the repository agrees, before staging anything:
git config user.name
git config user.email
| Situation | Action |
|---|---|
| Both configuration fields present, repository matches | commit |
| Both present, repository differs | set the repository values, then commit |
| Either field missing or empty | stop, name the missing field, run bash install.sh --configure |
| Repository deliberately uses a different identity | follow the repository, and say so once |
An identity is never invented, never inferred from the last commit, and never
filled with a placeholder to get past this step. A history whose author cannot
be traced to a person is not auditable, which is the entire point of a history.
The field reference is in config/README.md.
Forbidden in commit messages, trailers, author fields, committer fields, pull request bodies and branch names:
Co-authored-by with any assistant or tool
Generated by, Created with, Assisted by
any mention of Claude, an AI, an assistant, a bot or a model
This rule overrides any default trailer behaviour of the tooling. A commit that has already been made with a forbidden trailer is amended before it is pushed.
2. What you are allowed to do
Read the delegation section of the configuration before acting. It decides
which of the steps below you perform and which you prepare and hand over.
| Field | Value | Behaviour |
|---|---|---|
commits |
yes |
commit normally |
stage-only |
stage the change, give the message you would have used, stop | |
no |
leave the tree ready, list the atomic commits in order with a message each, stop | |
branches |
no |
do not create a branch; ask which one to use |
push |
yes |
push |
branch-only |
push feature branches, never a protected branch | |
no |
commit locally and stop | |
pull_requests |
draft |
open it as a draft, do not mark it ready |
no |
write the description into the branch and stop |
git.protected_branches names what never receives a direct push. Anything
other than none means the pull request path, always.
When a step is not yours, say so in one line, state exactly what is waiting,
and give the command. Do not perform it anyway because it would be faster, and
do not stay silent about it: a step nobody was told about is a step nobody
does. The full list lives in craft-manual-tasks.md next to the
configuration file.
Missing configuration is not permission. If the file has no delegation
section, use the defaults in config/README.md and say which ones you
applied.
3. Atomic commits
One commit contains one change, and nothing else.
| Situation | Commits |
|---|---|
| a feature with a migration, an endpoint and a UI | at least three |
| a fix plus a formatting sweep | two, the sweep separate |
| a dependency addition plus its usage | two, the dependency alone |
| a refactor plus a behaviour change | two, the refactor first |
| unrelated typo noticed while working | its own commit, or left alone |
The test: can the commit be reverted alone without breaking something unrelated? If not, it is two commits.
The other test: does the message need the word and? If yes, it is two
commits.
4. Message format
<type>: <imperative summary under about seventy characters>
<body, only when the summary is insufficient: why, not what>
Types: feat, fix, docs, test, refactor, chore, perf, style,
build, ci.
Rules:
- English, imperative mood:
add, notaddedoradds; - no trailing period on the summary;
- the summary describes the change, not the file list;
- the body explains why the change was necessary, and what was rejected, when that is not obvious;
- reference an issue when the project does so, in the project's format;
- match the project's existing style, read from
git log, when it differs from this default.
feat: add user profile endpoint
fix: handle expired payment session
test: cover invalid registration input
refactor: extract payment validation
docs: document authentication flow
perf: replace per order customer lookup with a join
chore: add pdf-lib for invoice generation
Rejected:
update code says nothing
fix bug which bug
feat: add endpoint and fix tests two commits
WIP not a commit, use a local stash or amend
Various improvements a diff nobody will read again
5. Before every commit
git status # nothing unexpected staged
git diff --staged # read it, entirely
Checked in the staged diff:
- no secret, key, token, password or connection string;
- no
.envfile, no local machine configuration; - no debug output, no commented out code, no temporary file;
- no unrelated change;
- no large binary that belongs elsewhere;
- no generated artefact the project does not track.
Reading the staged diff before committing is not optional. It is the last point at which a secret can be kept out of history cheaply.
6. Ignore rules
Verify the repository ignores, at minimum:
.env
.env.*
*.pem
*.key
credentials.json
node_modules/ and equivalent dependency directories
build output directories
editor and OS local files
agent and tool local directories such as .claude/
When one is missing, fix the ignore file before committing anything else, in
its own chore: commit.
Two exceptions exist and are decided explicitly rather than silently: a file that is already tracked is not hidden by adding it to the ignore file, and a repository that deliberately tracks its own agent configuration or memory file records that decision instead of following the default blindly.
A secret already committed is not solved by a later ignore rule or a subsequent deletion. It is reported for rotation.
7. Branches
Read the convention from the repository before creating anything:
git branch -a
git log --oneline --decorate -20
Follow what exists. When nothing exists, use type/short-kebab-description,
in English, naming the change and not the person or the ticket alone.
feat/team-invitations
fix/expired-session-redirect
chore/upgrade-prisma
Never commit directly to the default branch when the project uses branches. Never force push a shared branch. When history must be rewritten on a personal branch, use the force with lease form so a concurrent push is not destroyed.
8. Pull requests
## Summary
What changed and why, in a few lines.
## Implementation
The decisions a reviewer needs, including what was rejected.
## Tests
What was added, what was run, the observed result.
## Screenshots
For any visual change, before and after.
## Migrations
What runs, whether it is reversible, the deploy ordering.
## Deployment notes
Environment variables, provider configuration, manual steps.
## Risks
What could break, and how it would show.
## Follow up
Named, with why it was not done here.
Sections that do not apply are removed, not filled with none. A pull request that only says what the diff already says has added nothing.
9. History hygiene
- Rebase a personal branch on the default branch rather than merging it back and forth, when that is the project's habit.
- Squash noise commits on a personal branch before review; keep meaningful ones.
- Never rewrite public history.
- Never amend a commit that has been pushed to a shared branch.
- Resolve conflicts by understanding both sides, never by taking one wholesale because it is faster.
- After any conflict resolution, run the tests before committing the merge.
10. Protocol
- Read the
delegationsection. Know which steps below are yours before starting any of them. - Verify the author identity.
- Verify the ignore rules, fix them first when they are wrong.
- Group the work into atomic changes.
- Stage one change, read the staged diff completely.
- Commit with a message that follows section 4, or stop at the boundary set
by
delegation.commitsand hand over the message. - Repeat.
- Verify the log: author, order, message quality.
- Push, within the limits of
delegation.pushandgit.protected_branches. On rejection, diagnose before retrying. - Open the pull request with the sections of section 8 that apply, within
the limits of
delegation.pull_requests. - Report every step you stopped at, in one line each, with its command.
11. Auto-critique
Score from 0 to 5: identity correct, no forbidden attribution, atomicity, message quality, staged diff actually read, ignore rules correct, no secret, branch convention followed, pull request usefulness, delegation boundaries respected and the handover stated.
Threshold: no axis below 3, average at least 4. A secret in a commit or a forbidden attribution is an automatic failure, and the commit is amended before any push. Performing a step the configuration reserved for the user is also an automatic failure, and so is stopping at one without saying so.
12. Interfaces
- Upstream: every skill that produces a change.
- Downstream:
release-readiness,project-continuity. - Related:
engineering-coresection 5 for secret hygiene.