Skip to content

feat(git): add no-cone support for sparse patterns#24

Merged
fbosch merged 5 commits into
masterfrom
feature/no-cone-patterns
Feb 4, 2026
Merged

feat(git): add no-cone support for sparse patterns#24
fbosch merged 5 commits into
masterfrom
feature/no-cone-patterns

Conversation

@fbosch
Copy link
Copy Markdown
Owner

@fbosch fbosch commented Feb 4, 2026

Summary

Refactor sparse checkout logic to support no-cone mode for glob patterns.

Changes

  • Replace isSparseEligible and extractSparsePaths with unified resolveSparseSpec function
  • Add glob detection via patternHasGlob to determine sparse mode (no-cone vs cone)
  • Pass --no-cone flag to git sparse-checkout when patterns contain globs or literal paths
  • Update all three checkout locations: clone, worktree, and cache operations

Summary by CodeRabbit

  • New Features

    • Sparse checkout is now driven by a structured spec; clone and sync consistently apply sparse mode and patterns.
    • Clone results now include an indicator showing whether a repository came from cache.
  • Bug Fixes

    • Mixed include patterns (literals + globs) correctly use no-cone sparse mode and apply all patterns.
  • Tests

    • Added test validating sparse checkout behavior with mixed include patterns.

Copilot AI review requested due to automatic review settings February 4, 2026 20:20
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 4, 2026

Warning

Rate limit exceeded

@fbosch has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 27 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Introduces a structured SparseSpec pipeline in src/git/fetch-source.ts (enabled, mode: "cone" | "no-cone", patterns), replaces prior boolean sparse logic, threads the spec through clone/add-worktree flows to emit --sparse, optional --no-cone, and sparse-checkout set; adds a test for mixed include patterns.

Changes

Cohort / File(s) Summary
Sparse Checkout Refactoring
src/git/fetch-source.ts
Replaces isSparseEligible/extractSparsePaths with resolveSparseSpec and internal helpers (patternHasGlob, normalizeSparsePatterns, isDirectoryLiteral, toNoConePattern). Produces SparseSpec (enabled, mode, patterns) and applies it across clone/add-worktree/update flows to drive --sparse, --no-cone, and sparse-checkout set invocations.
CloneResult Shape
src/git/fetch-source.ts
Updates exported CloneResult type to include usedCache: boolean alongside existing cleanup function to signal whether a cached repo was used.
Sparse Mode Testing
tests/fetch-source-file-protocol.test.js
Adds test "sync uses no-cone sparse for mixed include patterns" verifying mixed literal+glob includes produce --no-cone sparse mode and that both patterns are passed to sparse-checkout set.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Runner as Sync Runner
participant Cache as Local Cache
participant Git as Git CLI
participant FS as Worktree/FS
Runner->>Cache: check for cached repo
alt cache hit
Cache-->>Runner: return cached repo (usedCache=true)
Runner->>Git: add worktree (apply sparseSpec)
Git-->>FS: apply sparse-checkout set (patterns; --no-cone if mode=no-cone)
else cache miss
Runner->>Git: clone repository (include --sparse, --no-cone per sparseSpec)
Git-->>FS: checkout commit and apply sparse-checkout set
end
Runner->>Runner: return CloneResult { cleanup, usedCache }

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I found my patterns, literal and wide,

No-cone and cone now walk side by side,
I hop through specs, tidy and fleet,
Sparse-checkout sings — the repo's neat.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(git): add no-cone support for sparse patterns' accurately captures the main feature introduced: adding support for no-cone mode in sparse-checkout operations. This directly aligns with the core change described in the PR objectives and file summaries.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/no-cone-patterns

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 4, 2026

Open in StackBlitz

npx https://pkg.pr.new/fbosch/docs-cache@24

commit: bfa4e4d

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

This PR adds support for git sparse-checkout's no-cone mode to handle advanced glob patterns like ** (double-star) and literal file patterns that cone mode doesn't support. Previously, patterns with ** were not eligible for sparse checkout; now they use no-cone mode with gitignore-style pattern matching.

Changes:

  • Refactored sparse-checkout eligibility logic from isSparseEligible/extractSparsePaths to a unified resolveSparseSpec function that determines mode and patterns
  • Added support for --no-cone flag when patterns include ** or literals
  • Added test coverage for no-cone mode with mixed literal and glob patterns

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/git/fetch-source.ts Replaced sparse eligibility logic with new resolveSparseSpec function that chooses between cone and no-cone modes based on pattern types; added --no-cone flag support in three git operation functions
tests/fetch-source-file-protocol.test.js Added test verifying no-cone mode is used for mixed include patterns (literal file + double-star glob)

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

