# When Does tuicr Switch Between libgit2 and CLI Backends for Sparse Checkout?

> Discover when tuicr switches to the Git CLI for sparse checkout. Learn why libgit2 lacks sparse checkout support and how tuicr handles these repositories.

- Repository: [Almog Gavra/tuicr](https://github.com/agavra/tuicr)
- Tags: internals
- Published: 2026-08-02

---

**tuicr automatically falls back to the Git CLI backend whenever it detects a sparse-checkout or sparse-index repository, because libgit2 does not support sparse checkout operations.**

tuicr is a terminal UI code review tool that abstracts Git operations through multiple backends. Understanding when it switches between the high-performance **libgit2** library and the **Git CLI** helps developers predict behavior and diagnose performance characteristics. The switching logic is deterministic and repository-state driven.

## How tuicr Detects Sparse Checkout Repositories

The detection happens at startup through `GitRepoMode::detect` in [`src/vcs/git/mod.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/mod.rs). This function queries the repository's Git configuration for sparse-related settings.

```rust
// src/vcs/git/mod.rs
fn detect(root_path: &Path) -> Result<Self> {
    let output = run_git_command(
        root_path,
        &["config", "--get-regexp", r"^(core\.sparsecheckout|index\.sparse)$"],
    ).unwrap_or_default();

    Ok(Self::from_config(&output))
}

```

The detection covers two sparse modes:

- **SparseCheckout** — triggered when `core.sparsecheckout` is true (traditional sparse checkout)
- **SparseIndex** — triggered when `index.sparse` is true (newer sparse-index format introduced in Git 2.25)

Repositories without these flags are classified as **Standard** and default to libgit2.

## The Backend Switching Logic in `discover_from`

The actual switch occurs in `GitBackend::discover_from` at [`src/vcs/git/mod.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/mod.rs). The implementation follows a try-fallback pattern:

```rust
// src/vcs/git/mod.rs
fn discover_from(
    cwd: &Path,
    preference: GitBackendPreference,
    whitespace_mode: DiffWhitespaceMode,
) -> Result<Self> {
    // Attempt libgit2 first (faster, preferred)
    let backend = Self::Libgit2(Libgit2Backend::discover_from(cwd, whitespace_mode)?);
    
    // Detect repository mode
    let repo_mode = GitRepoMode::detect(&backend.info().root_path)?;
    
    // Fallback check: sparse checkout detected but libgit2 cannot handle it
    if repo_mode.is_sparse_checkout() && !backend.supports_sparse_checkout() {
        return Ok(Self::Cli(GitCliBackend::discover_from(cwd, whitespace_mode)?));
    }
    
    Ok(backend)
}

```

This logic executes on every repository initialization. The `supports_sparse_checkout()` check against the libgit2 backend is the critical gate.

## Why libgit2 Cannot Handle Sparse Checkouts

The libgit2 backend explicitly reports this limitation. In [`src/vcs/git/libgit2.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/libgit2.rs):

```rust
// src/vcs/git/libgit2.rs
impl VcsBackend for Libgit2Backend {
    fn supports_sparse_checkout(&self) -> bool {
        false   // libgit2 lacks sparse-checkout support
    }
    // ...
}

```

Because this method always returns `false`, the condition `!backend.supports_sparse_checkout()` is always true for libgit2. Combined with `repo_mode.is_sparse_checkout()` being true for sparse repositories, the fallback trigger is guaranteed.

## User-Facing Indicators of the Switch

When the CLI backend activates due to sparse checkout, tuicr emits a startup warning. In [`src/vcs/git/cli.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/cli.rs):

```rust
// src/vcs/git/cli.rs
fn startup_warnings(&self) -> Vec<String> {
    if !self.repo_mode().is_sparse_checkout() {
        return Vec::new();
    }
    vec!["Sparse checkout detected; using Git CLI backend.".to_string()]
}

```

This warning appears in tuicr's interface to inform users that Git CLI operations (slower than libgit2) are in use.

## Complete Backend Selection Rules

| Condition | Detection Method | Backend Used |
|-----------|----------------|--------------|
| Standard repository | No sparse flags in `git config` | **libgit2** (fast, default) |
| Sparse checkout repository | `core.sparsecheckout=true` | **Git CLI** (fallback) |
| Sparse index repository | `index.sparse=true` | **Git CLI** (fallback) |
| User-configured CLI preference | `backend = "cli"` in tuicr config | **Git CLI** (forced) |
| Reftable or split-index format | Early detection in `discover_from` | **Git CLI** (fallback) |

The sparse-checkout detection takes precedence after reftable/split-index checks but before the libgit2 backend is finalized.

## Test Verification of the Behavior

The project includes integration tests confirming this behavior. From [`src/vcs/git/mod.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/mod.rs):

```rust
// src/vcs/git/mod.rs (tests)
#[test]
fn default_preference_routes_sparse_index_repo_to_cli_with_warning() {
    // Set up repo with `git sparse-checkout init --cone --sparse-index`
    let backend = GitBackend::discover_from(
        root,
        GitBackendPreference::Libgit2,  // Explicitly request libgit2
        DiffWhitespaceMode::Normal,
    ).expect("failed to discover backend");

    match backend {
        GitBackend::Cli(backend) => {
            assert!(backend.supports_sparse_checkout());
            assert_eq!(
                backend.startup_warnings().first().map(String::as_str),
                Some("Sparse checkout detected; using Git CLI backend.")
            );
        }
        GitBackend::Libgit2(_) => panic!("sparse-index repo should use Git CLI backend"),
    }
}

```

This test verifies that even with `GitBackendPreference::Libgit2`, sparse repositories route to CLI with the expected warning.

## Performance and Compatibility Implications

- **libgit2 backend**: Uses in-memory operations, avoids process spawning, significantly faster for large repositories
- **Git CLI backend**: Spawns `git` subprocesses, higher overhead, but supports all Git features including sparse checkout

The automatic fallback ensures correctness over performance—tuicr prefers slower, correct operations to failing or producing incorrect results on sparse repositories.

## Summary

- **Detection**: `GitRepoMode::detect` queries `core.sparsecheckout` and `index.sparse` configuration
- **Decision point**: Lines 161-188 in [`src/vcs/git/mod.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/mod.rs) contain the switching logic
- **Determinant**: `Libgit2Backend::supports_sparse_checkout()` returns `false`, forcing fallback
- **Result**: `GitCliBackend` replaces `Libgit2Backend` transparently with user warning
- **Override**: No user override exists for sparse repositories—CLI is mandatory for correctness

## Frequently Asked Questions

### Can I force tuicr to use libgit2 on a sparse checkout repository?

No. According to the source code in [`src/vcs/git/mod.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/mod.rs), the fallback occurs unconditionally when `repo_mode.is_sparse_checkout()` is true and libgit2 reports `supports_sparse_checkout()` as false. Even setting `backend = "libgit2"` in configuration cannot override this safety check.

### How does tuicr detect sparse checkout vs sparse index?

Both are detected through the same `git config --get-regexp` command run by `GitRepoMode::detect`. `core.sparsecheckout` indicates traditional sparse checkout, while `index.sparse` indicates the newer sparse-index format. Both trigger CLI fallback.

### Does sparse checkout detection impact startup time?

Minimal impact. The detection executes a single `git config` subprocess during repository discovery. This occurs once at tuicr startup and adds only milliseconds compared to the ongoing performance difference between libgit2 and CLI operations.

### Will libgit2 support sparse checkout in the future?

The source code comment in [`src/vcs/git/libgit2.rs`](https://github.com/agavra/tuicr/blob/main/src/vcs/git/libgit2.rs) indicates libgit2 "lacks sparse-checkout support" with no version or timeline specified. The tuicr maintainers treat this as a permanent limitation, implementing CLI fallback as the long-term solution.