Git Workflow Skill
Enforce a disciplined Gitflow-based development workflow. Every git operation follows strict rules: conventional commits, atomic logical changes, semantic versioning, issue-driven branching, and PR-only merges to protected branches.
When This Skill Applies
- User asks to commit changes
- User asks to create a branch, open a PR, or merge
- User asks to tag a release or create a hotfix
- User mentions "commit", "branch", "merge", "release", "hotfix", "gitflow", "conventional commit", "semver"
- User asks about branching strategy or version management
- Any git operation that affects the repository history
Core Principles
- Atomic logical commits — one commit = one logical change, never mix concerns
- Conventional Commits — structured commit messages with type prefixes
- No AI signatures — never add "Co-Authored-By", "Generated by", or similar lines
- Semantic Versioning —
MAJOR.MINOR.PATCHfor all releases - Issue-driven workflow — every branch starts from a GitHub Issue and closes it
- PR-only merges —
mainanddevelopare never committed to directly - Always
--no-ff— all merges into protected branches use--no-ffto preserve branch topology - Discipline over tooling — follow all workflow rules even when branch protection is not configured or when operating as an admin user who can bypass it. Branch protection is a safety net, not a substitute for discipline. Early-stage repositories may lack protection rules, and admin users are often exempt — neither case permits direct commits to protected branches or merging without a PR.
Branch Model (Gitflow)
Protected Branches
| Branch | Purpose | Merge via |
|---|---|---|
main | Production-ready code | PR only (from release/* or hotfix/*) |
develop | Integration branch for next release | PR only (from feature/* or fix/*) |
Working Branches
| Pattern | Base branch | Merges into | Purpose |
|---|---|---|---|
feature/<issue>-<slug> | develop | develop | New features |
fix/<issue>-<slug> | develop | develop | Bug fixes on develop |
hotfix/<issue>-<slug> | main | main AND develop | Urgent production fixes |
release/<version> | develop | main AND develop | Release preparation |
Sync Before Branching
Always pull the latest base branch before creating a new branch. Without this, sequential branches fork from the same stale commit and miss previously merged work.
git checkout develop
git pull origin develop # ← mandatory before branching
git checkout -b feature/42-slug
This applies to every branch type: feature/* and fix/* pull develop, hotfix/* pulls main, release/* pulls develop.
Merge Strategy
- Always use
--no-fffor merges intomainanddevelop— this preserves the branch topology and groups commits visually - Never squash merge into protected branches — squashing destroys the atomic commit history you carefully crafted
- Never rebase merge into protected branches — rebase rewrites hashes and removes merge commit markers
GitHub settings: In repository settings, only enable "Allow merge commits" and disable "Allow squash merging" and "Allow rebase merging". When using
gh pr merge, always pass--merge --delete-branch.
Keeping Feature Branches Up to Date
- Not yet pushed: rebase onto
developis acceptable (git rebase develop) - Already pushed or PR open: merge
developinto the feature branch (git merge develop) — never force-push a rebased shared branch
Branch Naming Convention
- Always lowercase, hyphen-separated
- Working branches (
feature/*,fix/*,hotfix/*) are prefixed with the issue number - Release branches use version number only:
release/<version> - Examples:
feature/42-add-search,fix/17-broken-navbar,hotfix/89-auth-crash,release/1.2.0
Commit Message Format (Conventional Commits)
Structure
<type>(<optional scope>): <description>
<optional body>
<optional footer>
Types
| Type | When to use | Semver impact |
|---|---|---|
feat | New feature or capability | MINOR bump |
fix | Bug fix | PATCH bump |
docs | Documentation only | None |
chore | Maintenance, config, dependencies | None |
refactor | Code change that neither fixes nor adds | None |
test | Adding or updating tests | None |
style | Formatting, whitespace (no logic change) | None |
perf | Performance improvement | PATCH bump |
ci | CI/CD configuration changes | None |
build | Build system or external dependency changes | None |
revert | Reverting a previous commit | Depends on the original commit type |
Revert semver note: The impact mirrors the reverted commit's type. Reverting a
featremoves a capability (potentially MAJOR if it was public API), reverting afixreintroduces a bug (PATCH when re-fixed). Evaluate the user-facing effect at release time.
Breaking Changes
Append ! after the type or add BREAKING CHANGE: in the footer:
feat!: replace authentication system
BREAKING CHANGE: OAuth tokens from v1 are no longer valid.
Breaking changes trigger a MAJOR version bump.
Rules
- Imperative mood in description: "add feature" not "added feature" or "adds feature"
- Lowercase description start (no capital after colon)
- No period at the end of the description line
- 72 character limit on the description line
- Body wraps at 80 characters, separated by a blank line
- One logical change per commit — if you need "and" in the description, split it
Examples
feat(auth): add OAuth2 login flow
fix: resolve race condition in websocket reconnect
docs: translate design language to English
chore: add MIT license and gitignore
refactor(api): extract validation into middleware
feat!: drop support for Node 16
Issue-Driven Workflow
The Flow
Issue created (including release issues)
↓
Checkout and pull base branch (git pull origin develop/main)
↓
Branch created from issue (feature/42-slug, fix/17-slug, etc.)
↓
Atomic commits on branch
↓
PR opened with Conventional Commits title
↓
Review + test plan verified (check off items in PR description)
↓
Merge (--no-ff)
↓
Issue closed (manually or auto-closed — see note below)
↓
Branch deleted (remote + local)
Rules
- Every branch starts from a GitHub Issue — no branch without an issue, including releases (create a lightweight "Release v1.2.0" issue with
chorelabel) - One PR per issue — the PR closes exactly one issue
- PR title follows Conventional Commits format:
<type>(<scope>): <description> (#<issue>)— e.g.,feat(auth): add OAuth2 login flow (#42) - PR body references the issue:
Closes #42 - Test plan verified before merge — check off each item (
- [x]) in the PR description as it passes. This makes test progress visible to reviewers and serves as an audit trail. - Branch is deleted after merge — both remote (enable GitHub's "Automatically delete head branches") and local (
git fetch --prune && git branch -d <branch>)
GitHub Auto-Close Limitation
Important: GitHub only auto-closes issues via
Closes #Xwhen the PR targets the repository's default branch (usuallymain). In Gitflow, feature and fix PRs targetdevelop, so issues will not auto-close.Workarounds:
- Close manually after merging to
develop— usegh issue close <number>or close via GitHub UI- Use GitHub Actions (recommended) — add a workflow that auto-closes the referenced issue when a PR is merged to any non-default branch. See the reference implementation below.
Always include
Closes #Xin PR bodies for traceability, even when targeting non-default branches.