Git & Version Control Standards
Git & Version Control Standards
Section titled “Git & Version Control Standards”1. Repository Structure
Section titled “1. Repository Structure”Branch Strategy
Section titled “Branch Strategy”- Main Branch:
main(ormasterfor legacy). Protected branch. All production code. - Development Branch:
develop(optional). Integration branch for features. - Feature Branches:
feature/description(e.g.,feature/user-authentication) - Bug Fixes:
fix/description(e.g.,fix/email-validation) - Hotfixes:
hotfix/description(e.g.,hotfix/security-patch) - Releases:
release/version(e.g.,release/1.2.0)
Branch Naming
Section titled “Branch Naming”- Format:
type/description(kebab-case) - Branch prefixes:
feature,fix,hotfix,release,refactor,docs,test - Description: Concise, descriptive (3-5 words)
Branch prefixes are not commit types. The words above name branches (
feature/user-auth,hotfix/security-patch). Commit messages use the Conventional Commits types below — notefeat, notfeature, and there is nohotfix/releasecommit type. The canonical commit-type set is defined once inshared/core-standards.md(§ Commit Messages); this document must stay aligned with it.
2. Commit Messages
Section titled “2. Commit Messages”Conventional Commits Format
Section titled “Conventional Commits Format”<type>(<scope>): <subject>
<body>
<footer>Commit Types
Section titled “Commit Types”The canonical cross-cutting set (from shared/core-standards.md) is:
feat, fix, refactor, test, docs, chore, perf, ci.
- feat: New feature
- fix: Bug fix
- refactor: Code refactoring (no functional changes)
- test: Adding or updating tests
- docs: Documentation changes
- chore: Maintenance tasks (dependencies, build config)
- perf: Performance improvements
- ci: CI/CD changes
Additional Conventional Commits types the linter also accepts
(scripts/lint-checks/common/conventional-commits.sh) but which fall outside
the canonical set: build (build-system changes), style (formatting-only
changes), revert (reverting a prior commit). Prefer the canonical types.
Commit Guidelines
Section titled “Commit Guidelines”- Subject: Imperative mood, 50 characters or less, no period
- Body: Explain “what” and “why”, wrap at 72 characters
- Footer: Reference issues/PRs:
Closes #123,Fixes #456 - Scope: Optional, indicates area of change (e.g.,
domain,api,ui)
Examples
Section titled “Examples”feat(domain): add user email validation
Implement RFC 5322 compliant email validation in Email value object.Rejects invalid formats at domain boundary to fail fast.
Closes #123fix(api): handle null response in user endpoint
Return 404 instead of 500 when user not found. Prevents servererrors from propagating to client.
Fixes #4563. Commit Best Practices
Section titled “3. Commit Best Practices”Atomic Commits
Section titled “Atomic Commits”- One Logical Change: Each commit should represent one complete, logical change
- Small Commits: Prefer multiple small commits over one large commit
- Testable: Each commit should leave the codebase in a working state
Commit Frequency
Section titled “Commit Frequency”- Regular Commits: Commit frequently (at least daily during active development)
- Logical Units: Commit when a logical unit of work is complete
- Before Break: Commit before leaving work for extended periods
What to Commit
Section titled “What to Commit”- Source Code: All source code, tests, and configuration
- Documentation: README, docs, comments
- Configuration: Build files, CI config, editor configs
- Dependencies: Lock files (package-lock.json, Cargo.lock, etc.)
What NOT to Commit
Section titled “What NOT to Commit”- Secrets: API keys, passwords, tokens, credentials
- Build Artifacts: Compiled binaries,
dist/,build/,target/ - Dependencies:
node_modules/,venv/,.envfiles - IDE Files:
.idea/,.vscode/(unless project-specific settings) - OS Files:
.DS_Store,Thumbs.db
4. Git Workflow
Section titled “4. Git Workflow”Feature Development
Section titled “Feature Development”- Create feature branch from
mainordevelop - Make atomic commits with descriptive messages
- Push branch regularly (at least daily)
- Open Pull Request when feature is complete
- Address review feedback with additional commits
- Squash commits if requested during review
- Merge via Pull Request (no direct pushes to main)
Pull Request Process
Section titled “Pull Request Process”- Title: Follow conventional commit format
- Description: Explain what, why, and how. Include screenshots for UI changes
- Size: Keep PRs focused and reviewable (< 400 lines when possible)
- Tests: Include tests for new features and bug fixes
- Documentation: Update documentation for user-facing changes
- CI: All CI checks must pass before merge
Code Review
Section titled “Code Review”- Required: At least one approval before merge
- Response Time: Review within 24-48 hours
- Feedback: Be constructive and specific
- Approval: Approve only when code meets standards
Merge Strategy
Section titled “Merge Strategy”- Squash and Merge: Preferred for feature branches (clean history)
- Merge Commit: Use for important features (preserve branch context)
- Rebase: Use for keeping feature branches up to date (avoid merge commits)
5. Tagging and Releases
Section titled “5. Tagging and Releases”Semantic Versioning
Section titled “Semantic Versioning”Format: MAJOR.MINOR.PATCH (e.g., 1.2.3)
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Tagging
Section titled “Tagging”- Format:
v1.2.3(prefixed withv) - Annotated Tags: Use annotated tags for releases:
git tag -a v1.2.3 -m "Release 1.2.3" - Release Notes: Include release notes in tag message or GitHub release
Release Process
Section titled “Release Process”- Update version in code and
CHANGELOG.md - Create release branch:
release/v1.2.3 - Final testing and bug fixes
- Merge to
mainand tag:git tag -a v1.2.3 - Push tag:
git push origin v1.2.3 - Create GitHub/GitLab release with notes
- Merge back to
developif applicable
Release Version vs. Build Version
Section titled “Release Version vs. Build Version”For products that deploy continuously, distinguish two version numbers:
- Release version — manual semantic version (
MAJOR.MINOR.PATCH), bumped deliberately at a release. It is what users see and what gates a coordinated release (e.g. apps and marketing site move together on a release-version bump). - Build version — derived automatically and ticking on every commit to the
mainline (e.g.
git rev-list --count HEAD). Useful for “exact build” reporting and crash triage, never for user-facing semver decisions.
Surface both in an About/diagnostics view. A value only tree-shakes in if it is actually rendered — exporting it isn’t enough.
Deploy Channels & Promotion
Section titled “Deploy Channels & Promotion”- Separate staging/preview from production by channel. The mainline branch auto-deploys to the staging channel; production is gated on an explicit promotion. Never deploy production off arbitrary feature branches.
- If the deploy platform’s branch control takes no wildcard, gate production on a
single long-lived
releasebranch (notrelease/*) and promote by fast-forwarding mainline into it (git push origin main:release). - Channel-gate not-yet-released content (e.g. an “unreleased” changelog section
visible only on the staging channel) via a build-time channel variable. Verify
the variable name matches what the deploy platform actually injects — a typo
(
PUBLIC_CHANNELvsVITE_CHANNEL) silently ships the wrong content. - A green release does not prove production updated. End the release with an
automated version assertion against the live deployment (fetch it, assert the
new release/build number), not “the promote step succeeded”. The deploy
platform’s credentials and branch protections live outside the repo and fail
invisibly — a rolled or deleted build token, or a force-push-protected
releasebranch that silently rejects the fast-forward promote — so a green in-repo pipeline is necessary but not sufficient. See arch-08_ci_cd_pipeline_standards.md §7 for the CI-side smoke check.
Scripted, Reviewable Release Cut
Section titled “Scripted, Reviewable Release Cut”Automate the release cut as a script that produces a reviewable PR, not a manual sequence of edits:
- A pure script performs the semver bump and promotes changelog entries
(
unreleased/→ the released version section), and emits the release-notes body. - The script opens (or prepares) a PR for human review before anything is tagged or promoted. Tagging and channel promotion happen only after that PR merges.
- Mind CI-identity loop-prevention: a PR opened by a CI token often does not trigger the normal PR gate, so a fully hands-free release usually needs a dedicated app token or a human to open/merge the cut PR. Document which model the repo uses.
See arch-08_ci_cd_pipeline_standards.md §7 for the CI side of channel promotion.
6. Git Configuration
Section titled “6. Git Configuration”Required Settings
Section titled “Required Settings”# User identificationgit config --global user.name "Your Name"git config --global user.email "your.email@example.com"
# Default branch namegit config --global init.defaultBranch main
# Push behaviorgit config --global push.default simplegit config --global push.autoSetupRemote true
# Pull behaviorgit config --global pull.rebase false # Use merge by defaultRecommended Settings
Section titled “Recommended Settings”# Color outputgit config --global color.ui auto
# Editorgit config --global core.editor "code --wait" # VS CodeGit Aliases
Section titled “Git Aliases”See Git Aliases Reference for the full alias catalog. Run scripts/setup-git-aliases.sh to install.
7. Git Hooks
Section titled “7. Git Hooks”Pre-commit Hook
Section titled “Pre-commit Hook”- Linting: Run linters (ESLint, Pylint, Clippy)
- Formatting: Auto-format code (Prettier, Black, rustfmt)
- Tests: Run fast unit tests
- Validation: Check commit message format
Pre-push Hook
Section titled “Pre-push Hook”- Tests: Run full test suite
- Type Checking: Run type checkers (TypeScript, mypy)
- Build: Verify project builds successfully
Commit-msg Hook
Section titled “Commit-msg Hook”- Format Validation: Ensure commit messages follow conventional format
- Length Check: Validate subject line length
Implementation
Section titled “Implementation”Use tools like:
- Husky (Node.js)
- pre-commit (Python)
- git-hooks (Rust)
- Custom shell scripts
8. .gitignore Patterns
Section titled “8. .gitignore Patterns”Language-Specific
Section titled “Language-Specific”Python:
__pycache__/*.py[cod]*$py.class*.so.Pythonvenv/env/.venvNode.js:
node_modules/npm-debug.log*yarn-debug.log*yarn-error.log*.pnpm-debug.log*dist/build/Rust:
target/Cargo.lock # For libraries, not applicationsJava:
*.class*.jar*.war*.ear.gradle/build/Test / coverage output
Section titled “Test / coverage output”Ignore generated coverage reports so they are never committed:
coverage/Common tools that write here: Vitest, Jest, pytest, Istanbul/c8, lcov. Projects using the standards setup or install scripts get this pattern added automatically.
General
Section titled “General”# Environment.env.env.local.env.*.local
# IDE.idea/.vscode/*.swp*.swo*~
# OS.DS_StoreThumbs.db
# Logs*.loglogs/9. Large Files and Git LFS
Section titled “9. Large Files and Git LFS”Git LFS
Section titled “Git LFS”Use Git LFS for:
- Binary files > 100MB
- Media files (images, videos)
- Compiled binaries
- Database dumps
Configuration
Section titled “Configuration”git lfs installgit lfs track "*.psd"git lfs track "*.zip"10. Branch Lifecycle
Section titled “10. Branch Lifecycle”Cleanup After Merge
Section titled “Cleanup After Merge”Branches MUST be deleted — both local and remote — immediately after their PR is merged or closed. Do not accumulate stale branches.
- PR merge: Enable “Automatically delete head branches” in GitHub repo settings. This handles the remote branch. Delete the local branch manually after merge.
- Squash merges: Squash-merged branches are not detected by
git branch --merged. Usegit branch -d <branch>(lowercase-d) which checks if the branch is fully merged; if it refuses, verify the work landed via PR, then usegit branch -D <branch>. - Worktrees: Remove the worktree before deleting its branch:
git worktree remove <path>thengit branch -D <branch>.
Naming Branches for Traceability
Section titled “Naming Branches for Traceability”Include enough context in the branch name to identify the work without checking the log:
feat/preview-scroll-optimization ✓ clear purposefix/sidebar-drag-crash ✓ clear purposeworktree-agent-a0939472 ✗ opaque, impossible to triage latertmp ✗ no contextcopilot/sub-pr-7 ✗ meaningless without the PRAgent-generated branches MUST follow the same type/description convention as human branches. Opaque IDs or numeric suffixes alone are not acceptable names.
Periodic Audit
Section titled “Periodic Audit”Run a branch audit at least every two weeks (or before starting a new feature):
# List local branches not on main, sorted by last commit dategit branch --no-merged main --format='%(committerdate:short) %(refname:short)' | sort
# List remote branches with no recent activity (>14 days)git for-each-ref --sort=committerdate --format='%(committerdate:short) %(refname:short)' refs/remotes/origin | head -20
# Delete local branches whose remote is gonegit fetch --prunegit branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -DProjects using make SHOULD include a cleanup target:
branch-cleanup: ## Delete local branches whose remote tracking branch is gone @git fetch --prune @git branch -vv | grep ': gone]' | awk '{print $$1}' | xargs -r git branch -D @echo "Remaining branches:" && git branchBranch Limits
Section titled “Branch Limits”As a guideline, a repository should have fewer than 10 active branches at any time. If you have more, audit and clean up before creating new ones. This applies to both local and remote branches (excluding main).
Garbage Collection
Section titled “Garbage Collection”- Run
git gcperiodically (usually automatic). - After large cleanups, run
git gc --prune=nowto reclaim space immediately.
Security
Section titled “Security”- Secrets Scanning: Use tools like
git-secrets,truffleHog - History Rewriting: Avoid force-pushing to shared branches
- Access Control: Use branch protection rules (GitHub/GitLab)
Backup
Section titled “Backup”- Remote Repository: Always push to remote (GitHub, GitLab, etc.)
- Multiple Remotes: Consider backup remote for critical projects
- Regular Pushes: Push at least daily during active development
11. Stacked & Dependent PRs and Platform Automation Traps
Section titled “11. Stacked & Dependent PRs and Platform Automation Traps”When PRs depend on each other or are driven by automation, a handful of platform behaviors silently cause lost work or false signals. Encode them.
Stacked PRs — the base-deletion trap
Section titled “Stacked PRs — the base-deletion trap”When PR B is based on PR A’s branch (B’s base = A’s feature branch):
- Merging A with delete-branch (
gh pr merge A --squash --delete-branch) closes B — the host does not auto-retarget B to mainline, and B cannot be reopened once its base branch is gone. - Avoid it: before merging A, either retarget B to mainline first
(
gh pr edit B --base main) while A’s branch still exists, or merge A without deleting its branch until B is retargeted. - Recover (if B was already closed by an A merge): in B’s worktree,
git rebase --onto origin/main <A-tip-commit>to drop A’s now-redundant commits (their content is in mainline via the squash) and replay only B’s own commits, then open a fresh PR B′ → mainline referencing the closed one.
A conflicting PR runs no checks
Section titled “A conflicting PR runs no checks”A PR with merge conflicts has no merge ref, so the host runs none of its merge-ref-triggered workflows — it looks like CI never fired (zero runs created, not even queued). If a PR’s checks are entirely absent, check its mergeable state and resolve the conflict; the checks then trigger normally. Distinguish this from a self-hosted runner being offline (which produces a queued run that waits).
Other host-automation traps
Section titled “Other host-automation traps”- One close-keyword per line.
Closes #A, #B, #Conly auto-closes the first issue. Write oneCloses #Xper line to fan out across issues. - Check polling can settle early. Right after a push, only fast external checks are registered; host-run jobs appear seconds later. A poll that exits as soon as “all known checks are non-pending” can exit before real CI starts — guard with a minimum-expected-check count.
gh pr createinfers the branch from the current directory. Run it from the correct worktree, or pass--head <branch>explicitly, or it opens a PR for whatever branch the cwd is on. See proc-04_agent_workflow_standards.md § Worktree Hygiene.