# Git Module
**Purpose**: Git CLI integration for repository root discovery.
## File Responsibilities
### repository.rs
- **find_repository_root()**: Convenience wrapper using `current_dir()`
- **find_repository_root_from(start_dir)**: Core logic, executes `git rev-parse --show-toplevel`
- **Error handling**: Git not installed, not in repo, invalid output, non-absolute path
- **Path conversion**: stdout bytes → UTF-8 string → trimmed → PathBuf
### mod.rs
- **Re-exports**: Makes `find_repository_root()` and `find_repository_root_from()` public
## Critical Functions
```rust
find_repository_root() -> Result<PathBuf>
// Uses current_dir(), delegates to find_repository_root_from()
find_repository_root_from(start_dir: &Path) -> Result<PathBuf>
// Shells out: git rev-parse --show-toplevel
// Returns: Absolute path to repo root
```
## Git Command Execution
```
Command::new("git")
.args(["rev-parse", "--show-toplevel"])
.current_dir(start_dir) // caller-supplied directory
.output()
↓
Check output.status.success()
↓
Parse output.stdout as UTF-8
↓
Trim whitespace
↓
Verify path is absolute (runtime check)
↓
Convert to PathBuf
```
## Error Cases
| cwd inaccessible | `GitCommandFailed` | command, stderr, io source, suggestion |
| Git not in PATH | `GitCommandFailed` | Detects `ErrorKind::NotFound`, suggests install |
| Git exec fails (other) | `GitCommandFailed` | Includes start_dir in command string |
| Not in git repo | `NotInGitRepository` | Includes start_dir and git's stderr output |
| Invalid UTF-8 output | `GitInvalidUtf8` | Wraps `FromUtf8Error` source |
| Non-absolute path | `GitCommandFailed` | `InvalidData` io error, defensive check |
All variants carry a `suggestion` field consumed by `miette` diagnostics.
## Key Invariants
- Only shells out to git CLI (no libgit2 dependency)
- Returns absolute path to repository root (runtime-verified)
- Does not verify .git directory exists
- Does not read .git/config or other git internals
- Single invocation per CLI run (not cached)
## API Design
- `find_repository_root_from(&Path)` is the core function accepting any starting directory
- `find_repository_root()` is a convenience wrapper using `current_dir()`
- Separation enables testability, composability, and use from non-cwd contexts
## Performance Notes
- Single subprocess spawn (~1-2ms typical)
- Not cached (`Config::from_args()` calls once)
- Fast enough for CLI startup (no optimization needed)
## Security Considerations
- Uses `Command` with explicit args (no shell, no injection risk)
- Trusts git binary in system PATH
- Output sanitized via UTF-8 conversion + trim
- No arbitrary command execution
## Extension Points
- Caching: Wrap in `std::sync::OnceLock` for repeated calls
- libgit2 alternative: Replace with `git2` crate for pure-Rust impl
- Config reading: Add functions for `.gitconfig` parsing
- Branch/status: Add `current_branch()`, `is_dirty()` using same pattern