This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
cargo build # debug build
cargo build --release # release build
mise run build # alias: mise run bcargo nextest run --all-features --no-fail-fast # run all tests (preferred)
cargo test --test integration_tests # integration tests only
cargo test --test command_contract_tests # command contract tests only
./scripts/run-tests.sh --verbose # comprehensive test runner with reporting
./scripts/run-tests.sh --filter sparse_checkout # filter to specific tests
mise run test # alias: mise run t (runs via hk)Integration tests that modify git repos are serialized via nextest test groups (.config/nextest.toml); other tests run in parallel. Each test gets an isolated git config via GIT_CONFIG_GLOBAL so tests never race on ~/.gitconfig. The test suite is integration-test-focused; unit tests are minimal by design.
cargo fmt # format code
cargo clippy --all-features # lint
hk run check # run all linters (fmt, clippy, deny, typos, pkl)
hk fix # auto-fix where possible
mise run lint # alias for hk run checkmise run ci # build + lint + test
hk run ci # same via hk (uses --fail-fast for tests)Managed by hk (configured in hk.pkl). Pre-commit runs: cargo fmt, clippy, check, nextest, typos, cargo-deny, pkl eval. Hooks install automatically with mise install.
submod is a CLI tool for managing git submodules with TOML configuration and sparse checkout support. It exposes the library as src/lib.rs primarily for integration testing (the public API is not stable).
CLI (commands.rs + main.rs)
↓ clap parsing
GitManager (git_manager.rs) ← high-level submodule operations
↓ delegates to
GitOpsManager (git_ops/mod.rs) ← unified backend with automatic fallback
├── GixOperations (git_ops/gix_ops.rs) ← gitoxide (preferred)
├── Git2Operations (git_ops/git2_ops.rs) ← libgit2 (fallback)
└── Git CLI ← last resort (spawned via std::process)
Config (config.rs) ← figment-based TOML config loading/saving
The core design is a gix-first, git2-fallback, CLI-last-resort strategy, driven by the immaturity of gitoxide's submodule support. GitOpsManager wraps both backends behind the GitOperations trait and calls try_with_fallback() / try_with_fallback_mut() for every operation. When gix fails, it logs a warning and transparently retries with git2; add_submodule has an additional CLI fallback that also cleans up any partial state from the prior attempt.
After destructive operations (delete, nuke), GitOpsManager::reopen() must be called to refresh the in-memory repository state. git2 reopen errors are fatal; gix reopen errors are warnings only.
Config uses figment to load submod.toml. The schema has:
[defaults]→SubmoduleDefaults(global git options applied to all submodules)[<name>]sections →SubmoduleEntry(per-submodule config, overrides defaults)
SubmoduleEntry merges SubmoduleGitOptions (ignore, fetch_recurse, branch, update) with submodule-specific fields (path, url, sparse_paths, active, shallow). Options are serialized to/from git-config-compatible strings via the options.rs newtype wrappers (SerializableIgnore, SerializableUpdate, etc.).
- Unsafe code is forbidden (
unsafe_code = "forbid"inCargo.toml) - Clippy is configured at
pedantic+nurserywarn level;correctnessis deny missing_docsis warn — public items need doc commentsmodule_name_repetitionsandtoo_many_linesare allowed- All error handling uses
anyhowfor propagation andthiserrorfor defining error types simple_gix.rscontains lightweight gix helpers used ingix_ops.rs
Integration tests in tests/ use a TestHarness (in tests/common/mod.rs) that creates temporary git repos and invokes the compiled binary. Test files:
integration_tests.rs— end-to-end CLI behaviorcommand_contract_tests.rs— CLI command argument contractsconfig_tests.rs— configuration parsing/serializationsparse_checkout_tests.rs— sparse checkout behaviorerror_handling_tests.rs— error conditions and messagesperformance_tests.rs— benchmarks (uses criterion)