Installs into .claude/skills of the current project.
Are you the author of Git Conventions?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/sefaertunc-git-conventions)
---
description: "Branch naming, commit message format, PR workflow, worktree conventions, versioning policy"
when_to_use: "When creating branches, writing commit messages, creating PRs, or making versioning decisions"
version: "1.0.0"
---
# Git Conventions
## Invocation Boundary
`git commit`, `git push`, and `gh pr create` are invoked only when the human
explicitly types `/commit-push-pr` or `/sync` (or one of their listed Trigger
Phrases). The slash commands themselves are not invoked autonomously — wait for
the human trigger. The `Version bump:` AskUserQuestion in `/commit-push-pr` is
non-skippable; refuse to proceed without an explicit human selection.
See CLAUDE.md Critical Rule 13.
## Branch Naming
Pattern: `{type}/{short-description}`
Types:
- `feature/` — New functionality
- `fix/` — Bug fixes
- `refactor/` — Code restructuring without behavior change
- `docs/` — Documentation only
- `test/` — Test additions or fixes
- `chore/` — Tooling, dependencies, config
Examples:
- `feature/auth-flow`
- `fix/login-timeout`
- `refactor/extract-merger-module`
Keep branch names under 50 characters. Use hyphens, not underscores.
## Commit Messages
Follow conventional commits format:
```
type(scope): short description
Longer explanation if needed. Focus on WHY, not WHAT.
The diff already shows what changed.
Closes #123
```
Types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf`, `ci`
Scope is optional but helpful: `feat(auth): add OAuth2 token refresh`
Rules:
- Subject line under 72 characters
- Imperative mood ("add" not "added" or "adds")
- No period at the end of the subject line
- Blank line between subject and body
- Body explains motivation, not mechanics
- Never append Co-Authored-By trailers, AI attribution lines, or "Generated with" footers
## When to Commit
Commit after each logical unit of work:
- A function is complete and tested
- A refactor is done and tests pass
- A bug is fixed and verified
Don't batch unrelated changes into one commit. Don't commit broken code.
## Branching Strategy
```
feature-branch ──PR──▶ develop ──PR──▶ main (release)
```
- `develop` — active development. Contributors fork, branch from `develop`, and PR back to `develop`.
- `main` — production releases. Maintainer-only, merged from `develop`.
- `gh-pages` — auto-deployed docs. Maintainer-only.
All feature/bugfix branches are created from and merged back into `develop`. Never PR directly to `main`.
## PR Workflow
1. Push your branch
2. Create PR with `gh pr create --base develop` (feature/bugfix branches target `develop`)
3. When on `develop`, PR targets `main`: `gh pr create --base main` (release merges only)
4. PR title follows same format as commit subject: `type(scope): description`
5. PR body includes: what changed, why, how to test, anything reviewers should know
6. Request review if the project has reviewers configured
7. Do not add AI-generated footers (e.g., "Generated with Claude Code") to PR descriptions
## Squash vs Merge
- Squash when: the branch has many small "wip" commits that don't individually matter
- Merge when: each commit in the branch is a meaningful, atomic change
- Rebase when: you need a linear history and commits are clean
Default preference: squash merge for feature branches, regular merge for release branches.
## Worktree Conventions
When using `git worktree` for parallel work:
- Worktrees go in a sibling directory, not inside the repo
- Naming: `{repo}-{branch-name}` for the worktree directory
- Always clean up worktrees when done: `git worktree remove {path}`
- Don't leave stale worktrees — they hold refs and can cause confusion
Agents that use worktree isolation (code-simplifier, test-writer, bug-fixer, etc.)
create and clean up their own worktrees automatically.
## Shared-State Files
These files are modified ONLY on the develop branch (via /sync), never on feature branches:
- `docs/spec/PROGRESS.md` — project progress tracker
- `docs/spec/SPEC.md` — feature specification
- `README.md` — project documentation
- `package.json` version field — release versioning
This prevents merge conflicts when running parallel feature branches.
## Versioning Policy
Follow [semver](https://semver.org/) when the project publishes releases:
| What changed | Bump | Example |
|---|---|---|
| Bug fix, patch to existing behavior | **patch** | Fixed edge case in date parser |
| New feature, command, or API surface | **minor** | Added CSV export option |
| Breaking change to public API or CLI | **major** | Renamed config key, removed flag |
| Only docs, CI, tests, internal refactor | **no bump** | Updated README, added test |
**Publish from the primary branch (usually `main`),** not from feature or development branches. What is published must always match what is on the release branch.
**When to bump:** Include the version change in the same PR as the work — no separate "bump version" commits after the fact.
**How to publish:**
1. Merge the release PR into `main`
2. Pull locally: `git checkout main && git pull`
3. Publish using your ecosystem's tool (`npm publish`, `cargo publish`, `twine upload`, etc.)
4. Sync develop: `git checkout develop && git merge main && git push origin develop`
**Rule of thumb:** If the change affects what users see, install, or depend on, it needs a version bump. If it only affects the project's internal development workflow, it does not.
### Per-PR bump declarations
Every PR targeting `develop` declares its intended version bump in the PR
description:
```
Version bump: {major|minor|patch|none}
```
- `major` — breaking change to public API, CLI, or scaffold contract
- `minor` — new feature, command, agent, or flag
- `patch` — bug fix or user-visible behavior change with no new surface
- `none` — docs, CI, tests, internal refactor (nothing consumers notice)
`/sync` aggregates declarations from all PRs merged since the last version
tag and picks the highest: `major > minor > patch > none`. If all merged
PRs are `none`, no release is cut — `/sync` updates shared-state files but
does not bump the version or open a PR to `main`.
This is how release batching works: internal-only work accumulates on
develop without triggering publishes, and multiple user-facing PRs group
into a single well-documented release.
### Edge cases
- **Release PRs (develop → main):** `/sync` excludes these from scanning.
They ARE the release, not an input to one. Known limitation: any
develop→main PR is excluded regardless of content. Safe in practice
because that direction is only used for releases.
- **Revert PRs:** Declare the same bump level as the PR being reverted.
Reverting a `patch` is itself a `patch`. A `patch` + matching revert
in the same release group produces a net-zero user-visible change but
still bumps the version — something shipped internally and was
un-shipped, which is part of the release's history. Do not cancel
them out.
- **Missing declarations:** Treated as `none` with a warning that
propagates to the release PR body and CHANGELOG entry. Do not manually
backfill old PR bodies — let them flow through as `none` so
under-documentation is visible rather than silent.
- **No tags yet (first release):** `/sync` prompts to create a starting
tag (default `v0.1.0`, customizable, cancelable). The tool does NOT
silently invent a tag.
- **Hotfix merged directly to main:** Bypasses `/sync` entirely. Requires
manual version management. Known limitation; out of scope.
**Optional:** GitHub labels (`release:major`, `release:minor`, etc.) can
replace body-text declarations for maintainers who prefer them. Deferred
to a future phase; not scaffolded by default.
## Gotchas
- Never force-push to main/master. Force-push to feature branches only when you
own the branch and have communicated with collaborators.
- If a rebase goes wrong, `git reflog` is your friend. The old state is still there.
- Don't commit generated files (build output, node_modules, .pyc) — check .gitignore.
- When working in worktrees, remember that stashes are shared across the repo.
A stash in one worktree is visible in another.
- Commit messages are documentation. Future you will read them. Write for that person.