Skip to content

feat: Git extension stage 2 — GIT_BRANCH_NAME override, --force for existing dirs, auto-install tests (#1940)#2117

Merged
mnriem merged 14 commits intogithub:mainfrom
mnriem:git-extension-stage2
Apr 8, 2026
Merged

feat: Git extension stage 2 — GIT_BRANCH_NAME override, --force for existing dirs, auto-install tests (#1940)#2117
mnriem merged 14 commits intogithub:mainfrom
mnriem:git-extension-stage2

Conversation

@mnriem
Copy link
Copy Markdown
Collaborator

@mnriem mnriem commented Apr 7, 2026

Summary

Stage 2 of the git extension extraction (#1940). Adds GIT_BRANCH_NAME environment variable override for exact branch naming, fixes --force flag for specify init into existing directories, and adds test coverage for git extension auto-install and feature directory resolution.

Follows stage 1 (#1941) which created the bundled extensions/git with hooks on all core commands.

Changes

GIT_BRANCH_NAME environment variable override

When GIT_BRANCH_NAME is set, create-new-feature.sh and .ps1 use the exact value as the branch name, bypassing all prefix/suffix generation. This parallels SPECIFY_FEATURE_DIRECTORY for spec directories.

  • extensions/git/scripts/bash/create-new-feature.sh
  • extensions/git/scripts/powershell/create-new-feature.ps1
  • extensions/git/commands/speckit.git.feature.md — documented override
  • templates/commands/specify.md — documented passthrough to hook

--force flag for existing directories

specify init <dir> --force now merges into an existing directory instead of erroring. Previously --force only worked with --here.

  • src/specify_cli/__init__.py

New tests

  • tests/integrations/test_cli.pyTestGitExtensionAutoInstall (3 tests: auto-install, --no-git skip, commands registered)
  • tests/test_timestamp_branches.pyTestFeatureDirectoryResolution (4 tests: env var override, feature.json, priority, branch fallback)

Pre-existing changes (from branch)

  • scripts/bash/common.sh, scripts/powershell/common.ps1 — feature directory resolution
  • tests/extensions/git/test_git_extension.py — test cleanup

Test Results

1,195 passed, 0 failed (43s)

All existing tests pass unchanged. No regressions.

…xisting dirs, auto-install tests (github#1940)

- Add GIT_BRANCH_NAME env var override to create-new-feature.sh/.ps1
  for exact branch naming (bypasses all prefix/suffix generation)
- Fix --force flag for 'specify init <dir>' into existing directories
- Add TestGitExtensionAutoInstall tests (auto-install, --no-git skip,
  commands registered)
- Add TestFeatureDirectoryResolution tests (env var, feature.json,
  priority, branch fallback)
- Document GIT_BRANCH_NAME in speckit.git.feature.md and specify.md
Copilot AI review requested due to automatic review settings April 7, 2026 18:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git extension extraction: moves git branching responsibilities further into the bundled extensions/git extension by (1) auto-installing it during specify init (unless --no-git), (2) adding GIT_BRANCH_NAME as an exact branch-name override for the branch-creation scripts, and (3) updating feature-directory resolution to prefer SPECIFY_FEATURE_DIRECTORY / .specify/feature.json over branch-based lookup, with accompanying docs and tests.

Changes:

  • Auto-install bundled git extension during specify init, and allow --force to merge into an existing target directory.
  • Add GIT_BRANCH_NAME override to git extension create-new-feature scripts (bash + PowerShell) and update command/template docs accordingly.
  • Add/adjust tests for git extension auto-install and feature directory resolution precedence.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior for existing dirs and installs bundled git extension during init.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override and removes spec-dir/spec-file creation from branch script.
extensions/git/scripts/powershell/create-new-feature.ps1 Same as bash: GIT_BRANCH_NAME override + branch-only behavior.
scripts/bash/common.sh Updates get_feature_paths to prioritize SPECIFY_FEATURE_DIRECTORY and .specify/feature.json.
scripts/powershell/common.ps1 Similar feature-dir resolution changes for PowerShell helper.
extensions/git/commands/speckit.git.feature.md Documents branch-only responsibility + GIT_BRANCH_NAME behavior/output.
templates/commands/specify.md Updates core /speckit.specify instructions to decouple spec-dir creation from git hook branch creation.
tests/integrations/test_cli.py Adds CLI-level tests for git extension auto-install/skip/registration.
tests/test_timestamp_branches.py Adds feature directory resolution precedence tests (env var, feature.json, branch fallback).
tests/extensions/git/test_git_extension.py Updates expectations to reflect branch-only script output (no SPEC_FILE).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

extensions/git/scripts/bash/create-new-feature.sh:312

  • The GIT_BRANCH_NAME override extracts FEATURE_NUM by checking ^[0-9]+- before the timestamp pattern. Timestamp-style names (e.g. 20260319-143022-foo) will match the first check and incorrectly set FEATURE_NUM to just 20260319 instead of 20260319-143022. Swap the order (timestamp check first) or make the sequential regex exclude the timestamp form.
    if echo "$BRANCH_NAME" | grep -Eq '^[0-9]+-'; then
        FEATURE_NUM=$(echo "$BRANCH_NAME" | grep -Eo '^[0-9]+')
    elif echo "$BRANCH_NAME" | grep -Eq '^[0-9]{8}-[0-9]{6}-'; then
        FEATURE_NUM=$(echo "$BRANCH_NAME" | grep -Eo '^[0-9]{8}-[0-9]{6}')

extensions/git/scripts/powershell/create-new-feature.ps1:266

  • In the GIT_BRANCH_NAME override path, the timestamp prefix extraction (^(\d{8}-\d{6})-) is unreachable because the prior ^(\d+)- regex matches timestamps first. This causes FEATURE_NUM to be truncated to the date-only portion for timestamp branch names. Check the timestamp pattern first, or refine the sequential pattern so it won’t match timestamps.
    if ($branchName -match '^(\d+)-') {
        $featureNum = $matches[1]
    } elseif ($branchName -match '^(\d{8}-\d{6})-') {
        $featureNum = $matches[1]
  • Files reviewed: 10/10 changed files
  • Comments generated: 8

mnriem added 2 commits April 7, 2026 13:35
- Fix timestamp regex ordering: check YYYYMMDD-HHMMSS before generic
  numeric prefix in both bash and PowerShell
- Set BRANCH_SUFFIX in GIT_BRANCH_NAME override path so 244-byte
  truncation logic works correctly
- Add 244-byte length check for GIT_BRANCH_NAME in PowerShell
- Use existing_items for non-empty dir warning with --force
- Skip git extension install if already installed (idempotent --force)
- Wrap PowerShell feature.json parsing in try/catch for malformed JSON
- Fix PS comment: 'prefix lookup' -> 'exact mapping via Get-FeatureDir'
- Remove non-functional SPECIFY_SPEC_DIRECTORY from specify.md template
Copilot AI review requested due to automatic review settings April 7, 2026 18:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the Git extension extraction: shifts branch creation fully into the bundled git extension (with new GIT_BRANCH_NAME override), fixes specify init <dir> --force to merge into existing directories, and expands test coverage around git extension auto-install and feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME override to git extension branch creation scripts + documentation updates.
  • Update specify init to allow --force merges into existing target directories and to auto-install the bundled git extension.
  • Add tests for git extension auto-install and for feature directory resolution priority (env var, feature.json, branch fallback).
Show a summary per file
File Description
src/specify_cli/__init__.py Enables --force merge into existing dirs and installs bundled git extension during init.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override; removes spec dir/file creation; adjusts JSON output.
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME override; removes spec dir/file creation; adjusts JSON output.
extensions/git/commands/speckit.git.feature.md Updates command docs for override behavior + branch-only responsibility.
scripts/bash/common.sh Resolves feature directory via env var / .specify/feature.json / branch fallback.
scripts/powershell/common.ps1 Same feature directory resolution priority as bash.
templates/commands/specify.md Updates /speckit.specify workflow to rely on hooks for branching and persist feature dir in .specify/feature.json.
tests/integrations/test_cli.py Adds TestGitExtensionAutoInstall verifying bundled git extension install/skip and command registration.
tests/test_timestamp_branches.py Adds TestFeatureDirectoryResolution covering env var / feature.json / fallback behavior.
tests/extensions/git/test_git_extension.py Updates tests to reflect branch-only outputs (no SPEC_FILE), removes spec-dir creation assertions.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 3

- Guard shutil.rmtree on init failure: skip cleanup when --force merged
  into a pre-existing directory (prevents data loss)
- Bash: error on GIT_BRANCH_NAME >244 bytes instead of broken truncation
- Fix malformed numbered list in specify.md (restore missing step 1)
- Add claude_skills.exists() assert before iterdir() in test
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git extension extraction work: shifts branch creation fully into the bundled extensions/git hook, adds an exact-branch-name override via GIT_BRANCH_NAME, fixes specify init <dir> --force to merge into existing directories, and expands automated test coverage around extension auto-install and feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME override support to git extension branch-creation scripts (bash + PowerShell) and document it in extension/core command templates.
  • Update specify init to allow --force merges into existing target directories and to auto-install the bundled git extension (unless --no-git).
  • Add/adjust tests for git extension auto-install + command registration and for SPECIFY_FEATURE_DIRECTORY / .specify/feature.json feature directory resolution.
Show a summary per file
File Description
extensions/git/scripts/bash/create-new-feature.sh Add GIT_BRANCH_NAME exact override; stop creating spec dirs/files; JSON output now focuses on branch metadata.
extensions/git/scripts/powershell/create-new-feature.ps1 Same as bash: GIT_BRANCH_NAME override + branch-only behavior + updated JSON output.
extensions/git/commands/speckit.git.feature.md Document the override and clarify that this command is branch-only and outputs BRANCH_NAME/FEATURE_NUM.
scripts/bash/common.sh Resolve feature directory via env var → .specify/feature.json → branch-prefix fallback.
scripts/powershell/common.ps1 Resolve feature directory via env var → .specify/feature.json → branch fallback.
templates/commands/specify.md Remove direct branching scripts; update workflow to treat branch creation as optional hook and move spec-dir creation into core flow.
src/specify_cli/__init__.py Fix --force behavior for existing dirs and switch “git step” from repo-init to bundled git extension install.
tests/integrations/test_cli.py Add integration-level tests validating git extension auto-install, opt-out (--no-git), and command registration.
tests/test_timestamp_branches.py Add tests for feature directory resolution precedence (env var, feature.json, branch fallback).
tests/extensions/git/test_git_extension.py Update expectations to match branch-only outputs (no SPEC_FILE creation from git scripts).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 2

- Bash: use LC_ALL=C wc -c for byte length instead of ${#VAR}
- PowerShell: use [System.Text.Encoding]::UTF8.GetByteCount() instead
  of .Length (UTF-16 code units)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of extracting git/branching behavior into the bundled extensions/git extension by adding an exact-branch-name override (GIT_BRANCH_NAME), fixing specify init <dir> --force to merge into existing directories, and expanding test coverage around git extension auto-install and feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME env var override support to extension branch-creation scripts (Bash + PowerShell) and document it.
  • Update specify init to auto-install the bundled git extension by default, and allow --force merges into existing non---here directories.
  • Add tests for git extension auto-install/registration and for feature directory resolution via SPECIFY_FEATURE_DIRECTORY and .specify/feature.json.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior for existing dirs and auto-installs bundled git extension (unless --no-git).
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override handling and adjusts JSON output to branch-only fields.
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME override handling and adjusts JSON output to branch-only fields.
extensions/git/commands/speckit.git.feature.md Documents branch-only responsibility + GIT_BRANCH_NAME override semantics.
templates/commands/specify.md Removes direct branch script invocation and documents hook-based branch creation + persisted feature dir.
scripts/bash/common.sh Adds feature directory resolution priority: env var → feature.json → branch lookup.
scripts/powershell/common.ps1 Mirrors feature directory resolution priority logic for PowerShell.
tests/integrations/test_cli.py Adds CLI-level tests validating git extension auto-install/skip/registration during init.
tests/test_timestamp_branches.py Adds tests for feature directory resolution precedence (bash common.sh).
tests/extensions/git/test_git_extension.py Updates extension tests to reflect branch-only output/behavior.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 5

- Update --dry-run help text in bash and PowerShell (branch name only)
- Fix specify.md JSON example: use concrete path, not literal variable
- Add TestForceExistingDirectory tests (merge + error without --force)
- Add PowerShell Get-FeaturePathsEnv tests (env var + feature.json)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the Git extension extraction: updates init behavior to auto-install the bundled git extension (opt-out), adds a GIT_BRANCH_NAME override for exact branch naming in extension scripts, and introduces feature-directory resolution via SPECIFY_FEATURE_DIRECTORY / .specify/feature.json with new tests.

Changes:

  • Add GIT_BRANCH_NAME env var override to git extension branch-creation scripts and document it.
  • Fix specify init <dir> --force to merge into existing directories (not only --here) and auto-install the bundled git extension during init.
  • Add/adjust tests for extension auto-install and feature-directory resolution; update git extension tests for new script output (no SPEC_FILE).
Show a summary per file
File Description
src/specify_cli/__init__.py Enables --force merge into existing dirs; installs bundled git extension during init; adjusts cleanup logic.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override; removes spec-dir/spec-file creation; updates JSON output fields.
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME override; removes spec-dir/spec-file creation; updates JSON output fields.
extensions/git/commands/speckit.git.feature.md Documents override and updated behavior/output for git feature command.
templates/commands/specify.md Removes direct branch-creation scripts; updates workflow instructions (hooks + feature dir persistence).
scripts/bash/common.sh Adds feature directory resolution priority: env var → feature.json → branch prefix mapping.
scripts/powershell/common.ps1 Adds feature directory resolution priority: env var → feature.json → branch mapping.
tests/integrations/test_cli.py Adds tests for --force merge behavior and git extension auto-install during init.
tests/test_timestamp_branches.py Adds tests for feature directory resolution (env var, feature.json, fallback) across bash/PowerShell.
tests/extensions/git/test_git_extension.py Updates tests to match new branch script outputs (no spec file creation).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (1)

scripts/bash/common.sh:212

  • The no-jq fallback parses feature.json with grep -o ... | sed ..., which only matches when "feature_directory": "..." appears on a single line. The updated specify.md instructions show a multi-line JSON example, and agents commonly pretty-print JSON—this will make _fd empty and silently fall back to branch lookup. Consider making the fallback newline-tolerant (e.g., strip newlines before grepping) or using a small Python json parse as a fallback.
    elif [[ -f "$repo_root/.specify/feature.json" ]]; then
        local _fd
        if command -v jq >/dev/null 2>&1; then
            _fd=$(jq -r '.feature_directory // empty' "$repo_root/.specify/feature.json" 2>/dev/null)
        else
            # Minimal fallback: extract value with grep/sed when jq is unavailable
            _fd=$(grep -o '"feature_directory"[[:space:]]*:[[:space:]]*"[^"]*"' "$repo_root/.specify/feature.json" 2>/dev/null | sed 's/.*"\([^"]*\)"$/\1/')
        fi
        if [[ -n "$_fd" ]]; then
  • Files reviewed: 10/10 changed files
  • Comments generated: 3

- Bash common.sh: normalize SPECIFY_FEATURE_DIRECTORY and feature.json
  relative paths to absolute under repo root
- PowerShell common.ps1: same normalization using IsPathRooted + Join-Path
- PowerShell create-new-feature.ps1: call Test-HasGit without -RepoRoot
  for compatibility with core common.ps1 (no param) and git-common.ps1
  (optional param with default)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git-extension extraction: updates the CLI to auto-install the bundled git extension during specify init, adds feature directory resolution precedence (SPECIFY_FEATURE_DIRECTORY.specify/feature.json → branch fallback) across bash/PowerShell common scripts, and introduces an exact-branch-name override via GIT_BRANCH_NAME in the git extension’s branch-creation scripts/docs.

Changes:

  • Add --force support for specify init <dir> when the target directory already exists (merge instead of error).
  • Auto-install the bundled git extension during specify init (unless --no-git) and update tests to validate install + hook/command registration.
  • Implement feature directory resolution via SPECIFY_FEATURE_DIRECTORY / .specify/feature.json and update templates/docs to decouple spec dir creation from git branch creation; add resolution tests.
Show a summary per file
File Description
src/specify_cli/__init__.py Allow --force merges into existing dirs; replace init-time git repo initialization with bundled git extension install.
tests/integrations/test_cli.py Add CLI tests for --force existing-dir merge and git extension auto-install/registration.
scripts/bash/common.sh Resolve feature directory via env var / .specify/feature.json before branch-based lookup.
scripts/powershell/common.ps1 PowerShell equivalent feature directory resolution precedence.
tests/test_timestamp_branches.py Add cross-shell tests for feature directory resolution precedence and fallbacks.
extensions/git/scripts/bash/create-new-feature.sh Add GIT_BRANCH_NAME exact override; adjust output to be branch-only (no spec file/dir creation).
extensions/git/scripts/powershell/create-new-feature.ps1 Add GIT_BRANCH_NAME exact override; align behavior/output with branch-only responsibility.
extensions/git/commands/speckit.git.feature.md Document override + clarify command handles branch creation only.
templates/commands/specify.md Remove direct branch-creation scripts; document hook-driven branch creation + core-owned spec dir/file creation + feature.json persistence.
tests/extensions/git/test_git_extension.py Update expectations to match “branch-only” behavior (no SPEC_FILE creation by git extension feature script).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 2

…thub#2117)

- TestGitBranchNameOverrideBash: 5 tests (exact name, sequential prefix,
  timestamp prefix, overlong rejection, dry-run)
- TestGitBranchNameOverridePowerShell: 4 tests (exact name, sequential
  prefix, timestamp prefix, overlong rejection)
- Tests use extension scripts (not core) via new ext_git_repo and
  ext_ps_git_repo fixtures
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git-extension extraction: shifts git branching responsibilities further into the bundled extensions/git workflow, adds an exact branch-name override (GIT_BRANCH_NAME), improves specify init behavior for --force into existing directories, and expands test coverage around extension auto-install and feature-directory resolution.

Changes:

  • Add GIT_BRANCH_NAME override support in git extension branch-creation scripts (bash + PowerShell) and document it.
  • Update specify init to support --force when initializing into an existing named directory, and add tests for this and git extension auto-install.
  • Update feature-directory resolution to prefer SPECIFY_FEATURE_DIRECTORY, then .specify/feature.json, then branch-based fallback; update /speckit.specify template accordingly and adjust tests.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge into existing dirs; changes “git” init step to install bundled git extension during init.
templates/commands/specify.md Removes direct branch-creation script invocation; documents hook-based branching + feature dir persistence to .specify/feature.json.
scripts/bash/common.sh Adds feature directory resolution via SPECIFY_FEATURE_DIRECTORY and .specify/feature.json before branch-prefix lookup.
scripts/powershell/common.ps1 Mirrors feature directory resolution priority logic for PowerShell.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override and aligns output to be branch-only (no spec file creation).
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME override; removes spec dir/file creation and outputs branch-only JSON.
extensions/git/commands/speckit.git.feature.md Updates command docs to reflect override behavior and branch-only output.
tests/integrations/test_cli.py Adds CLI-level tests for --force into existing dirs and git extension auto-install / registration.
tests/test_timestamp_branches.py Adds fixtures + tests for GIT_BRANCH_NAME override and feature-directory resolution order.
tests/extensions/git/test_git_extension.py Updates expectations to match branch-only output / behavior (no SPEC_FILE).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 3

- Restore is_git_repo() and init_git_repo() functions removed in stage 2
- specify init now runs git init AND installs git extension (not just
  extension install alone)
- Add is_dir() guard for non-here path to prevent uncontrolled error
  when target exists but is a file
- Add python3 JSON fallback in common.sh for multi-line feature.json
  (grep pipeline fails on pretty-printed JSON without jq)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git-extension extraction: adds an exact GIT_BRANCH_NAME override for the git extension’s branch-creation scripts, fixes specify init <dir> --force to merge into existing directories, and expands test coverage around git extension auto-install and feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME override to extension create-new-feature scripts (bash + PowerShell) and document the behavior.
  • Update specify init to support --force when targeting an existing (named) directory, and auto-install the bundled git extension during init (unless --no-git).
  • Extend tests for git extension auto-install, GIT_BRANCH_NAME, and feature directory resolution via SPECIFY_FEATURE_DIRECTORY / .specify/feature.json.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior for existing dirs and auto-installs bundled git extension during init.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME exact-branch override; outputs branch-only JSON (no spec file creation).
extensions/git/scripts/powershell/create-new-feature.ps1 PowerShell parity for GIT_BRANCH_NAME override; removes spec dir/file creation and output.
extensions/git/commands/speckit.git.feature.md Updates extension command docs to reflect branch-only behavior and the override env var.
templates/commands/specify.md Removes direct branch-creation scripts from core /speckit.specify; documents hook-based branching and feature dir persistence.
scripts/bash/common.sh Enhances feature directory resolution priority: env var → .specify/feature.json → branch-based fallback.
scripts/powershell/common.ps1 Mirrors feature directory resolution priority logic for PowerShell.
tests/integrations/test_cli.py Adds CLI tests for --force on existing dirs and git extension auto-install/registration.
tests/test_timestamp_branches.py Adds tests for GIT_BRANCH_NAME override (bash + PS) and feature directory resolution behavior.
tests/extensions/git/test_git_extension.py Updates expectations for branch script output (no SPEC_FILE) and adjusts no-git behavior assertions.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 1

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the bundled extensions/git migration: adds an explicit GIT_BRANCH_NAME override for exact branch naming, fixes specify init <dir> --force to merge into existing directories, and expands test coverage around git extension auto-install and feature-directory resolution via SPECIFY_FEATURE_DIRECTORY / .specify/feature.json.

Changes:

  • Add GIT_BRANCH_NAME override support in git extension branch-creation scripts (Bash + PowerShell) and document it.
  • Update specify init to allow --force merges into an existing target directory and auto-install the bundled git extension by default (opt-out via --no-git).
  • Add/adjust tests for git extension auto-install, branch-name override behavior, and feature directory resolution priority.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior for existing dirs and installs bundled git extension during init.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME exact-branch override + adjusts JSON output to branch-only fields.
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME exact-branch override + aligns behavior/output with Bash.
extensions/git/commands/speckit.git.feature.md Documents override semantics and updated script output contract.
scripts/bash/common.sh Resolves feature directory via SPECIFY_FEATURE_DIRECTORY.specify/feature.json → branch lookup fallback.
scripts/powershell/common.ps1 Mirrors feature directory resolution priority for PowerShell workflows.
templates/commands/specify.md Moves spec dir/file creation responsibility to core workflow; treats git branch creation as hook-driven.
tests/integrations/test_cli.py Adds coverage for --force merging and git extension auto-install/registration.
tests/test_timestamp_branches.py Adds tests for GIT_BRANCH_NAME override and feature-directory resolution priority.
tests/extensions/git/test_git_extension.py Updates expectations to reflect “branch-only” behavior (no spec file creation in git extension).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 1

…ub#2117)

Extension .sh scripts (e.g. create-new-feature.sh, initialize-repo.sh)
may lack execute bits after install. Scan both .specify/scripts/ and
.specify/extensions/ for permission fixing.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git-extension extraction: adds an exact branch-name override (GIT_BRANCH_NAME), fixes specify init <dir> --force behavior for existing directories, and expands tests around auto-install + feature directory resolution (SPECIFY_FEATURE_DIRECTORY / .specify/feature.json).

Changes:

  • Add GIT_BRANCH_NAME override support to the git extension’s branch creation scripts (Bash + PowerShell) and update related docs/templates.
  • Allow specify init <dir> --force to merge into an existing directory (instead of erroring), with new integration tests.
  • Add feature directory resolution logic to core common.sh / common.ps1 (env var → feature.json → branch fallback) with new tests.
Show a summary per file
File Description
src/specify_cli/__init__.py Implement --force merge into existing dirs; auto-install bundled git extension during init; expand chmod scanning to extensions.
extensions/git/scripts/bash/create-new-feature.sh Add GIT_BRANCH_NAME override + byte-length validation; stop creating spec dirs/files; adjust JSON output.
extensions/git/scripts/powershell/create-new-feature.ps1 Add GIT_BRANCH_NAME override + UTF-8 byte-length validation; stop creating spec dirs/files; adjust JSON output.
extensions/git/commands/speckit.git.feature.md Document override behavior and updated outputs (branch-only).
templates/commands/specify.md Remove direct branch-creation scripts; document hook-based branching + feature dir persistence to .specify/feature.json.
scripts/bash/common.sh Resolve feature directory via env var / feature.json before branch-based lookup.
scripts/powershell/common.ps1 Same feature directory resolution precedence as Bash.
tests/integrations/test_cli.py Add tests for --force into existing dir and git extension auto-install (and --no-git skip).
tests/test_timestamp_branches.py Add tests for GIT_BRANCH_NAME override (Bash + pwsh) and feature directory resolution order.
tests/extensions/git/test_git_extension.py Update expectations now that extension branch scripts no longer create spec files/dirs.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 2

…2117)

- ensure_executable_scripts() now runs after git extension install so
  extension .sh files get execute bits in the same init run
- Sanitize init_git_repo error_msg to single line (replace newlines,
  truncate to 120 chars) to prevent garbled StepTracker output
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git-extension extraction effort: adds an exact-branch override (GIT_BRANCH_NAME) for the git extension’s branch-creation scripts, fixes specify init <dir> --force to merge into existing directories, and expands test coverage for both git extension auto-install and feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME env var override to extension branch-creation scripts (bash + PowerShell) and document it.
  • Update specify init to allow --force when targeting an existing directory and to auto-install the bundled git extension (unless --no-git).
  • Add/adjust tests for git extension auto-install and for feature directory resolution via SPECIFY_FEATURE_DIRECTORY and .specify/feature.json.
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior; adds bundled git extension auto-install during init; updates chmod scanning to include installed extensions.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override, removes spec dir/file creation responsibilities, updates JSON output to branch-only fields.
extensions/git/scripts/powershell/create-new-feature.ps1 Same as bash: GIT_BRANCH_NAME override and branch-only behavior/output.
extensions/git/commands/speckit.git.feature.md Documents override semantics and updated script output/behavior.
templates/commands/specify.md Shifts branch creation to hook-driven flow and documents persisting .specify/feature.json for feature dir discovery.
scripts/bash/common.sh Adds feature dir resolution via SPECIFY_FEATURE_DIRECTORY and .specify/feature.json before branch-based fallback.
scripts/powershell/common.ps1 Mirrors feature dir resolution priority logic in PowerShell.
tests/integrations/test_cli.py Adds tests for init --force merge behavior and git extension auto-install/registration.
tests/test_timestamp_branches.py Adds tests for GIT_BRANCH_NAME override (bash + pwsh) and for feature directory resolution priority order.
tests/extensions/git/test_git_extension.py Updates tests to reflect that extension branch scripts no longer create spec files/directories.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

src/specify_cli/init.py:1205

  • The git step is marked as complete even when init_git_repo() fails (only a string like init failed: ... is appended). This makes the step look successful in the UI despite a failure. Consider calling tracker.error("git", ...) (while still continuing init if git is optional) and/or surfacing the full error somewhere (panel/log) instead of truncating it into the success detail.
                    success, error_msg = init_git_repo(project_path, quiet=True)
                    if success:
                        git_messages.append("initialized")
                    else:
                        # Sanitize multi-line error_msg to single line for tracker
                        if error_msg:
                            sanitized = error_msg.replace('\n', ' ').strip()
                            git_messages.append(f"init failed: {sanitized[:120]}")
                        else:
                            git_messages.append("init failed")

src/specify_cli/init.py:1225

  • Extension install failures are swallowed into git_messages and the step is still completed as done. If installation fails, this should be reflected as an error/warning state (e.g., tracker.error("git", ...)), otherwise users may miss that the bundled git extension is not installed and hooks won’t run.
                    else:
                        git_messages.append("bundled extension not found")
                except Exception as ext_err:
                    git_messages.append(f"extension install failed: {ext_err}")
                tracker.complete("git", "; ".join(git_messages))
  • Files reviewed: 10/10 changed files
  • Comments generated: 4

Git init failure and extension install failure were reported as
tracker.complete (showing green) even on error. Now track a
git_has_error flag and call tracker.error when any step fails,
so the UI correctly reflects the failure state.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git extension extraction: adds an explicit GIT_BRANCH_NAME override for branch creation scripts, makes specify init <dir> --force merge into an existing directory, and expands automated tests around git extension auto-install + feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME env var override to extension branch-creation scripts (bash + PowerShell) and document the behavior.
  • Allow specify init <dir> --force to proceed when the target directory already exists (merge behavior), and auto-install the bundled git extension during init when not --no-git.
  • Add/adjust tests for git extension auto-install and for feature directory resolution priority (SPECIFY_FEATURE_DIRECTORY > .specify/feature.json > branch fallback).
Show a summary per file
File Description
src/specify_cli/__init__.py Implements --force merge behavior for named dirs; installs bundled git extension during init; chmod now includes extension scripts.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override; adjusts dry-run semantics; stops creating spec dirs/files; updates JSON output.
extensions/git/scripts/powershell/create-new-feature.ps1 Same as bash: GIT_BRANCH_NAME override + dry-run semantics; removes spec dir/file creation and SPEC_FILE output.
extensions/git/commands/speckit.git.feature.md Documents new override behavior and updated outputs (BRANCH_NAME + FEATURE_NUM).
templates/commands/specify.md Removes direct branch script invocation from the core specify template; documents hook-driven branching + feature dir persistence to .specify/feature.json.
scripts/bash/common.sh Adds .specify/feature.json support + env var override to feature dir resolution.
scripts/powershell/common.ps1 Mirrors bash: feature dir resolution priority and feature.json support.
tests/integrations/test_cli.py Adds tests for --force into existing dirs and for git extension auto-install/registration.
tests/test_timestamp_branches.py Adds tests for GIT_BRANCH_NAME override (bash + pwsh) and for feature dir resolution order.
tests/extensions/git/test_git_extension.py Updates tests to reflect branch scripts no longer creating spec files / emitting SPEC_FILE.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 1

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Stage 2 of the git extension extraction: adds an exact-branch override (GIT_BRANCH_NAME) to the git extension branch-creation scripts, fixes specify init <dir> --force to merge into existing directories, and expands automated test coverage around auto-install + feature directory resolution.

Changes:

  • Add GIT_BRANCH_NAME environment variable override support to git extension create-new-feature (bash + PowerShell) and document it.
  • Update specify init to allow --force when targeting an existing directory (not just --here) and auto-install the bundled git extension.
  • Add/adjust tests covering git extension auto-install, branch-name override, and feature directory resolution precedence.
Show a summary per file
File Description
src/specify_cli/__init__.py Enables --force merge into existing dirs; installs bundled git extension during init; expands chmod scan roots.
extensions/git/scripts/bash/create-new-feature.sh Adds GIT_BRANCH_NAME override and adjusts JSON output to branch-only fields.
extensions/git/scripts/powershell/create-new-feature.ps1 Adds GIT_BRANCH_NAME override and adjusts behavior/output to branch-only fields.
scripts/bash/common.sh Feature dir resolution now prioritizes SPECIFY_FEATURE_DIRECTORY, then .specify/feature.json, then branch-based lookup.
scripts/powershell/common.ps1 Mirrors feature dir resolution precedence (env var > feature.json > branch fallback).
templates/commands/specify.md Updates specify workflow to rely on before_specify hook for branching; documents feature dir persistence and overrides.
extensions/git/commands/speckit.git.feature.md Documents override behavior and clarifies output fields (BRANCH_NAME, FEATURE_NUM).
tests/integrations/test_cli.py Adds CLI tests for --force on existing dirs and git extension auto-install during init.
tests/test_timestamp_branches.py Adds override tests for extension scripts + feature directory resolution tests (bash + pwsh).
tests/extensions/git/test_git_extension.py Updates expectations after removing spec-file creation from the git extension branch script.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 10/10 changed files
  • Comments generated: 0 new

@mnriem mnriem merged commit 2972dec into github:main Apr 8, 2026
12 checks passed
@mnriem mnriem deleted the git-extension-stage2 branch April 8, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants