Git Workflow
Use when making git commits, creating branches, or starting any implementation work that will require more than one commit. Ensures Conventional Commits format, atomic commits (one logical unit per commit), and git worktree isolation for multi-commit work.
Git Workflow
Overview
Enforces three practices: Conventional Commits for every commit message, atomic commits that separate changes into logical/contextual units, and git worktree isolation for any work requiring more than one commit.
When to Use
- Before writing a commit message
- Before starting feature work, bug fixes, or refactors that need multiple commits
- When creating branches
Pre-Commit Gate
<!-- Defense-in-depth: this gate is intentionally redundant with CLAUDE.md and using-necturalabs. --> <!-- It catches the case where the model skipped the mandatory review and reached commit directly. --> <HARD-GATE> **BEFORE committing, verify that `necturalabs:iterative-code-review` has run on these changes.** If it has not, **STOP** — invoke it first. If changes are security-related, `necturalabs:iterative-security-audit` must run before code review.Do NOT commit without a completed review. No exceptions — not for "small changes", not for "just docs", not for "I already looked at it manually." </HARD-GATE>
Atomic Commits
Every commit should be a single logical unit of change. Separate unrelated changes into distinct commits, even within the same work session.
Rules
- One concern per commit — a bug fix, a feature addition, a refactor, a test, or a docs update. Never mix these in a single commit.
- Each commit should compile and pass tests — the repo must be in a valid state at every commit. Never commit a half-finished feature that breaks the build.
- Group by context, not by file — if a feature requires changes across 5 files, that is one commit. If you fix a typo in the README while implementing a feature, that is two commits.
- Refactoring goes in its own commit — separate "move/rename/restructure" from "add/change behavior." This makes each commit reviewable in isolation.
- Config and dependency changes go in their own commit — version bumps, new dependencies, and config changes should not be mixed with feature code.
Decision Guide
Is this change related to the same logical concern?
YES → Same commit
NO → Separate commit
Does this commit do exactly ONE thing?
YES → Good
NO → Split it
Could someone revert this commit without losing unrelated work?
YES → Good
NO → Split it
Anti-Patterns
| Bad Practice | Why | Fix |
|---|---|---|
| "Fix bug and add feature" | Two concerns in one commit | Two separate commits |
| "Update 12 files" | No indication of what changed or why | Split by logical concern |
| "WIP" or "checkpoint" | Incomplete work pollutes history | Finish the unit, then commit |
| Mixing formatting with logic | Impossible to review logic changes | Formatting commit first, then logic |
| Committing generated + source together | Generated files obscure real changes | Source commit, then regenerate |
Commit Message Format
<type>(<optional-scope>): <description>
[optional body]
[optional footer(s)]
Types
| Type | When to use |
|---|---|
feat | New feature or functionality |
fix | Bug fix |
docs | Documentation only |
style | Formatting, whitespace (no logic change) |
refactor | Code restructuring (no bug fix, no new feature) |
perf | Performance improvement |
test | Adding or fixing tests |
build | Build system or dependency changes |
ci | CI/CD configuration |
chore | Routine maintenance |
Subject Line Rules
- Imperative mood -- "add" not "added" or "adds"
- 50 chars target, 72 hard max -- if you struggle to fit, the commit does too much
- No period at the end
- Lowercase after type prefix
- Litmus test: "If applied, this commit will [your subject line]"
Body (required for non-trivial changes)
- Blank line between subject and body
- Wrap at 72 characters
- Explain what changed and why, not how
- Describe: what was wrong before, what is better now, why this approach
Footers
- Issue references:
Closes #123,Fixes #456 - Breaking changes:
BREAKING CHANGE: <description>or!after type (feat!:)
Examples
feat(auth): add OAuth2 login flow
Implement OAuth2 authorization code flow with PKCE. Replaces the
legacy session-based auth which doesn't meet compliance requirements
for token storage.
Closes #142
fix: prevent race condition in request handler
Introduce a request ID and reference to the latest request. Dismiss
incoming responses other than from the latest request.
Previously, rapid sequential requests returned stale data because
responses were processed in arrival order.
refactor: extract validation into shared module
docs: update API authentication guide
Bad Commits -- Never Do These
| Bad message | Why it's wrong |
|---|---|
fix stuff | No type prefix, vague |
feat: Updated the login page. | Past tense, period, capitalized after prefix |
WIP | Never commit work-in-progress |
misc changes | Meaningless |
feat: changes | No description of what changed |
Worktree Workflow
When to Use Worktrees
digraph worktree_decision {
"Starting new work" [shape=doublecircle];
"Needs >1 commit?" [shape=diamond];
"Create worktree + branch" [shape=box];
"Commit directly on current branch" [shape=box];
"Do the work" [shape=box];
"Merge, remove worktree, delete branch" [shape=box];
"Starting new work" -> "Needs >1 commit?";
"Needs >1 commit?" -> "Create worktree + branch" [label="yes"];
"Needs >1 commit?" -> "Commit directly on current branch" [label="no"];
"Create worktree + branch" -> "Do the work";
"Do the work" -> "Merge, remove worktree, delete branch";
}
Skip worktrees for: single-commit changes (typo fixes, one-line config tweaks).
Creating a Worktree
# From your main worktree — use <project>-<description> for the path:
git worktree add ../<project>-<description> -b feature/short-description
# Examples:
git worktree add ../myapp-user-auth -b feature/user-authentication
git worktree add ../myapp-fix-cart -b bugfix/cart-total-rounding
LFS in Worktrees
Git worktrees share the main repo's .git directory (the worktree has a .git file pointing back, not its own .git folder). This means the LFS object cache at .git/lfs/objects/ is already shared — objects downloaded in the main repo are available to every worktree.
# In the worktree, populate LFS files from the shared local cache:
cd <worktree> && git lfs checkout
# Do NOT use `git lfs pull` — it contacts the remote and re-downloads
# objects that are already in the shared cache.
- Use
git lfs checkout(local-only) — reads from the shared.git/lfs/objects/cache - Never use
git lfs pullin a worktree when the main repo already has the objects — it wastes bandwidth re-fetching what's already cached locally - Only fall back to
git lfs pullif objects are genuinely missing from the local cache
Branch Naming
Format: <type>/<lowercase-hyphenated-description>
| Prefix | Purpose | Example |
|---|---|---|
feature/ | New functionality | feature/user-authentication |
bugfix/ | Non-urgent bug fix (longer form distinguishes from hotfix/) | bugfix/cart-total-rounding |
hotfix/ | Urgent production fix | hotfix/payment-null-pointer |
refactor/ | Code improvement | refactor/extract-auth-service |
docs/ | Documentation | docs/api-reference |
test/ | Test additions | test/payment-edge-cases |
chore/ | Maintenance | chore/upgrade-dependencies |
Rules:
- Lowercase only, hyphens between words
- Be specific:
feature/user-authnotfeature/stuff - Include ticket ID when available:
feature/PROJ-123-user-auth
Cleanup After Merge
# After branch is merged:
git worktree remove ../worktree-path
git branch -d feature/branch-name
# NEVER use rm -rf on worktrees -- leaves stale metadata
# If you did, fix with:
git worktree prune
Quick Reference
| Action | Command |
|---|---|
| Create worktree | git worktree add <path> -b <branch> |
| List worktrees | git worktree list |
| Remove worktree | git worktree remove <path> |
| Clean stale data | git worktree prune |
| Delete branch | git branch -d <branch> |
Post-Push: CI Monitoring
After every git push, if gh CLI is available:
- Run
gh run list --limit 1to check if the push triggered a CI run - If a run was triggered,
gh run watch <run-id>to monitor it to completion - If no run was triggered (branch doesn't match workflow triggers), skip
Never push and walk away without confirming CI status.