Comment thread src/git/fetch-source.ts Outdated
Comment thread src/git/fetch-source.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/git/fetch-source.ts`:
- Around line 292-309: resolveSparseSpec currently truncates patterns at the
first "*" only (see the starIndex calculation) which lets patterns containing
"?" or "[" slip through and be treated as cone-mode; update the truncation to
locate the first occurrence of any glob character (e.g., "*", "?", "[") when
computing base paths so patterns like "docs/??.md" or "docs/[ab].md" are
detected as non-cone and handled accordingly; keep the rest of the flow
(normalizeSparsePatterns, patternHasGlob check, trimming trailing slashes,
uniquePaths creation) the same but replace the single-character indexOf("*")
logic with a search for the first index among the full set of glob chars and use
that index to slice the base.
🧹 Nitpick comments (1)
src/git/fetch-source.ts (1)

292-296: Avoid as const/as string[] by typing the sparse spec.
A small SparseSpec type and explicit return type removes the assertions and aligns with the “avoid type casts” guideline.

♻️ Suggested refactor
+type SparseSpec = {
+	enabled: boolean;
+	mode: "cone" | "no-cone";
+	patterns: string[];
+};
+
-const resolveSparseSpec = (include?: string[]) => {
+const resolveSparseSpec = (include?: string[]): SparseSpec => {
 	const normalized = normalizeSparsePatterns(include);
 	if (normalized.length === 0) {
-		return { enabled: false, mode: "cone" as const, patterns: [] as string[] };
+		return { enabled: false, mode: "cone", patterns: [] };
 	}
 	const hasDoubleStar = normalized.some((pattern) => pattern.includes("**"));
 	const hasLiteral = normalized.some((pattern) => !patternHasGlob(pattern));
 	if (hasDoubleStar || hasLiteral) {
-		return { enabled: true, mode: "no-cone" as const, patterns: normalized };
+		return { enabled: true, mode: "no-cone", patterns: normalized };
 	}
 	// ...
-	return { enabled: true, mode: "cone" as const, patterns: uniquePaths };
+	return { enabled: true, mode: "cone", patterns: uniquePaths };
 };

Comment thread src/git/fetch-source.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/git/fetch-source.ts`:
- Around line 307-335: resolveSparseSpec currently treats patterns with
glob/wildcard as cone-eligible by extracting the base path, causing broad
matching; change the logic so any pattern where patternHasGlob(pattern) is true
(including ones that matched the '**' check) sets coneEligible = false and
breaks out of the loop so cone mode is disabled for globs; update the loop in
resolveSparseSpec to only push to conePaths when a pattern is a pure directory
literal (isDirectoryLiteral returns true) and otherwise mark coneEligible =
false (using the existing variables patternHasGlob, isDirectoryLiteral,
conePaths, and coneEligible).
🧹 Nitpick comments (1)
src/git/fetch-source.ts (1)

598-629: Consider extracting a shared sparse-checkout helper to avoid duplication.

The same sparse-checkout set block appears in cloneRepo, addWorktreeFromCache, and cloneOrUpdateRepo. A small helper would reduce drift risk and keep option wiring consistent.

♻️ Suggested refactor
+const applySparseCheckout = async (
+	repoDir: string,
+	sparseSpec: ReturnType<typeof resolveSparseSpec>,
+	options?: {
+		timeoutMs?: number;
+		logger?: (message: string) => void;
+		allowFileProtocol?: boolean;
+	},
+) => {
+	if (!sparseSpec.enabled) return;
+	const sparseArgs = ["-C", repoDir, "sparse-checkout", "set"];
+	if (sparseSpec.mode === "no-cone") {
+		sparseArgs.push("--no-cone");
+	}
+	sparseArgs.push(...sparseSpec.patterns);
+	await git(sparseArgs, options);
+};
-	if (sparseSpec.enabled) {
-		const sparseArgs = ["-C", outDir, "sparse-checkout", "set"];
-		if (sparseSpec.mode === "no-cone") {
-			sparseArgs.push("--no-cone");
-		}
-		sparseArgs.push(...sparseSpec.patterns);
-		await git(sparseArgs, {
-			timeoutMs: params.timeoutMs,
-			allowFileProtocol: true,
-			logger: params.logger,
-		});
-	}
+	await applySparseCheckout(outDir, sparseSpec, {
+		timeoutMs: params.timeoutMs,
+		allowFileProtocol: true,
+		logger: params.logger,
+	});

Comment thread src/git/fetch-source.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/git/fetch-source.ts`:
- Around line 307-338: The resolveSparseSpec function currently uses inline type
assertions (`as const`, `as string[]`) in its return objects; remove those
assertions and instead add an explicit return type to the function signature
that models the discriminated union (e.g. { enabled: false; mode: "cone";
patterns: string[] } | { enabled: true; mode: "cone" | "no-cone"; patterns:
string[] } or your existing SparseSpec type). Update the function declaration
for resolveSparseSpec(include?: string[]): <ExplicitReturnType> and return plain
objects (no `as const`/`as string[]`) so the compiler infers the discriminant
and patterns as string[] correctly; keep the existing control flow and values
(conePaths/uniquePaths/normalized.map(toNoConePattern)) unchanged.

Comment thread src/git/fetch-source.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/git/fetch-source.ts`:
- Around line 292-305: The current logic in isDirectoryLiteral treats
extensionless filenames (e.g., LICENSE, Makefile) as directories by checking for
absence of a dot in the last segment; change this to a conservative rule that
only treats a pattern as a directory literal when it explicitly ends with '/'
(i.e., make isDirectoryLiteral return true only for pattern.endsWith('/')), and
keep toNoConePattern unchanged so no trailing slash is appended for ambiguous
extensionless patterns; if you want later disambiguation, add a separate pass
after clone (e.g., using git ls-tree) rather than inferring by lack of a dot.

Comment thread src/git/fetch-source.ts Outdated
@fbosch fbosch merged commit c6ad123 into master Feb 4, 2026
16 checks passed
@fbosch fbosch deleted the feature/no-cone-patterns branch February 4, 2026 22:29
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