Skip to content
Santekno.com | Level Up Your Engineering Skills
EN
📖 0%
27 Aug 2026 · 6 min read ·Article 32 / 208
Go

Branching Strategy: One Feature = One Branch, One Spec

How to manage a branching strategy for GitHub Spec Kit in a Golang project. Every feature gets its own branch, its own spec, and a structured Git workflow that keeps the audit trail complete.

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

A branching strategy spec kit golang teams can trust rests on one powerful principle applied consistently: every feature has one branch and one spec, linked to each other. This isn’t just Git hygiene — it’s how you build a complete audit trail and let a team work in parallel without conflicts.

In this article we translate that principle into concrete branch names, workflows, protection rules, and CI checks you can adopt as-is.


12.1 Core Principle

The whole strategy fits in one mental picture: a feature branch that carries its spec alongside its code. The tree below shows that pairing.

text
1feature/SHOP-789-product-review
2├── .specify/features/product-review/spec.md
3├── .specify/features/product-review/plan.md
4├── .specify/features/product-review/tasks.md
5└── [implementation files]

When this branch merges to main, the spec, plan, and tasks enter alongside the code — so a reviewer can trace spec → plan → tasks → implementation inside a single PR.

The takeaway: because the spec travels with the branch, the merge commit itself becomes permanent documentation, not just a code change.


12.2 Branch Naming

Consistent names make a repository with many parallel features navigable. The convention below covers the three branch types you’ll create.

bash
1feature/{ticket}-{feature-name}     # for implementation
2spec/{ticket}-{feature-name}        # spec-only branch for early review
3hotfix/{ticket}-{short-description} # for urgent fixes

The takeaway: a descriptive name like feature/SHOP-789-product-review beats feature/789 — it tells a reviewer what the branch does before they open it.


12.3 Workflow

The recommended flow splits spec review from implementation, so a PM or tech lead can approve the spec before any code exists. The commands below walk through both stages.

bash
1# Spec-only branch for early feedback
2git checkout -b spec/SHOP-789-product-review
3specify feature && specify clarify
4git push  # create a draft PR for spec review
5
6# After approval, create the implementation branch
7git checkout -b feature/SHOP-789-product-review spec/SHOP-789-product-review
8specify plan && specify tasks && specify implement
9git push  # update the PR to full implementation

The takeaway: pushing the spec branch first unlocks an early feedback loop — you get direction corrected before writing code, when it’s cheapest to change.


12.4 Parallel Features — No Conflicts

The one-feature-one-branch rule is what makes concurrent work safe. When two developers build different features at the same time, three separations keep them out of each other’s way:

  • Different branches — each feature is isolated in its own line of history.
  • Different spec folders.specify/features/product-review/ vs .specify/features/shipping-calculator/.
  • Different implementation files — which typically don’t overlap.

The takeaway: because Spec Kit scopes each feature to its own folder, the specs never collide even when two features are in flight simultaneously.


12.5 Branch Protection Rules

To enforce the strategy rather than merely recommend it, wire spec presence into branch protection. The configuration below requires a spec reference and passing checks before merge.

yaml
1main:
2  require_pull_request: true
3  required_status_checks:
4    - "Spec Compliance Check"  # CI running specify audit
5    - "Build"
6    - "Test"
7  spec_compliance:
8    - check_type: spec_link_required
9      pattern: "Spec.*: .specify/features/"

The takeaway: protection rules turn “please link a spec” into a hard merge gate, which is what prevents undocumented code from ever reaching main.


12.6 Hotfix vs Feature

Not every change deserves the full Spec Kit ceremony, and forcing it on trivial fixes just slows the team down. Use this split to decide:

Use Spec Kit (feature branch): new features, significant enhancements (more than ~2 hours of work), and any change that needs PM or business approval.

Skip Spec Kit (hotfix branch): urgent bug fixes under 30 minutes, typo and copy fixes, config updates, and security dependency bumps.

The takeaway: reserve the process for changes where a spec adds value — applying it to a one-line typo fix is pure overhead.


12.7 Squash vs Preserve Commits

How you merge determines how much task-level history survives. The two options trade traceability against a clean log:

Preserve (recommended for Spec Kit): keep all ~14 per-feature commits, each traceable back to a task in tasks.md.

Squash: collapse to one commit per feature — a cleaner git log, but you lose the task-level granularity.

The takeaway: Spec Kit favors preserving commits because the per-task history is exactly the audit trail SDD exists to create; squash only if your team values a terse log more.


12.8 Monorepo Support

In a monorepo with several services, a shared constitution plus per-service config keeps everyone aligned without central bottlenecks. The layout below shows the split.

text
1santekno-shop/
2├── .specify/constitution.md            ← shared
3├── order-service/.speckit-config.yaml  ← service-specific
4├── product-service/.speckit-config.yaml
5└── notification-service/.speckit-config.yaml

You run specify feature from each service directory, pointing at the shared constitution for context so every service inherits the same principles.

The takeaway: one constitution, many service configs — each team stays autonomous while the whole monorepo shares a single source of architectural truth.


12.9 CI Enforcement

Beyond branch protection, a lightweight CI step can assert that every feature branch actually carries its spec file. The check below fails the build if the spec is missing.

yaml
1- name: Check for spec file in feature branch PR
2  run: |
3    if [[ "$BRANCH" == feature/* ]]; then
4      FEATURE=$(echo "$BRANCH" | sed 's/feature\/[A-Z0-9-]*-//')
5      [ ! -f ".specify/features/$FEATURE/spec.md" ] && exit 1
6    fi

The takeaway: this check closes the last gap — code can’t slip onto a feature branch and into a PR without the spec that justifies it.


12.10 Tips & Gotchas

A handful of habits keep the branching strategy healthy over months of parallel work:

💡 Tip 1: Create the branch first, then run specify feature — the spec is immediately associated with the correct branch.

💡 Tip 2: Push the spec branch for early feedback — no need to wait for implementation.

💡 Tip 3: Use descriptive branch names — feature/SHOP-789-product-review beats feature/789.

💡 Tip 4: Archive the branch after merge, but don’t delete the spec — .specify/features/product-review/ in main becomes permanent documentation.

⚠️ Gotcha 1: Specs in old branches can go stale — rebase with main and update the spec if needed.

⚠️ Gotcha 2: Constitution conflicts require careful manual resolution — coordinate before updating.

⚠️ Gotcha 3: auto_create_branch: true can produce orphan branches — verify intent before running specify feature.


12.11 Summary

“One feature, one branch, one spec” isn’t just Git hygiene — it’s how the SDD workflow stays tied to clear, auditable units of work.

Feature branch = a unit of work with linked spec, plan, tasks, and implementation.

Spec branch = an early feedback mechanism before implementation starts.

CI enforcement = the guarantee that every PR to main carries a spec reference.

With branches and specs now firmly linked, the next step is automating the Git plumbing itself — the commits and pull requests. Next, we look at how Spec Kit generates clean commit history and comprehensive PR descriptions automatically.

Related Articles

💬 Comments