Skip to content

fix(extensions): stop the git extension's fetch from waiting on a credential prompt - #5201

Open
JakkulaVeerababu wants to merge 1 commit into
github:mainfrom
JakkulaVeerababu:fix/5199-git-fetch-terminal-prompt
Open

JakkulaVeerababu wants to merge 1 commit into
github:mainfrom
JakkulaVeerababu:fix/5199-git-fetch-terminal-prompt

Conversation

@JakkulaVeerababu

@JakkulaVeerababu JakkulaVeerababu commented Oct 30, 2026 •

Copy link
Copy Markdown

Description

Fixes #5199

Before it numbers a new feature branch, the git extension runs git fetch --all --prune with its output redirected. Git writes credential prompts to the terminal, not to stdout or stderr. So when a remote uses HTTPS and has no usable credential helper, the fetch stops at Username for 'https://github.com': and waits. speckit.git.feature is the mandatory before_specify hook, so in an agent session /speckit.specify appears to hang. The dry-run path already runs ls-remote with GIT_TERMINAL_PROMPT=0. The fetch path did not.

This PR sets GIT_TERMINAL_PROMPT=0 for that fetch in all three scripts:

  • Bash: GIT_TERMINAL_PROMPT=0 git fetch --all --prune >/dev/null 2>&1 || true
  • Python: env={**os.environ, "GIT_TERMINAL_PROMPT": "0"} on the fetch subprocess.run
  • PowerShell: sets the variable around the fetch in try/finally, then restores the caller's value (or removes the variable if it was unset), so nothing leaks into the calling session.

A failed fetch is still ignored, as before. Numbering then uses local branches and specs/.

Out of scope: SSH passphrase prompts. GIT_TERMINAL_PROMPT does not cover them, and forcing ssh -o BatchMode=yes would override a user's own GIT_SSH_COMMAND or core.sshCommand. That is the open question in the bug assessment, so I left it for a separate decision.

Testing

The new tests use a probe remote. It is an ssh:// URL whose core.sshCommand records the GIT_TERMINAL_PROMPT value it inherits from the fetch (or ls-remote), then fails. No network is used.

  • TestCreateFeatureBash::test_remote_lookup_disables_terminal_prompt[fetch|dry-run]
  • TestCreateFeaturePowerShell::test_remote_lookup_disables_terminal_prompt[fetch|dry-run]
  • TestCreateFeaturePowerShell::test_fetch_restores_caller_terminal_prompt[set|unset]
  • TestCreateFeatureBranchParity::test_fetch_disables_terminal_prompt (Bash and Python twins)

Results on Ubuntu 26.04 (WSL2), Python 3.13, bash 5.3, pwsh 7.6.8, git 2.53:

  • main with only the new tests: 5 failed, 2 passed. The probe saw unset on the fetch path. The two dry-run cases already passed.
  • This branch: 7 passed. tests/extensions/git: 181 passed, 2 skipped.
  • Full suite: 13927 passed, 166 skipped, 11 failed. The same 11 tests (composed-template cases in test_*_python_parity.py) also fail on unmodified main in this environment. They do not touch the git extension.
  • shellcheck --severity=error on the changed Bash script: clean.

Windows PowerShell 5.1 (5.1.26100, Desktop edition) with Git for Windows 2.55, same probe remote, non-dry-run:

Run GIT_TERMINAL_PROMPT seen by the fetch Caller's value after the script
main unset unset
this PR 0 unset
this PR, caller had 1 0 1
  • Tested locally with uv run specify --help
  • Ran existing tests (uv sync --extra test, then .venv/bin/python -m pytest, as AGENTS.md recommends)
  • Tested with a sample project (if applicable)

Manual test results

Agent: Claude Code (Claude Opus 5.5), autonomous | OS/Shell: Ubuntu 26.04 on WSL2 / bash 5.3, pwsh 7.6.8, python 3.13

Each project was scaffolded from the branch under test with specify init <dir> --integration claude --script {sh,ps,py} --extension git. Its only remote was https://github.com/github/spec-kit-issue-5199-does-not-exist.git (answers 401), with no credential helper. The agent ran the script line that speckit.git.feature instructs it to run, under a pseudo-terminal whose stdin stays open and silent, like an agent terminal that nobody types into. The script lines were run directly, not from an interactive agent session.

Command tested main this PR
/speckit.git.feature (Bash script) Stuck at Username for 'https://github.com':, killed after 20 s, no branch Exit 0 in 1 s, 001-probe created
/speckit.git.feature (PowerShell script) Same hang Exit 0 in 3 s, 001-probe created
/speckit.git.feature (Python script) Same hang Exit 0 in under 1 s, 001-probe created

Test selection reasoning

Changed file Affects Test Why
extensions/git/scripts/bash/create-new-feature-branch.sh /speckit.git.feature, and /speckit.specify through the before_specify hook T1 The command runs this script
extensions/git/scripts/powershell/create-new-feature-branch.ps1 Same T1 PowerShell twin
extensions/git/scripts/python/create_new_feature_branch.py Same T1 Python twin
tests/extensions/git/*.py None – Tests only

Required tests

  • T1: /speckit.git.feature, once per script flavour. The rest of /speckit.specify is unchanged; its only changed step is this hook.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Claude Code (model: Claude Opus 5.5, maximum reasoning effort) ran autonomously on behalf of the account owner, JakkulaVeerababu. It did the investigation, wrote the code change in all three scripts and the tests, ran the checks above, and wrote this description. The commit has an Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous) trailer. The account owner had not reviewed the change line by line when this PR was opened. That is why it is a draft: they will review it and then mark it ready.

🤖 Generated with Claude Code

…dential prompt

Before it numbers a new feature branch, the git extension runs
`git fetch --all --prune` with its output redirected. Git writes
credential prompts to the terminal, not to stdout or stderr, so an HTTPS
remote without a usable credential helper makes the fetch wait for a
username that nobody types. speckit.git.feature is the mandatory
before_specify hook, so /speckit.specify appears to hang in agent
sessions. The dry-run path already ran ls-remote with
GIT_TERMINAL_PROMPT=0; the fetch path did not.

Set GIT_TERMINAL_PROMPT=0 for that fetch in the Bash, PowerShell and
Python scripts. The PowerShell script restores the caller's value (or
removes the variable when it was unset). A failed fetch is still
ignored, as before.

Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI auto review requested due to automatic review settings October 30, 2026 21:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Oct 30, 2026
@JakkulaVeerababu
JakkulaVeerababu marked this pull request as ready for review October 31, 2026 02:03

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: git extension: non-dry-run git fetch can block /speckit.specify on a hidden credential prompt

3 participants