βββ βββ
βββ
βββββββββ βββ βββ ββββββββββββ
βββ βββ βββ βββ βββ βββ
βββ βββ βββ βββ βββ βββ
βββ ββββ ββββββ βββ βββ
βββββββββ ββββ βββ βββββ
βββ
ββββββββ
Git-aware Virtual Environment Manager
Automates virtual environment management for Git repositories.
- β Vision
- π Motivation
- βοΈ What gvit does
- π» Installation
- π§© Usage
- π§ How it works
- βοΈ Configuration
- π§± Architecture
- π§ Roadmap
- π§ͺ Testing
- π€ Contributing
- βοΈ License
βOne repo, its own environment β without thinking about it.β
The goal of gvit CLI is to eliminate the need to manually create or update virtual environments. No more friction between version control and Python environment management. Git and Python should work together seamlessly β this tool makes it possible.
Have you ever cloned a project and had to do all this?
git clone https://github.com/someone/project.git
cd project
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtWith gvit, all of that happens automatically:
# Clone from scratch
gvit clone https://github.com/someone/project.git
# Or setup an existing repo
cd existing-project
gvit setupπ Environment created and dependencies installed!
- πͺ Automatically creates environments when cloning or initializing repos.
- π Multiple backends:
venv(built-in),conda,virtualenvanduvsupport. - π¦ Choose your package manager to install dependencies (
uvorpip). - π Auto-syncs environment on pull if there are any changes in the dependencies.
- β¬οΈ Installs dependencies from
requirements.txt,pyproject.toml, or custom paths. Supports extra dependencies (dev, test, etc.). - π Dependency validation:
commitcommand validates installed packages match declared dependencies. - π Status overview:
statuscommand shows both Git and environment changes in one view. - π Git command fallback: Use
gvitfor all git commands - unknown commands automatically fallback to git. - π Tracks environments in registry (
~/.config/gvit/envs/) with metadata and dependency hashes. - π Interactive environment management.
- π§ Cleans orphaned environments automatically with
prunecommand. - π Command logging: Automatic tracking of all command executions with analytics and error capture.
- π§ Remembers your preferences via local configuration (
~/.config/gvit/config.toml). - π§ Flexible configuration: per-repository (
.gvit.toml) or global settings. - π³ Visual command tree to explore available commands.
gvit globally, not in a project-specific virtual environment. Since gvit manages virtual environments, it needs to be available system-wide.
# Install pipx if you don't have it
python3 -m pip install --user pipx
python3 -m pipx ensurepath
# Install gvit with pipx
pipx install gvitWhy pipx?
- β Installs CLI tools in isolated environments
- β Makes them globally available
- β Prevents dependency conflicts
- β Easy to upgrade and uninstall
# Install globally (may require sudo on some systems)
pip install gvit
# Or with --user flag
pip install --user gvitgvit --version
# Should work from any directory
cd ~ && gvit --versionSet up your default preferences (interactive):
gvit config setupOr specify options directly:
# Use venv with uv
gvit config setup --backend venv --package-manager uv --python 3.11 --base-deps requirements.txt
# Or use conda with pip
gvit config setup --backend conda --package-manager pip --python 3.12
# Or use conda with uv
gvit config setup --backend conda --package-manager uv --python 3.11
# Or use virtualenv with pip
gvit config setup --backend virtualenv --package-manager pip --python 3.11
# Or use uv with uv
gvit config setup --backend uv --package-manager uv --python 3.11
# Or any other combination...The package manager (uv or pip) and the virtual environment backend (venv, virtualenv, conda or uv) serve different purposes but complement each other.
The backend defines where the Python environment lives and how it is isolated β for example, whether packages are stored in a venv directory, a virtualenv, or a Conda environment.
The package manager defines how dependencies are installed and resolved inside that environment β for example, using pip install for the standard Python installer or uv pip install for a faster, cache-optimized installation.
In gvit users can freely combine both layers (e.g., uv with venv, or pip with conda), since the package manager operates independently of the environment backend as long as it can target the correct Python interpreter.
Basic clone with automatic environment creation:
gvit clone https://github.com/user/repo.gitAdvanced options:
# Custom environment name
gvit clone https://github.com/user/repo.git --venv-name my-env
# Specify Python version
gvit clone https://github.com/user/repo.git --python 3.12
# Install extra dependencies from pyproject.toml
gvit clone https://github.com/user/repo.git --extra-deps dev,test
# Skip dependency installation
gvit clone https://github.com/user/repo.git --no-deps
# Force overwrite existing environment
gvit clone https://github.com/user/repo.git --force
# Verbose output
gvit clone https://github.com/user/repo.git --verboseSimilar to git init but with environment setup:
# In current directory
gvit init
# In specific directory (--target-dir)
gvit init -t my-project
# With remote repository
gvit init --remote-url https://github.com/user/my-project.git
# With all options
gvit init -t my-project \
--remote-url https://github.com/user/my-project.git \
--python 3.12 \
--extra-deps dev,testIf you already have a cloned repository and want to set up the environment:
# In the repository directory
cd my-existing-repo
gvit setup
# Or specify a different directory (--target-dir)
gvit setup -t path/to/repo
# With custom options
gvit setup --python 3.12 --extra-deps dev,test
# Skip dependency installation
gvit setup --no-depsSmart git pull that automatically detects and reinstalls changed dependencies:
# Pull and auto-update dependencies if changed
gvit pull
# Pull without checking dependencies
gvit pull --no-deps
# Force reinstall all dependencies even if unchanged
gvit pull --force-deps
# Pass options to git pull
gvit pull --rebase origin mainSmart git commit that validates your installed packages match your dependency files:
# Commit with automatic validation
gvit commit -m "Add new feature"
# Skip validation if needed
gvit commit --skip-validation -m "Quick fix"
# Pass any git commit options
gvit commit -a -m "Update everything"
gvit commit --amendWhat it validates:
- β Detects added packages not declared in dependency files.
- β Detects removed packages still declared in dependency files.
- β Detects version changes not reflected in pinned versions.
- β
Works with
requirements.txt,pyproject.toml, and custom paths. - β Shows detailed diff of package changes (added/removed/modified).
Combined view of Git status and environment changes:
# Show just repository (same as `git status`)
gvit status
# Show repository and environment status
gvit status -e
# In a specific directory
gvit status -e --target-dir path/to/repo
What it shows:
- π Repository Status: Standard
git statusoutput. - π Environment Status: Packages added/removed/modified since last tracking.
- β Clean overview of both code and dependency changes.
- β‘ Quick way to see if you need to update dependency files.
# Add extra dependency groups to local config
gvit config add-extra-deps dev requirements-dev.txt
gvit config add-extra-deps test requirements-test.txt
# Remove extra dependency groups
gvit config remove-extra-deps dev
# Show current configuration
gvit config show# List all tracked environments
gvit envs list
# Show details of a specific environment
gvit envs show my-env
# Remove an environment (registry and backend)
gvit envs delete my-env
# Reset an environment (recreate and reinstall dependencies)
gvit envs reset my-env
# Reset without reinstalling dependencies
gvit envs reset my-env --no-deps
# Show activate command for current repository's environment
gvit envs show-activate
# Show activate command for a specific environment
gvit envs show-activate --venv-name my-env
# Show activate command with relative path (venv/virtualenv/uv only)
gvit envs show-activate --relative
# Activate environment directly (recommended)
eval "$(gvit envs show-activate)"
# Show deactivate command for current repository's environment
gvit envs show-deactivate
# Show deactivate command for a specific environment
gvit envs show-deactivate --venv-name my-env
# Deactivate environment directly (recommended)
eval "$(gvit envs show-deactivate)"
# Clean up orphaned environments (repos that no longer exist)
gvit envs prune
# Preview what would be removed
gvit envs prune --dry-run
# Auto-confirm removal
gvit envs prune --yesInteractive Environment Management
# Open an interactive menu to manage your environments
gvit envs managegvit automatically tracks all command executions for analytics and debugging:
# Show recent command logs
gvit logs show
# Limit number of entries
gvit logs show --limit 10
# Filter by environment
gvit logs show --venv-name my-env
# Show full commands
gvit logs show --verbose
# Show error messages
gvit logs show --errors
# Combine filters
gvit logs show --limit 20 --venv-name my-env --errors --verbose
# Show logs statistics
gvit logs stats
# Clear all logs
gvit logs clear
# Clear with auto-confirm
gvit logs clear --yes
# Enable/disable logging
gvit logs enable
gvit logs disable
# Configure logging
gvit logs config --show
gvit logs config --max-entries 500
gvit logs config --ignore "status,tree"What gets logged:
- β±οΈ Timestamp: When the command was executed.
- π― Command: Short command name (e.g.,
status,envs.list). - π Environment: Associated environment name (if applicable).
- β‘ Duration: Execution time in milliseconds.
- β Status: Success (β ) or failure (β).
- π Full Command: Complete command with all arguments (verbose mode).
- β Error: Error message (if command failed).
Configuration:
- π§ Logs stored in
~/.config/gvit/logs/commands.csv. - π’ Default max entries: 1000 (configurable).
- π« Ignored commands by default (configurable): read-only commands like
logs.show,envs.list,status,tree. - ποΈ Automatic log rotation when limit exceeded.
gvit can replace git in your daily workflow! Any command not implemented in gvit automatically falls back to git:
# These work exactly like git commands
gvit add file.py
gvit diff --stat
gvit log --oneline -10
gvit branch -a
gvit checkout -b feature
gvit push origin main
gvit stash
gvit rebase main
# Complete workflow with gvit
gvit status # gvit's enhanced status
gvit add .
gvit commit -m "feat" # gvit's validated commit
gvit pushHow it works:
- π
gvitchecks if the command is implemented (clone, commit, init, pull, status, etc.). - β
If implemented: runs
gvit's enhanced version. - π If not implemented: automatically forwards to
git. - π― Seamless experience - just replace
gitwithgvit.
Git aliases support:
gvit automatically resolves your git aliases and uses gvit's enhanced versions when available!
# If you have git aliases configured:
# git config --global alias.st status
# git config --global alias.ci commit
# git config --global alias.co checkout
# These will use gvit's enhanced versions
gvit st -e # β gvit status (with environment tracking)
gvit ci -m # β gvit commit (with validation)
# This will use git directly
gvit co main # β git checkout main- π Respects all your existing git aliases.
- π Automatically uses
gvit's enhanced versions when the alias resolves to a gvit command. - π Falls back to git for other commands.
# Show all available commands in tree structure
gvit tree
# Output
gvit
βββ clone
βββ commit
βββ config
β βββ add-extra-deps
β βββ remove-extra-deps
β βββ setup
β βββ show
βββ envs
β βββ delete
β βββ list
β βββ manage
β βββ prune
β βββ reset
β βββ show
β βββ show-activate
β βββ show-deactivate
βββ init
βββ logs
β βββ clear
β βββ config
β βββ disable
β βββ enable
β βββ show
β βββ stats
βββ pull
βββ setup
βββ status
βββ treegvit clone β Clones repository + creates environment:
- Clones the repository using standard
git clone. - Detects repository name from URL (handles
.gitsuffix correctly). - Proceeds to environment setup.
gvit init β Initializes Git repository + creates environment:
- Initializes Git repository using
git init. - Optionally adds remote if
--remote-urlis provided. - Proceeds to environment setup.
gvit setup β Creates environment for existing repository:
- Verifies Git repository exists in target directory.
- Detects remote URL if available.
- Proceeds to environment setup.
gvit pull β Pulls changes and syncs dependencies:
- Finds tracked environment for current repository.
- Runs
git pullwith any extra arguments you provide. - Compares dependency file hashes (stored in registry vs. current files).
- Reinstalls only changed dependencies automatically.
- Updates registry with new hashes.
gvit commit β Validates dependencies before committing:
- Finds tracked environment for current repository.
- Compares pip freeze outputs (stored snapshot vs. current state).
- Detects package changes: added, removed, modified versions.
- Validates dependency files to ensure changes are reflected.
- Shows detailed report of discrepancies (if any).
- Runs
git commitwith any extra arguments you provide.
gvit status β Shows combined repository and environment status:
- Displays
git statusoutput for repository changes. - Finds tracked environment for current repository.
- Compares pip freeze outputs (stored snapshot vs. current state).
- Shows package changes: added, removed, modified versions.
- Provides clean overview of both code and dependency changes.
- Creates virtual environment using your preferred backend:
venv: Python's built-in venv module (creates.venv/, or the defined environment name, in repo).virtualenv: Enhanced virtual environments (creates.venv/, or the defined environment name, in repo).conda: Conda environments (centralized management).uv: uv environments (an extremely fast Python package and project manager, written in Rust).
- Resolves dependencies with priority system:
- CLI arguments (highest priority).
- Repository config (
.gvit.toml). - Local config (
~/.config/gvit/config.toml). - Default values (lowest priority).
- Installs dependencies from:
pyproject.toml(with optional extras support).requirements.txtor custom paths.- Multiple dependency groups (_base, dev, test, etc.).
- Tracks environment in registry:
- Saves environment metadata to
~/.config/gvit/envs/{env_name}.toml. - Records dependency file hashes for change detection.
- Stores complete pip freeze snapshot for validation.
- Stores repository information (path, URL).
- Saves environment metadata to
- Validates and handles conflicts:
- Detects existing environments.
- Offers options: rename, overwrite, or abort.
- Auto-generates unique names if needed.
Global preferences: ~/.config/gvit/config.toml
[gvit]
backend = "venv" # or "conda", "virtualenv", "uv"
python = "3.11"
[deps]
_base = "requirements.txt"
dev = "requirements-dev.txt"
test = "requirements-test.txt"
[logging]
enabled = true
max_entries = 1000 # Maximum log entries before rotation
ignored = ["logs.show", "status", "tree"]
[backends.venv]
name = ".venv" # Directory name for venv (default: .venv)
[backends.virtualenv]
name = ".venv" # Directory name for virtualenv (default: .venv)
[backends.uv]
name = ".venv" # Directory name for uv (default: .venv)
[backends.conda]
path = "/path/to/conda" # Optional: custom conda pathEnvironment tracking: ~/.config/gvit/envs/{env_name}.toml
[environment]
name = "my-project"
backend = "conda"
path = "/Users/user/miniconda3/envs/gvit"
python = "3.11"
created_at = "2025-01-22T20:53:01.123456"
[repository]
path = "/Users/user/projects/my-project"
url = "https://github.com/user/my-project.git"
[deps]
_base = "requirements.txt"
dev = "requirements-dev.txt"
[deps.installed]
_base_hash = "a1b2c3d4e5f6g7h8" # SHA256 hash for change detection
dev_hash = "i9j0k1l2m3n4o5p6"
_freeze_hash = "q7r8s9t0u1v2w3x4" # SHA256 hash of pip freeze output
_freeze = """ # Complete pip freeze snapshot for validation
package1==1.0.0
package2==2.3.4
"""
installed_at = "2025-01-22T20:53:15.789012"Per-project settings: .gvit.toml (in repository root)
[gvit]
python = "3.12" # Override Python version for this project
[deps]
_base = "requirements.txt"
dev = "requirements-dev.txt"
internal = "requirements-internal.txt"Or use pyproject.toml (tool section):
[tool.gvit]
python = "3.12"
[tool.gvit.deps]
_base = "pyproject.toml"gvit/
βββ src/gvit/ # Source code
β βββ cli.py # CLI entry point & command routing
β βββ env_registry.py # Environment registry management
β βββ git.py # Git operations & alias resolution
β βββ commands/ # Command implementations
β β βββ clone.py # Clone repos with auto environment setup
β β βββ init.py # Initialize new Git repos + environments
β β βββ setup.py # Setup environments for existing repos
β β βββ pull.py # Smart pull with dependency sync
β β βββ commit.py # Commit with dependency validation
β β βββ status.py # Git + environment status overview
β β βββ tree.py # Visual command structure explorer
β β βββ config.py # Configuration management
β β βββ envs.py # Environment management (list, delete, etc)
β βββ backends/ # Backend implementations
β β βββ common.py # Shared backend functions
β β βββ venv.py # Python's built-in venv
β β βββ virtualenv.py # virtualenv
β β βββ uv.py # uv (faster, more features)
β β βββ conda.py # conda environments
β βββ utils/ # Utilities & helpers
β βββ exceptions.py # Custom exception classes
β βββ globals.py # Constants and defaults
β βββ schemas.py # Type definitions (TypedDict)
β βββ utils.py # Helper functions
β βββ validators.py # Input validation
βββ tests/ # Test suite (49 tests, 33% coverage)
β βββ unit/ # Unit tests (38 tests)
β β βββ test_env_registry.py
β β βββ test_backends/
β β βββ test_utils/
β βββ integration/ # Integration tests (11 tests)
β β βββ test_envs.py
β βββ fixtures/ # Test fixtures
β βββ conftest.py # Shared pytest fixtures
β βββ README.md # Complete testing guide
βββ .coveragerc # Coverage configuration
βββ pytest.ini # Pytest configuration
βββ pyproject.toml # Project metadata & dependencies
βββ README.md # This file
cli.py- Entry point with Typer app, command routing, and git fallback.env_registry.py- Manages environment tracking in~/.config/gvit/envs/.git.py- Git operations, alias resolution, and git command execution.
Each command is self-contained with its own logic:
Abstraction for different virtual environment tools.
Support utilities (configuration paths, defaults, constants, custom exceptions, etc.).
1. User runs command
β
2. cli.py parses with Typer
β
3. Command module executes logic
β
4. Backend creates/manages environment
β
5. env_registry.py tracks metadata
β
6. Files saved to ~/.config/gvit/
CLI Arguments (highest priority)
β
Repository Config (.gvit.toml or pyproject.toml)
β
Local Config (~/.config/gvit/config.toml)
β
Defaults (globals.py)
| Feature | Status | Description |
|---|---|---|
| Clone command | β | Full repository cloning with environment setup |
| Init command | β | Initialize new Git repos with environment setup |
| Setup command | β | Create environment for existing repositories |
| Pull command | β | Smart git pull with automatic dependency sync |
| Commit command | β | Git commit with automatic dependency validation |
| Tree command | β | Visual command structure explorer |
| venv backend | β | Python's built-in venv support |
| conda backend | β | Complete conda integration |
| virtualenv backend | β | Complete virtualenv integration |
| uv backend | β | Complete uv integration |
| Config management | β | setup, add-extra-deps, remove-extra-deps, show |
| Environment registry | β | Track environments with metadata, dependency hashes, and freeze snapshots |
| Environment management | β | list, show, delete, prune, reset, show-activate, show-deactivate commands |
| Orphan cleanup | β | Automatic detection and removal of orphaned environments |
| Dependency resolution | β | Priority-based resolution (CLI > repo > local > default) |
| pyproject.toml support | β | Install base + optional dependencies (extras) |
| Requirements.txt support | β | Standard pip requirements files |
| Custom dependency paths | β | Flexible path specification via config or CLI |
| Environment validation | β | Detect conflicts, offer resolution options |
| TypedDict schemas | β | Full type safety with typed configuration schemas |
| Dependency validation | β | Validate installed packages match declared dependencies on commit |
| Status command | β | Combined view of Git status and environment changes |
| Git command fallback | β | Automatic fallback to git for unknown commands |
| Version | Status | Description |
|---|---|---|
| 0.6.0 | π Planned | Add checkout command to switch branches and sync deps |
| 0.6.0 | π Planned | gvit sync command for full dependency refresh |
| 1.0.0 | π― Goal | Stable release with all core features |
gvit has a comprehensive test suite with 49 tests and growing coverage.
When testing CLI commands built with Typer (or Click), the test runner internally captures and redirects standard output (stdout). At the same time, pytest also captures stdout by default. This double capture can interfere with how Typer detects and writes to the terminal, causing missing or inconsistent output during tests. Running tests with the -s flag disables pytestβs output capture, allowing Typerβs console output (including echo and secho) to behave normally.
In short, use pytest -s to ensure CLI tests run with the same behavior as when executing the commands directly in a real terminal.
# Install test dependencies
pip install -e ".[test]"
# Run all tests
pytest -s
# Run with coverage report
pytest -s --cov=src/gvit --cov-report=html
open tests/htmlcov/index.htmlTest Suite:
- β 38 unit tests (fast, isolated)
- β 11 integration tests (end-to-end)
- β 33% coverage (target: 80%+)
- β Fully isolated (no system side effects)
Documentation: See tests/README.md for the complete testing guide including:
- How to run and write tests.
- Coverage analysis.
- Available fixtures.
- Best practices.
Contributions are welcome! Areas we'd love help with:
- Additional backends (pyenv, poetry).
checkoutand other commands.- Cross-platform testing.
- Documentation improvements.
- Writing tests - See tests/README.md
Open an issue or submit a pull request on GitHub.
MIT Β© 2025




