A lightweight, fast CLI tool for managing git submodules with advanced sparse checkout support. Built on top of gitoxide and git2 libraries for maximum performance and reliability.
- TOML-based configuration - Define submodules, sparse-checkout paths, and settings in a simple config file
- Global defaults with overrides - Set project-wide submodule settings with per-submodule customization
- Sparse checkout support - Efficiently checkout only the parts of submodules you need
- Fast operations - Leverages gitoxidefor high-performance git operations
- Robust fallbacks - Automatic fallback to git2and CLI when needed
- Comprehensive commands - Add, check, init, update, reset, and sync submodules with ease
- Developer-friendly - Clear status reporting and error messages
cargo install submodMise is a project management tool and package manager that can manage your development environment.
# Global installation
mise use -g cargo:submod@latest
# Project-specific installation
mise use cargo:submod@latestgit clone https://github.com/yourusername/submod.git
cd submod
cargo install --path .- 
Initialize a config file in your git repository: # Create a basic submod.toml configuration cat > submod.toml << EOF [defaults] ignore = "dirty" [my-submodule] path = "vendor/my-lib" url = "https://github.com/example/my-lib.git" sparse_paths = ["src/", "include/", "*.md"] EOF 
- 
Initialize your submodules: submod init 
- 
Check status: submod check 
Create a submod.toml file in your repository root:
# Global defaults applied to all submodules
[defaults]
ignore = "dirty"          # ignore dirty state in status
update = "checkout"       # update method
branch = "main"          # default branch to track
# Individual submodule configuration
[vendor-utils]
path = "vendor/utils"
url = "https://github.com/example/utils.git"
sparse_paths = ["src/", "include/", "*.md"]
ignore = "all"           # override default ignore setting
active = true            # whether submodule is active
[my-submodule]
path = "libs/my-submodule"
url = "https://github.com/example/my-submodule.git"
sparse_paths = ["src/core/", "docs/"]
branch = "develop"       # track specific branch- ignore: How to handle dirty submodules (- all,- dirty,- untracked,- none)
- update: Update strategy (- checkout,- rebase,- merge,- none,- !command)
- branch: Default branch to track (- .for current superproject branch)
- fetchRecurse: Fetch recursion (- always,- on-demand,- never)
- path: Local path where submodule should be placed
- url: Git repository URL
- sparse_paths: Array of paths to include in sparse checkout
- active: Whether the submodule is active (default:- true)
- All global defaults can be overridden per submodule
Add a new submodule to your configuration and repository:
submod add my-lib libs/my-lib https://github.com/example/my-lib.git \
  --sparse-paths "src/,include/" \
  --settings "ignore=all"Check the status of all configured submodules:
submod checkInitialize all missing submodules:
submod initUpdate all submodules to their latest commits:
submod updateHard reset submodules (stash changes, reset --hard, clean):
# Reset all submodules
submod reset --all
# Reset specific submodules
submod reset my-lib vendor-utilsRun a complete sync (check + init + update):
submod sync# Start with checking current state
submod check
# Initialize any missing submodules
submod init
# Update everything to latest
submod update
# Or do it all at once
submod sync# Add a submodule that only checks out specific directories
submod add react-components src/components https://github.com/company/react-components.git \
  --sparse-paths "src/Button/,src/Input/,README.md"# Use a custom config file
