repoverlay is a CLI tool that overlays config files into git repositories without committing them. It supports local overlays, GitHub repository overlays, and shared overlay repositories.
src/
├── main.rs # CLI entry point (minimal - delegates to lib)
├── cli.rs # CLI command definitions and argument parsing (clap)
├── lib.rs # Core library with apply/remove/status/restore/update operations
├── state.rs # State persistence (in-repo and external backup)
├── github.rs # GitHub URL parsing and source resolution
├── cache.rs # GitHub repository cache management
├── config.rs # Global and per-repo configuration (CCL format)
├── sources.rs # Multi-source overlay resolution with priority ordering
├── overlay_repo.rs # Shared overlay repository integration
├── upstream.rs # Upstream repository detection for fork inheritance
├── library.rs # In-repo overlay library management
├── detection.rs # File discovery for overlay creation
├── selection.rs # Interactive file selection UI
├── widgets/ # Reusable ratatui UI components
│ ├── mod.rs
│ └── multi_select_tree.rs # Tree widget with tri-state checkboxes
└── testutil.rs # Test utilities (create_test_repo, create_test_overlay)
tests/
├── cli.rs # CLI integration tests using assert_cmd
└── common/mod.rs # Shared test utilities and fixtures
-
main.rs - Minimal CLI entry point. Initializes logging and delegates to
lib::run(). -
cli.rs - CLI command definitions using clap derive macros. Defines all subcommands, arguments, and flags.
-
lib.rs - Core operations:
apply_overlay,remove_overlay,show_status,restore_overlays,update_overlays,create_overlay,switch_overlay. Also handles git exclude file management. -
selection.rs - Interactive file selection UI. Handles checkbox-style multi-select for overlay creation.
-
widgets/ - Reusable ratatui UI components.
- multi_select_tree.rs -
MultiSelectTreestateful widget: renders a tree with tri-state checkboxes (checked/unchecked/partial) based on descendant selection state.
- multi_select_tree.rs -
-
state.rs - State persistence layer. Manages overlay state in two locations:
- In-repo:
.repoverlay/overlays/<name>.ccl- tracks applied overlays - External:
~/.local/share/repoverlay/applied/- backup for recovery aftergit clean
- In-repo:
-
github.rs - GitHub URL parsing. Handles URL formats like
https://github.com/owner/repo/tree/branch/subpathand extracts owner, repo, ref, and subpath components. -
cache.rs - GitHub repository caching. Manages cloned repos in
~/.cache/repoverlay/github/owner/repo/. Supports shallow clones and update checking. -
config.rs - Configuration management using CCL format. Handles global config (
~/.config/repoverlay/config.ccl) and per-overlay config (repoverlay.ccl). -
sources.rs - Multi-source overlay resolution. Manages a priority-ordered list of overlay sources (configured via
repoverlay source add/remove/list). ProvidesSourceManagerfor resolving overlay references across multiple sources with first-match-wins semantics. -
overlay_repo.rs - Shared overlay repository support. Allows overlays to be referenced as
org/repo/namefrom a centrally managed repository. Supports fallback resolution for fork inheritance. -
upstream.rs - Upstream repository detection. Scans git remotes to identify parent repositories (forks), enabling automatic overlay inheritance from upstream.
-
library.rs - In-repo overlay library management. Handles the
.repoverlay/library/directory for storing shareable overlays within a repository. Provides path resolution (configurable via per-repo config), overlay listing, import/export/remove operations, and gitignore detection. Library overlays are auto-discovered and resolved with highest priority. -
detection.rs - File discovery for the
createcommand. Identifies AI configs, gitignored files, and untracked files that might be candidates for overlay creation. -
testutil.rs - Test utilities including
create_test_repo()andcreate_test_overlay()helpers for setting up temporary git repositories in tests.
Source string → resolve_source() → local path
↓
Walk files in overlay directory
↓
For each file:
- Check for conflicts with existing overlays
- Check for conflicts with existing files
- Create symlink or copy
↓
Update .git/info/exclude with overlay section
↓
Save state to .repoverlay/overlays/<name>.ccl
↓
Save external backup to ~/.local/share/repoverlay/applied/
Load state from .repoverlay/overlays/<name>.ccl
↓
For each file entry:
- Remove file/symlink
- Clean empty parent directories
↓
Remove overlay section from .git/info/exclude
↓
Delete state file
↓
Remove external backup
Load external state backup from ~/.local/share/repoverlay/applied/
↓
For each saved overlay:
- Re-apply using original source (path or GitHub URL)
For each applied GitHub overlay:
- Check remote for new commits
- If updates available:
- Remove old overlay
- Re-apply with updated cache
Discover files in repository (AI configs, gitignored, untracked)
↓
Interactive selection or --include flags
↓
Copy selected files to output directory
↓
Generate repoverlay.ccl config
Remove all existing overlays
↓
Apply new overlay (atomic replacement)
Overlay state is stored in CCL format (a human-readable configuration language). Example:
name = my-overlay
applied_at = 2024-01-15T10:30:00Z
source = local|/path/to/overlay
files =
source = .envrc
target = .envrc
link_type = symlink
Source types are encoded as pipe-delimited strings:
- Local:
local|/path/to/overlay - Library:
library|name(in-repo.repoverlay/library/overlay) - GitHub:
github|url|owner|repo|ref|commit|subpath|cached_at - Overlay repo:
overlay_repo|org|repo|name|commit
Overlay files are excluded from git tracking via .git/info/exclude using named sections:
# repoverlay:my-overlay start
.envrc
.claude/
# repoverlay:my-overlay end
This approach:
- Keeps overlay files out of version control
- Doesn't modify
.gitignore(which is tracked) - Allows multiple overlays with distinct sections
- Enables clean removal of individual overlays
The resolve_source() function determines the overlay source type:
- GitHub URL (
https://github.com/...) - Downloads to cache, returns cached path - Local path (
./pathor/path) - Returns path directly after validation - Library overlay (bare name) - Checks
.repoverlay/library/first (highest priority) - Overlay repo reference (
org/repo/name) - Resolves from configured shared repository
When applying overlays from a shared repository to a forked repo, repoverlay automatically inherits overlays from the upstream (parent) repository.
- Direct match - Look for
fork-org/fork-repo/overlay-name - Upstream fallback - If not found and upstream exists, look for
upstream-org/upstream-repo/overlay-name
The upstream repository is detected by scanning git remotes:
- Check for a remote named
upstream(standard fork convention) - Parse the remote URL (supports both HTTPS and SSH formats)
- Extract org/repo for fallback resolution
Example:
# Fork setup
git remote -v
# origin git@github.com:tylerbutler/FluidFramework.git (fetch)
# upstream git@github.com:microsoft/FluidFramework.git (fetch)
# Apply overlay - will fallback to microsoft/FluidFramework if needed
repoverlay apply microsoft/FluidFramework/claude-configThe ResolvedVia enum tracks how an overlay was resolved:
Direct- Exact match in overlay repositoryUpstream- Resolved via upstream fallback
This is stored in the overlay state and displayed in repoverlay status:
Overlay: claude-config
Source: microsoft/FluidFramework/claude-config (via upstream) (overlay repo)
Commit: abc123def456
GitHub repositories are cached in ~/.cache/repoverlay/github/owner/repo/:
- Uses shallow clones to minimize disk usage
- Caches are updated on
repoverlay updateor when--refchanges - Cache metadata tracks commit hash and last update time
repoverlay cachesubcommands manage the cache
See docs/adr/ for architectural decision records.