GameSave-VCS provides automated version control for PC game saves, supporting both delta-based Git backups (via Dulwich), simple full-copy strategies, and an optimized chunked storage backend for massive save files.
- Python 3.13+
- Bazel (7.4.1 recommended) - for hermetic builds
- pip-tools (optional, for regenerating dependency locks)
pip install -e .Bazel ensures all dependencies (including Python 3.13 itself) are managed hermetically.
# Build the project
bazel build //...
# Run CLI
bazel run //:gamesave -- <command>A visually rich, 8-bit inspired interface for managing your saves.
bazel run //:gamesave -- tuiRequires textual and rich (included in Bazel build).
- Git (Default): Efficient delta-based backups using
dulwich. - Full-Copy: Simple timestamped directory mirrors with hard-link deduplication.
- Chunked: optimized for files >100MB; splits files into chunks to deduplicate internal changes.
- Inotify (Linux): Zero-polling, kernel-level event monitoring.
- Polling (Cross-platform): High-frequency hashing fallback for Windows/macOS.
We use pytest integrated with Bazel.
bazel run //:pytest -- tests/Because Bazel runs tests in a sandbox, pytest-cov requires the absolute path to the source tree to map coverage data correctly.
bazel run //:pytest -- tests/ --cov=$(pwd)/gamesave_vcs --cov-report=term-missingDependencies are locked in requirements_lock.txt. If you modify pyproject.toml, you must regenerate the lockfile.
We use pip-compile with specific flags to avoid circular dependencies in the Bazel graph (specifically stripping extras from transitive dependencies like markdown-it-py).
pip install pip-tools
pip-compile --extra test --strip-extras --generate-hashes --output-file=requirements_lock.txt pyproject.toml- Read-only Filesystem Errors: Tests must use the
tmp_pathfixture. Writing to absolute paths like/dstwill fail in the Bazel sandbox. - ModuleNotFoundError: Ensure the dependency is added to the
depsattribute inBUILD.bazelAND included inrequirements_lock.txt. - Async Test Failures: Ensure
pytest-asynciois installed and theasyncio_default_fixture_loop_scopeis considered if using older pytest versions.
| Command | Description | Example |
|---|---|---|
add <name> [path] |
Register a game | gamesave add EldenRing ~/saves/er |
backup <name> |
Manual backup | gamesave backup EldenRing |
watch <name> |
Start background monitor | gamesave watch EldenRing --interval 5 |
list |
Show backup history | gamesave list --game EldenRing |
restore [spec] |
Restore to state | gamesave restore repo@commit_hash |
tui |
Launch Retro Manager | gamesave tui |
- Config:
~/.gamesave-vcs/config.json - Backups:
~/.gamesave-vcs/backups/