submod --config my-custom.toml check
# Check status with custom config
submod --config production.toml sync# Reset a problematic submodule
submod reset my-problematic-submodule
# Check what's wrong
submod check
# Re-sync everything
submod sync- Rust 1.87 or later
- Git
- Mise (recommended) - for tool management and task running
# Clone the repository
git clone https://github.com/bashandbone/submod.git
cd submod
# Install mise if you haven't already
curl https://mise.run | sh
# Install all development tools and dependencies
mise install
# Build the project
mise run build
# or: mise run b (alias)
# Run tests
mise run test
# Run the full CI suite (build + lint + test)
mise run ci# Build the project
mise run build          # or: mise run b
# Run tests
mise run test
# Lint with clippy
mise run lint
# Run full CI pipeline
mise run ci
# Clean build artifacts
mise run clean
# Cut a new release (maintainers only)
mise run releaseThis project uses hk for automated git hooks that ensure code quality:
# Install git hooks (done automatically with mise install)
hk install
# Run pre-commit checks manually
hk run pre-commit
# Run all linters and checks
hk check
# Auto-fix issues where possible
hk fix
# Run CI checks locally
hk run ciThe pre-commit hooks automatically run:
- cargo fmt - Code formatting
- cargo clippy - Linting
- cargo test - Test suite
- typos - Spell checking
- prettier - TOML/YAML formatting
- cargo deny - Security and license auditing
If you prefer not to use mise:
# Clone the repository
git clone https://github.com/bashandbone/submod.git
cd submod
# Install Rust if needed
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Build the project
cargo build
# Run tests
cargo test
# or hk run test
# Or use the comprehensive test runner
./scripts/run-tests.sh --verbose# Using mise (recommended)
mise run test           # Run all tests
mise run ci             # Run full CI suite
# Using hk
hk run test                 # Run tests only
hk run ci                   # Run CI checks
# Using cargo directly
cargo test              # Run all tests
cargo test --test integration_tests  # Integration tests only
# Using the test script
./scripts/run-tests.sh --verbose     # Comprehensive reporting
./scripts/run-tests.sh --performance # Include performance tests
./scripts/run-tests.sh --filter sparse_checkout  # Filter testssubmod/
βββ src/
β   βββ main.rs              # CLI entry point
β   βββ commands.rs          # Command definitions
β   βββ config.rs            # TOML configuration handling
β   βββ gitoxide_manager.rs  # Core submodule operations
βββ tests/                   # Integration tests
βββ sample_config/           # Example configurations
βββ scripts/                 # Development scripts
βββ docs/                    # Documentation
We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch: git checkout -b feature/amazing-feature
- Set up development environment: mise install(installs all tools and git hooks)
- Make your changes and add tests if applicable
- Commit your changes: git commit -m 'Add amazing feature'(hooks run automatically)
- Push to your branch: git push origin feature/amazing-feature(they'll actually run again in check mode, so they need to pass)
- Open a Pull Request
- Follow Rust best practices and idioms
- Add tests for new functionality. I'm not big on unit tests, but integration tests are essential.
- Update documentation for user-facing changes
- Use conventional commit messages
- Run mise run ciorhk run cibefore submitting PR
- Pre-commit hooks will automatically format code and run basic checks
- All automated checks must pass before PR can be merged
Submodule not initializing:
# Check if the URL is accessible
git ls-remote <submodule-url>
# Verify your configuration
submod checkSparse checkout not working:
- Ensure paths in sparse_pathsare relative to the submodule root
- Check that the submodule repository contains the specified paths
- Verify sparse checkout is enabled: git config core.sparseCheckoutin the submodule
Permission issues:
- Ensure you have proper SSH keys set up for private repositories
- Check if your Git credentials are configured correctly
Managing git submodules, especially with sparse checkouts, can be complex and error-prone. Traditional git submodule commands require multiple steps and careful attention to configuration details.
This tool was created to:
- Reduce barriers to contribution - Make it easier for new developers to work with projects using submodules
- Simplify complex workflows - Handle initialization, updates, and sparse checkout configuration automatically
- Provide better tooling - Clear status reporting and error messages
- Leverage modern Git libraries - Use gitoxidefor better performance and reliability
The tool is actively used in multiple projects at @knitli and @plainlicense, where submodules are essential for sharing core functionality across repositories.
This project is licensed under the Plain MIT License.
- gitoxide - Fast and safe pure Rust implementation of Git
- git2-rs - Rust bindings to libgit2
- clap - Command line argument parser
Homepage β’ Documentation β’ Crate
Made with β€οΈ for the Rust and Git communities