* feat(git-extension): add configurable Conventional Commit support Adds a commit_style option (fixed | conventional) to the git extension's auto-commit config. When set to conventional, the speckit.git.commit hook instructs the agent to generate a Conventional Commit message from the diff and pass it to auto-commit.sh / auto-commit.ps1 as an explicit argument. If no message is supplied in conventional mode, the scripts fail loudly (stderr + exit 1) instead of silently falling back to the fixed message, but still short-circuit cleanly when there are no changes to commit. - extensions/git/config-template.yml, git-config.yml: new commit_style: fixed (default) / conventional option. - extensions/git/scripts/bash/auto-commit.sh: optional [generated_message] arg, commit_style parsing, conventional-mode enforcement. - extensions/git/scripts/powershell/auto-commit.ps1: mirrored PowerShell implementation. - extensions/git/commands/speckit.git.commit.md: documents commit message styles and updated execution/config guidance. - extensions/git/README.md: documents the new option. - tests/extensions/git/test_git_extension.py: regression tests for fixed default, conventional success, conventional missing-message failure, and no-changes short-circuit (bash + PowerShell). Fixes #3390 Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(tests): check combined stdout+stderr for conventional commit_style failure test Write-Warning output stream placement is not deterministic across pwsh versions/platforms (observed failing on macOS CI). Match the existing pattern used elsewhere in this file (e.g. test_not_a_repo_still_detected_with_autocrlf) by asserting against the combined stdout+stderr instead of stderr alone. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) * fix(git-extension): strip YAML inline comments from commit_style value Copilot review feedback on PR #3413 identified that commit_style parsing didn't strip trailing YAML inline comments (e.g. "commit_style: conventional # team standard"), causing the value to retain a trailing comment fragment and silently skip conventional-mode enforcement. - bash: fix the inline-comment strip regex to use a proper {1,} interval so multiple spaces before '#' are consumed together with the comment, preventing a stray trailing quote character from surviving quote-strip when the value is quoted (e.g. commit_style: "conventional" # x). - powershell: already handled this correctly via \s+#.*$ + Trim(); no behavior change needed there. - tests: add regression coverage for commit_style values with trailing inline comments (bash + pwsh), and a pwsh regression test for the no-changes short-circuit ordering, per additional Copilot suggestion. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) * fix(git-extension): validate commit_style and reword abort message per review Address Copilot review feedback on PR #3413: - Validate commit_style against the documented fixed/conventional values; an unrecognized value now warns and falls back to fixed instead of silently mis-parsing. - Reword the conventional-mode-without-generated-message message from 'skipped auto-commit' to 'aborting auto-commit' since the script exits 1 (a failure, not a skip), and include the actionable remediation. - Add regression tests (bash + pwsh) covering the unknown commit_style fallback. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(git-extension): limit commit_style parsing to first match in config Address Copilot review feedback on PR #3413: grep '^commit_style:' without -m1 could concatenate values if a config file accidentally contains multiple commit_style lines (e.g. from a bad merge/manual edit), causing an unexpected fallback to 'fixed'. Limit to the first match and add a regression test covering duplicate commit_style lines. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(git-extension): avoid shell interpolation of generated commit messages - Remove r -d '[:space:]' from commit_style parsing in auto-commit.sh: it stripped ALL whitespace (not just leading/trailing), so commit_style: con ventional was silently normalized to conventional instead of being rejected as unknown (PowerShell version already rejected it correctly). - Add a file-based message-passing channel to both auto-commit scripts: --message-file <path> (bash) / -MessageFile <path> (PowerShell). Agent-generated commit messages may contain quotes, $(...), or backticks; passing them as a shell argument risked command injection if ever inlined into a shell command string. The new flag reads the message from a file instead, so untrusted content never touches a shell command line. The raw positional-argument form is kept for backward compatibility. - Update speckit.git.commit.md to instruct the agent to write the generated message to a temp file (via its file-editing tool) and pass the file path, explicitly warning against inlining the message into a shell command string. - Add test coverage: explicit commit_style: fixed (previously only the absent-key default was tested), --message-file/-MessageFile success path (including injection-shaped content), and missing-file error path, for both bash and PowerShell suites. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * fix(git-extension): exclude --message-file transport file from staging The temp file passed via --message-file / -MessageFile was read but left in the worktree. If written inside the project (as an agent's file-editing tool would naturally do), git add . staged it into the commit, and its mere presence as an untracked file could also defeat the no-changes short-circuit, causing a spurious commit containing only that file. Remove the file immediately after its content is captured, before the change-detection check and before staging. Add bash + pwsh regression tests covering both scenarios. Assisted-by: GitHub Copilot (model: claude-sonnet-5, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
5.7 KiB
Git Branching Workflow Extension
Git repository initialization, feature branch creation, numbering (sequential/timestamp), validation, remote detection, and auto-commit for Spec Kit.
Overview
This extension provides Git operations as an optional, self-contained module. It manages:
- Repository initialization with configurable commit messages
- Feature branch creation with sequential (
001-feature-name) or timestamp (20260319-143022-feature-name) numbering and optional templates for branch namespaces - Branch validation to ensure branches follow naming conventions
- Git remote detection for GitHub integration (e.g., issue creation)
- Auto-commit after core commands (configurable per-command with custom messages, or Conventional Commit messages generated by the agent)
Commands
| Command | Description |
|---|---|
speckit.git.initialize |
Initialize a Git repository with a configurable commit message |
speckit.git.feature |
Create a feature branch with sequential or timestamp numbering |
speckit.git.validate |
Validate current branch follows feature branch naming conventions |
speckit.git.remote |
Detect Git remote URL for GitHub integration |
speckit.git.commit |
Auto-commit changes (configurable per-command enable/disable and messages) |
Hooks
| Event | Command | Optional | Description |
|---|---|---|---|
before_constitution |
speckit.git.initialize |
No | Init git repo before constitution |
before_specify |
speckit.git.feature |
No | Create feature branch before specification |
before_clarify |
speckit.git.commit |
Yes | Commit outstanding changes before clarification |
before_plan |
speckit.git.commit |
Yes | Commit outstanding changes before planning |
before_tasks |
speckit.git.commit |
Yes | Commit outstanding changes before task generation |
before_implement |
speckit.git.commit |
Yes | Commit outstanding changes before implementation |
before_checklist |
speckit.git.commit |
Yes | Commit outstanding changes before checklist |
before_analyze |
speckit.git.commit |
Yes | Commit outstanding changes before analysis |
before_taskstoissues |
speckit.git.commit |
Yes | Commit outstanding changes before issue sync |
after_constitution |
speckit.git.commit |
Yes | Auto-commit after constitution update |
after_specify |
speckit.git.commit |
Yes | Auto-commit after specification |
after_clarify |
speckit.git.commit |
Yes | Auto-commit after clarification |
after_plan |
speckit.git.commit |
Yes | Auto-commit after planning |
after_tasks |
speckit.git.commit |
Yes | Auto-commit after task generation |
after_implement |
speckit.git.commit |
Yes | Auto-commit after implementation |
after_checklist |
speckit.git.commit |
Yes | Auto-commit after checklist |
after_analyze |
speckit.git.commit |
Yes | Auto-commit after analysis |
after_taskstoissues |
speckit.git.commit |
Yes | Auto-commit after issue sync |
Configuration
Configuration is stored in .specify/extensions/git/git-config.yml:
# Branch numbering strategy: "sequential" or "timestamp"
branch_numbering: sequential
# Optional branch name template. Leave empty for the default "{number}-{slug}".
# Supported tokens: {author}, {app}, {number}, {slug}; {slug} must not appear
# before {number}, and the final path segment must start with {number}-.
# Example for monorepos: "{author}/{app}/{number}-{slug}"
branch_template: ""
# Optional shorthand namespace. Leave empty to use branch_template/default behavior.
# Example: "features/{app}" expands to "features/{app}/{number}-{slug}"
branch_prefix: ""
# Custom commit message for git init
init_commit_message: "[Spec Kit] Initial commit"
# Commit message style for auto-commit hooks: "fixed" (default) uses the
# messages below; "conventional" asks the agent to generate a Conventional
# Commit message (e.g. "feat: add OAuth spec") from the diff instead.
commit_style: fixed
# Auto-commit per command (all disabled by default)
# Example: enable auto-commit after specify
auto_commit:
default: false
after_specify:
enabled: true
message: "[Spec Kit] Add specification"
{author} is derived from Git config and sanitized for branch names. {app} is derived from the Spec Kit init directory name. Custom templates must not put {slug} before {number}, and must put {number}- at the start of the final path segment so generated names remain valid feature branches. For a monorepo project at apps/web/.specify/, a template such as {author}/{app}/{number}-{slug} produces branches like jdoe/web/008-guided-tour.
For simple namespace-only customization, branch_prefix is also accepted as a shorthand and expands to <branch_prefix>/{number}-{slug}.
Installation
# Install the bundled git extension (no network required)
specify extension add git
Disabling
# Disable the git extension (spec creation continues without branching)
specify extension disable git
# Re-enable it
specify extension enable git
Graceful Degradation
When Git is not installed or the directory is not a Git repository:
- Spec directories are still created under
specs/ - Branch creation is skipped with a warning
- Branch validation is skipped with a warning
- Remote detection returns empty results
Scripts
The extension bundles cross-platform scripts:
scripts/bash/create-new-feature-branch.sh— Bash implementation (branch creation only)scripts/bash/git-common.sh— Shared Git utilities (Bash)scripts/powershell/create-new-feature-branch.ps1— PowerShell implementation (branch creation only)scripts/powershell/git-common.ps1— Shared Git utilities (PowerShell)