VersionDrift
Find every out-of-sync Git repo on your machine, without touching your work.
VersionDrift is a safety-first Git checkup for developers with more repositories than they can keep track of. It scans only the local directories you provide, separates safe fast-forwards from local work that must be protected, and records every decision locally.
$ version-drift scan ~/code --fetch
VersionDrift scanned 17 repositories under ~/code
✓ 10 in sync
↓ 3 safe to update
! 2 local work protected
↑ 1 ahead of upstream
↕ 1 diverged
Safe to update
docs 2 commits behind
website 4 commits behind
Protected. VersionDrift will not touch these
client-api dirty_worktree
prototype diverged_from_upstream
Working files changed: 0
Remote data: refreshed now
The example above illustrates the output format. It is not an adoption claim or benchmark.
Install
Install from PyPI:
uv tool install version-drift
# or
pipx install version-drift
For development:
git clone https://github.com/seojoonkim/version-drift.git
cd version-drift
python -m pip install -e .
Run your first Git checkup
version-drift scan ~/code --fetch
scan never modifies working files, the index, local commits, or branches. Without --fetch, it compares against local remote-tracking refs. With --fetch, it first runs a non-destructive fetch so the comparison is current.
Why VersionDrift?
A loop that runs git pull everywhere can stop on dirty work, create conflicts, or conceal work behind an automatic stash. VersionDrift takes the opposite approach:
- Discover repositories only inside roots you provide.
- Classify every repository before taking action.
- Protect anything dirty, ahead, diverged, ambiguous, or missing an upstream.
- Fast-forward only repositories proven safe at execution time.
- Record every decision locally as JSONL.
Safety contract
VersionDrift will never automatically:
- reset your working tree
- stash or drop changes
- clean untracked files
- merge or rebase branches
- force-pull or force-push
- guess a missing upstream
sync --apply is allowed only when a repository is clean, tracks an upstream, and is behind-only. VersionDrift checks the state again immediately before running exactly git pull --ff-only; if the snapshot changed, it aborts.
Commands
Scan one or more roots
version-drift scan ~/code ~/work
--fetch: refresh remote-tracking refs first--json: emit machine-readable output--check: return exit code 1 when drift exists--max-depth N: bound discovery depth
Set repeatable default roots with your platform path separator:
export VERSION_DRIFT_ROOTS="$HOME/code:$HOME/work"
version-drift scan
Inspect one repository
version-drift inspect ~/code/project --fetch --json
Preview safe synchronization
version-drift sync ~/code
Apply safe fast-forwards
version-drift sync ~/code --apply
Repositories with local work or ambiguous history remain untouched.
JSON and local decision events
Every scan and sync decision is appended to:
macOS: ~/Library/Application Support/VersionDrift/events.jsonl
Linux: ${XDG_STATE_HOME:-~/.local/state}/version-drift/events.jsonl
The state file defaults outside your Git repositories, so recording a checkup does not dirty the repository where you invoked VersionDrift. The current schema is version-drift/1. Choose another state root with --base-dir or VERSION_DRIFT_DIR; explicit state roots retain the legacy .version-drift/events.jsonl suffix for compatibility.
Working files changed is measured from repository HEAD and worktree snapshots taken before and after the command. A read-only scan should report 0; an applied fast-forward reports the files changed by the accepted upstream commits.
VersionDrift sends no telemetry and never uploads repository paths, remotes, or results.
VersionDrift, Gita, and myrepos
Gita and myrepos are strong choices for broad multi-repository management or arbitrary commands. VersionDrift is deliberately narrower: fail-closed diagnosis plus clean fast-forward-only reconciliation.
Choose VersionDrift when you want a read-only first run, a fixed non-destructive policy, apply-time revalidation, machine-readable decisions, and a local audit trail.
MemKraft integration
MemKraft can optionally use the standalone version_drift engine. VersionDrift remains independently installable and owns the version-drift command.
Contributing
Bug reports and focused pull requests are welcome. Safety invariants are part of the public API and cannot be weakened for convenience. See CONTRIBUTING.md.
License
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file version_drift-0.2.1.tar.gz.
File metadata
- Download URL: version_drift-0.2.1.tar.gz
- Upload date:
- Size: 16.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf8f56d4f1e4a252f16db466e975ea429abca569b564ff014ca9899848aef863
|
|
| MD5 |
62c351dd0d516537b3500f75e708e9dd
|
|
| BLAKE2b-256 |
8fa0324e6e03273e668fa957a38d9b0e1bd70f11e9933a2b26561787f7fc9b31
|
Provenance
The following attestation bundles were made for version_drift-0.2.1.tar.gz:
Publisher:
release.yml on seojoonkim/version-drift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
version_drift-0.2.1.tar.gz -
Subject digest:
bf8f56d4f1e4a252f16db466e975ea429abca569b564ff014ca9899848aef863 - Sigstore transparency entry: 2548567251
- Sigstore integration time:
-
Permalink:
seojoonkim/version-drift@b7479db3b6177209f989b2b7e2f1b3fdc01070c6 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/seojoonkim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b7479db3b6177209f989b2b7e2f1b3fdc01070c6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file version_drift-0.2.1-py3-none-any.whl.
File metadata
- Download URL: version_drift-0.2.1-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
deee6cfc7d7d4c2161b738eedac3ed5c3f082c92b44f64d140e25fdd2c7a7fb6
|
|
| MD5 |
90de6a5c22a540f38a53d284820ade4c
|
|
| BLAKE2b-256 |
143b71d2c3bb8d11969dbc253cb5ba0ed54263e86145267a1b177aa78aa51fdd
|
Provenance
The following attestation bundles were made for version_drift-0.2.1-py3-none-any.whl:
Publisher:
release.yml on seojoonkim/version-drift
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
version_drift-0.2.1-py3-none-any.whl -
Subject digest:
deee6cfc7d7d4c2161b738eedac3ed5c3f082c92b44f64d140e25fdd2c7a7fb6 - Sigstore transparency entry: 2548568078
- Sigstore integration time:
-
Permalink:
seojoonkim/version-drift@b7479db3b6177209f989b2b7e2f1b3fdc01070c6 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/seojoonkim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b7479db3b6177209f989b2b7e2f1b3fdc01070c6 -
Trigger Event:
push
-
Statement type: