Skip to content

fix(git): non-interactive clones (no hang, #104) + blobless partial clone for speed (#91)#108

Merged
Minitour merged 3 commits into
developfrom
fix/git-no-interactive-prompt
Jun 10, 2026
Merged

fix(git): non-interactive clones (no hang, #104) + blobless partial clone for speed (#91)#108
Minitour merged 3 commits into
developfrom
fix/git-no-interactive-prompt

Conversation

@Minitour

@Minitour Minitour commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Closes #104 and #91. Two related improvements to repository cloning.


1. Private-repo installs fail fast instead of hanging (#104)

Problem

Cloning a private repo with no usable credentials made capa install hang forever: git fell back to an interactive terminal prompt (Username for 'https://...':) that capa never answers.

Fix

Force git non-interactive in the central git() wrapper, so every clone/fetch (skills, rules, hooks, plugins, registries) fails fast and the error is surfaced:

  • GIT_TERMINAL_PROMPT=0 — no interactive HTTP(S) credential prompt
  • GCM_INTERACTIVE=never — no Git Credential Manager GUI/browser popup
  • GIT_SSH_COMMAND=ssh -o BatchMode=yes -o ConnectTimeout=10 — defensive; a user-set value still wins

A caller-supplied opts.env still overrides these. explainGitError() now recognises git's terminal prompts disabled output and, for the no-auth case, tells the user the repo is private/inaccessible and to connect the integration.


2. Blobless partial clone for faster big-repo installs (#91)

Problem

git clone --mirror downloads every blob across all history — slow on large repos (e.g. remotion).

Fix

Switch the mirror clone to a blobless partial clone (--filter=blob:none): fetch the full commit/tree graph (so any SHA/tag/branch still resolves offline in resolveRef) but skip historical file contents. The blobs for the single revision we actually check out are fetched lazily by git worktree add during materializeSnapshot, so the snapshot tree stays byte-identical and no consumer is affected.

Why not the sparse-checkout-per-file approach from the issue? Consumers walk whole trees (@-basename search for skills/rules/hooks/plugins) and copy entire skill directories that reference sibling files — the full file set isn't knowable up front. Blobless keeps the materialized tree complete while still skipping the expensive history: the speedup without the regression risk the issue explicitly cautions about (skills/rules/hooks/plugins must not regress).

Safety:

  • Requires git ≥ 2.19. Servers without partial-clone support degrade gracefully to a full clone (git warns and ignores the filter) — verified with file:// fixtures, which still materialize completely.
  • Offline cache hits (pinned-SHA snapshot already on disk) are unaffected — only the first materialize of a SHA needs blobs.
  • Existing full-clone mirrors on disk keep working untouched.

Verification

  • Confirmed a clone of an inaccessible repo exits in ~1s with an actionable error (no hang).
  • Confirmed end-to-end that a blobless clone + worktree add materializes every file at the revision.
  • Tests: non-interactive env is passed (and overridable); explainGitError prompt-disabled/no-auth/token/not-found/network cases; blobless clone issues --filter=blob:none and still materializes a complete snapshot.
  • bunx tsc --noEmit clean; full suite 1048 pass / 0 fail.

🤖 Generated with Claude Code

Minitour and others added 3 commits June 10, 2026 16:53
…t instead of hanging

When cloning a private repo with no usable credentials, git fell back to an
interactive terminal prompt ("Username for 'https://...':"). capa never answers
it, so `capa install` hung indefinitely instead of reporting that the repo is
inaccessible.

Force git to run non-interactively in the central git() wrapper, so every
clone/fetch (skills, rules, hooks, plugins, registries) fails fast and the error
is surfaced to the user:

- GIT_TERMINAL_PROMPT=0  — no interactive HTTP(S) credential prompt
- GCM_INTERACTIVE=never  — no Git Credential Manager GUI/browser prompt
- GIT_SSH_COMMAND=ssh -o BatchMode=yes -o ConnectTimeout=10 (defensive; a
  user-set GIT_SSH_COMMAND still wins) — SSH fails fast instead of prompting

A caller-supplied opts.env still overrides these defaults.

Also improve explainGitError(): recognise git's "terminal prompts disabled"
(and "could not read Password") output and, for the no-auth case, tell the user
the repo is private/inaccessible and to connect the integration — while keeping
the "authentication failed"/"not accessible" substrings install-one-skill keys
off to append the integrations link.

Tests: assert the non-interactive env is passed (and is overridable), and cover
explainGitError's prompt-disabled / no-auth / token / not-found / network cases.

Closes #104

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Type the mock's opts param as `object` and cast at the use site (matching the
existing windowsHide test) so the cast to `typeof execFile` is valid without an
intermediate `unknown`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed up big-repo installs

`git clone --mirror` downloads every blob across all history, which is slow on
large repos (e.g. remotion). Switch to a blobless partial clone: fetch the full
commit/tree graph (so any SHA/tag/branch still resolves offline in resolveRef)
but skip historical file contents. The blobs for the single revision we check
out are fetched lazily by `git worktree add` during materializeSnapshot, so the
snapshot tree stays byte-identical and no consumer is affected.

Why blobless rather than the sparse-checkout-per-file approach from #91:
consumers walk whole trees (`@`-basename search for skills/rules/hooks/plugins)
and copy entire skill directories that reference sibling files, so the full file
set isn't known up front. Blobless keeps the materialized tree complete while
still skipping the expensive history — the speedup without the regression risk
the issue itself cautions about.

Requires git >= 2.19; servers without partial-clone support degrade gracefully
to a full clone (git warns and ignores the filter), so there's no regression on
older transports (verified: file:// fixtures still materialize completely).

Closes #91.

Tests: a real-git regression guard that cloning via ensureMirrorClone then
materializing still yields every file, plus an assertion that the clone is
issued with --filter=blob:none immediately after --mirror.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Minitour Minitour changed the title fix(git): private-repo installs fail fast instead of hanging (closes #104) fix(git): non-interactive clones (no hang, #104) + blobless partial clone for speed (#91) Jun 10, 2026
@Minitour Minitour merged commit 25d5e04 into develop Jun 10, 2026
10 of 11 checks passed
@Minitour Minitour deleted the fix/git-no-interactive-prompt branch June 10, 2026 17:10
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.

1 participant