feat: make git extension opt-in and remove --no-git at v0.10.0#2873
Open
Copilot wants to merge 13 commits into
Open
feat: make git extension opt-in and remove --no-git at v0.10.0#2873Copilot wants to merge 13 commits into
Copilot wants to merge 13 commits into
Conversation
5 tasks
Copilot
AI
changed the title
[WIP] Finalize git extension as opt-in and remove --no-git flag
feat(init)!: make git extension opt-in and remove --no-git at v0.10.0
Jun 5, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR finalizes the v0.10.0 breaking change around Git behavior during specify init: the bundled git extension is no longer auto-installed, and the deprecated --no-git flag is removed, while git repository initialization (git init) still occurs when git is available and no repo exists.
Changes:
- Removes
--no-gitfrom theinitcommand and drops bundled git extension auto-installation from the init flow. - Updates integration tests to stop passing
--no-gitand adds new opt-in assertions around the git extension. - Updates docs/changelog to reflect the new “git extension is opt-in” behavior and the flag removal.
Show a summary per file
| File | Description |
|---|---|
| src/specify_cli/commands/init.py | Removes the --no-git flag and bundled git extension auto-install; keeps git init when available. |
| tests/integrations/test_cli.py | Removes --no-git usage and replaces auto-install tests with opt-in expectations. |
| docs/upgrade.md | Updates upgrade guidance for projects previously relying on --no-git. |
| docs/reference/core.md | Removes --no-git from specify init reference and updates notes/examples. |
| docs/local-development.md | Updates troubleshooting guidance related to the git step. |
| CHANGELOG.md | Adds a v0.10.0 entry documenting the breaking changes. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 6/6 changed files
- Comments generated: 5
- Remove --no-git parameter from specify init command - Remove git extension auto-installation from init flow - Git repository initialization (git init) still runs when git is available - Remove --no-git from all test invocations across the test suite - Update docs to reflect opt-in git extension behavior - Replace TestGitExtensionAutoInstall with TestGitExtensionOptIn tests BREAKING CHANGE: specify init no longer auto-installs the git extension. Use `specify extension add git` to install it explicitly. The --no-git flag has been removed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
558bfa9 to
90d1d69
Compare
Git functionality is now entirely managed by the git extension. Core scripts only handle directory-based feature creation and numbering. - Remove has_git(), check_feature_branch(), git branch creation from core - Simplify number detection to use only spec directory scanning - Remove HAS_GIT output from get_feature_paths() - Remove git remote fetching and branch querying - Keep BRANCH_NAME output key for backward compatibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove is_git_repo() and init_git_repo() dead code from _utils.py - Remove --branch-numbering from init command - Remove git from 'specify check' (now extension-only) - Update docs: git is optional prerequisite, check command description - Fix tests to reflect no-git-in-core reality (fallback to main) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… core Core scripts now resolve feature context exclusively from: 1. SPECIFY_FEATURE env var (set by git extension) 2. .specify/feature.json (persisted by specify command) Removed find_feature_dir_by_prefix() and directory scanning heuristics — these are the git extension's responsibility. Scripts error clearly when no feature context is available. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-options - specify command template now reads feature_numbering (preferred) with fallback to branch_numbering (deprecated) from init-options.json - Git extension reads git-config.yml > feature_numbering > branch_numbering - init now writes feature_numbering: sequential to init-options.json - Deprecation warning emitted when branch_numbering is used as fallback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When SPECIFY_FEATURE_DIRECTORY is set, get_feature_paths() now writes the value to .specify/feature.json so future sessions without the env var can still resolve the feature directory. The write is idempotent — it skips when the file already contains the same value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
docs/upgrade.md:285
- These instructions say setting
SPECIFY_FEATUREis sufficient for non-git projects, but the updated shared scripts now requireSPECIFY_FEATURE_DIRECTORYor.specify/feature.jsonto resolve the feature directory. Update the docs to reflect the new required feature context so non-git workflows remain usable.
Projects that do not use Git can still work with Spec Kit by setting `SPECIFY_FEATURE` manually before planning commands:
```bash
# Bash/Zsh
export SPECIFY_FEATURE="001-my-feature"
- Files reviewed: 46/46 changed files
- Comments generated: 11
This was referenced Jun 8, 2026
Closed
…git-extension-opt-in
- Update error messages in common.sh and common.ps1 to reference SPECIFY_FEATURE_DIRECTORY instead of SPECIFY_FEATURE (which no longer resolves feature directories) - Fix get_current_branch comment (returns empty string, not error) - Update upgrade.md to reference SPECIFY_FEATURE_DIRECTORY with correct example paths - Update local-development.md troubleshooting: replace stale 'Git step skipped' row with actionable git extension guidance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a61adfb to
458449a
Compare
- Use json_escape in printf fallback when jq is unavailable (common.sh) - Replace utf8NoBOM encoding with UTF8Encoding($false) for PowerShell 5.1 compatibility (common.ps1) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (2)
scripts/bash/create-new-feature.sh:253
- create-new-feature.sh now drives feature directory creation without relying on git, but it doesn't persist the resolved feature directory to
.specify/feature.jsonand it still tells users to exportSPECIFY_FEATURE. Sinceget_feature_pathsnow requiresSPECIFY_FEATURE_DIRECTORYorfeature.json, a fresh run of this script can leave follow-on scripts (setup-plan/tasks/check-prerequisites) without resolvable feature context unless the user manually setsSPECIFY_FEATURE_DIRECTORY. Persist the feature directory via_persist_feature_jsonand update the persistence hint accordingly.
mkdir -p "$FEATURE_DIR"
if [ ! -f "$SPEC_FILE" ]; then
TEMPLATE=$(resolve_template "spec-template" "$REPO_ROOT") || true
if [ -n "$TEMPLATE" ] && [ -f "$TEMPLATE" ]; then
scripts/powershell/create-new-feature.ps1:201
- create-new-feature.ps1 still only sets
SPECIFY_FEATUREafter creating the feature directory. With the new common.ps1 behavior, downstream scripts resolve feature context fromSPECIFY_FEATURE_DIRECTORYor.specify/feature.json, so a run of this script can leave follow-on commands without resolvable feature context. Persist the feature directory viaSave-FeatureJsonand setSPECIFY_FEATURE_DIRECTORYfor the current session (in addition toSPECIFY_FEATUREif you still want to expose the feature name).
New-Item -ItemType Directory -Path $featureDir -Force | Out-Null
if (-not (Test-Path -PathType Leaf $specFile)) {
$template = Resolve-Template -TemplateName 'spec-template' -RepoRoot $repoRoot
if ($template -and (Test-Path $template)) {
- Files reviewed: 46/46 changed files
- Comments generated: 0 new
…ions These guards are no longer needed since the branch-name validation they protected against has been removed from check-prerequisites. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
tests/integrations/test_integration_subcommand.py:967
- These assertions expect
setup-tasks.shto contain hard-coded/speckit-planand then change to/speckit.planafter an integration switch. The shared bash scripts now build command hints dynamically viaformat_speckit_command+integration.json(and do not contain literal/speckit-*strings), so this test will fail even when behavior is correct. Update the test to assert the dynamic formatter is present (and no hard-coded invocations exist), or validate command-style changes via rendered templates (which do use__SPECKIT_COMMAND_*__placeholders).
- Files reviewed: 46/46 changed files
- Comments generated: 4
Comment on lines
239
to
+243
| if [ "$DRY_RUN" != true ]; then | ||
| if [ "$HAS_GIT" = true ]; then | ||
| branch_create_error="" | ||
| if ! branch_create_error=$(git checkout -q -b "$BRANCH_NAME" 2>&1); then | ||
| current_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)" | ||
| # Check if branch already exists | ||
| if git branch --list "$BRANCH_NAME" | grep -q .; then | ||
| if [ "$ALLOW_EXISTING" = true ]; then | ||
| # If we're already on the branch, continue without another checkout. | ||
| if [ "$current_branch" = "$BRANCH_NAME" ]; then | ||
| : | ||
| # Otherwise switch to the existing branch instead of failing. | ||
| elif ! switch_branch_error=$(git checkout -q "$BRANCH_NAME" 2>&1); then | ||
| >&2 echo "Error: Failed to switch to existing branch '$BRANCH_NAME'. Please resolve any local changes or conflicts and try again." | ||
| if [ -n "$switch_branch_error" ]; then | ||
| >&2 printf '%s\n' "$switch_branch_error" | ||
| fi | ||
| exit 1 | ||
| fi | ||
| elif [ "$USE_TIMESTAMP" = true ]; then | ||
| >&2 echo "Error: Branch '$BRANCH_NAME' already exists. Rerun to get a new timestamp or use a different --short-name." | ||
| exit 1 | ||
| else | ||
| >&2 echo "Error: Branch '$BRANCH_NAME' already exists. Please use a different feature name or specify a different number with --number." | ||
| exit 1 | ||
| fi | ||
| else | ||
| >&2 echo "Error: Failed to create git branch '$BRANCH_NAME'." | ||
| if [ -n "$branch_create_error" ]; then | ||
| >&2 printf '%s\n' "$branch_create_error" | ||
| else | ||
| >&2 echo "Please check your git configuration and try again." | ||
| fi | ||
| exit 1 | ||
| fi | ||
| if [ -d "$FEATURE_DIR" ] && [ "$ALLOW_EXISTING" != true ]; then | ||
| if [ "$USE_TIMESTAMP" = true ]; then | ||
| >&2 echo "Error: Feature directory '$FEATURE_DIR' already exists. Rerun to get a new timestamp or use a different --short-name." | ||
| else |
| exit 1 | ||
| } | ||
|
|
||
| New-Item -ItemType Directory -Path $featureDir -Force | Out-Null |
Comment on lines
63
to
67
| # Strip repo root prefix if the value is absolute and under repo root | ||
| $prefix = $RepoRoot + [System.IO.Path]::DirectorySeparatorChar | ||
| if ($FeatureDirectory.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) { | ||
| $FeatureDirectory = $FeatureDirectory.Substring($prefix.Length) | ||
| } |
| @@ -28,11 +28,6 @@ eval "$_paths_output" | |||
| unset _paths_output | |||
|
|
|||
| # Validate branch | |||
…anch The git extension's script only creates the git branch — rename it to reflect that responsibility. The core create-new-feature.sh/.ps1 handles feature directory creation and feature.json persistence. Also includes fixes from review feedback: - common.sh: _persist_feature_json uses json_escape fallback - common.ps1: Save-FeatureJson uses UTF8Encoding for PS 5.1 compat - common.ps1: case-sensitive path stripping on non-Windows - create-new-feature.sh/ps1: output both SPECIFY_FEATURE and SPECIFY_FEATURE_DIRECTORY - setup-tasks.sh: fix stale 'Validate branch' comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Finalizes the git extension default change at v0.10.0:
specify initno longer auto-installs the bundled git extension, and the deprecated--no-gitflag is removed. Users who want the git extension must opt in viaspecify extension add git.Core changes
src/specify_cli/commands/init.py--no-gitparameter and its deprecation warning blockExtensionManager.install_from_directoryforgit) from the init flowgit_default_noticevariable and the "Notice: Git Default Changing" panel--branch-numberingparameter (now managed entirely by the git extension's config)git initis now the git extension's responsibility (via itsspeckit.git.initializecommand)"git"tracker step entirely (no git-related work happens during init)scripts/bash/common.sh/scripts/powershell/common.ps1check_feature_branch/Test-FeatureBranch) fromcheck-prerequisitesSPECIFY_FEATURE_DIRECTORYenv var or.specify/feature.json_persist_feature_json/Save-FeatureJsonhelpers for writing feature stateSPECIFY_FEATURE_DIRECTORY(notSPECIFY_FEATURE)Tests
TestGitExtensionAutoInstall→ replaced withTestGitExtensionOptIn:test_git_extension_not_auto_installed— extension dir absent after plainspecify inittest_no_git_flag_is_rejected—--no-gitnow exits non-zero (unknown option)test_git_extension_commands_not_registered_by_default— nospeckit-git-*skills after init--no-gitfrom all other test invocations throughouttests/integrations/test_cli.pyDocs & changelog
docs/reference/core.md: removed--no-gitrow from options table and the pre-v0.10.0 NOTE; updated examplesdocs/upgrade.md: updated Scenario 4 (no-git projects); removed the## Using --no-git Flagsectiondocs/local-development.md: updated common-issues tableCHANGELOG.md: added## [0.10.0] - TBDsection documenting both breaking changesCloses #2887