libvcs parses and validates Git, Mercurial, and Subversion URLs, wraps each VCS's command-line tool in a typed Python object, and synchronizes a local checkout against a remote — cloning it if it does not exist, fetching and updating it if it does. It also ships a pytest plugin for creating disposable repositories in your own test suite.
It powers vcspull, which uses it to sync many repositories from a single config file.
Features at a Glance
- Repository synchronization: One
obtain()/update_repo()call clones a repository if it is missing and fetches it if it already exists, the same way for git, hg, and svn. - Command abstraction: Call
git,hg, andsvnthrough typed Python objects instead of shelling out and parsing text yourself. - URL parsing: Parse, validate, and transform VCS URLs, including
SCP-style
git@host:pathremotes. - Pytest fixtures: Create disposable local git, hg, and svn repositories for your own tests, with per-test isolation.
Installation
$ pip install libvcs
With uv:
$ uv add libvcs
Try it interactively:
$ uvx --with libvcs ipython
libvcs is pre-1.0: a minor version bump (0.45 to 0.46) may change the public API. Pin a version range in projects to avoid surprises:
# pyproject.toml
dependencies = ["libvcs>=0.45,<0.46"]
Usage
1. Synchronize Repositories
GitSync, HgSync, and SvnSync give the same two calls regardless of the
underlying VCS: obtain() clones if the path does not exist yet, and
update_repo() does that or fetches and updates an existing checkout — call
it either way and let libvcs decide.
Learn more about Synchronization
import pathlib
from libvcs.sync.git import GitSync
# Define your repository
repo = GitSync(
url="https://github.com/vcs-python/libvcs",
path=pathlib.Path.cwd() / "libvcs",
remotes={"gitlab": "https://gitlab.com/vcs-python/libvcs"},
)
# Clone (if not exists) or fetch & update (if exists)
result = repo.update_repo()
if result.ok:
print(f"Current revision: {repo.get_revision()}")
else:
for error in result.errors:
print(f"Sync failed at {error.step}: {error.message}")
2. Command Abstraction
Git, Hg, and Svn wrap the binary directly — each call maps to one
subprocess invocation of the real VCS tool, so there is no divergent
reimplementation to trust. Branches, remotes, and tags are also reachable
through QueryList, which filters like a Django ORM queryset.
Learn more about Command Abstraction
import pathlib
from libvcs.cmd.git import Git
# Initialize the wrapper
git = Git(path=pathlib.Path.cwd() / "libvcs")
# Run commands directly
git.clone(url="https://github.com/vcs-python/libvcs.git")
git.checkout(ref="master")
# Traverse branches with ORM-like filtering
git.branches.create("feature/new-gui")
print(git.branches.ls()) # Returns QueryList for filtering
# Target specific entities with contextual commands
git.remotes.set_url(name="origin", url="git@github.com:vcs-python/libvcs.git")
git.tags.create(name="v1.0.0", message="Release version 1.0.0")
3. URL Parsing
GitURL, HgURL, and SvnURL parse and validate VCS URLs — including
SCP-style git remotes — without hand-written regular expressions, and let
you rewrite a parsed URL's parts back into a valid URL string.
from libvcs.url.git import GitURL
# Validate URLs
GitURL.is_valid(url="https://github.com/vcs-python/libvcs.git") # True
# Parse complex URLs
url = GitURL(url="git@github.com:vcs-python/libvcs.git")
print(url.user) # 'git'
print(url.hostname) # 'github.com'
print(url.path) # 'vcs-python/libvcs'
# Transform URLs
url.hostname = "gitlab.com"
print(url.to_url()) # 'git@gitlab.com:vcs-python/libvcs.git'
4. Testing with Pytest
The bundled pytest plugin builds a real, temporary VCS repository per test and tears it down after — no network access, no shared state between tests. A VCS's fixtures are only available when its binary is installed.
Learn more about Pytest Fixtures
import pathlib
from libvcs.pytest_plugin import CreateRepoFn
from libvcs.sync.git import GitSync
def test_my_git_tool(create_git_remote_repo: CreateRepoFn, tmp_path: pathlib.Path):
# Spin up a real, temporary Git server
git_server = create_git_remote_repo()
# Clone it to a temporary directory
checkout_path = tmp_path / "checkout"
repo = GitSync(path=checkout_path, url=f"file://{git_server}")
repo.obtain()
assert checkout_path.exists()
assert (checkout_path / ".git").is_dir()
Project Information
- Python Support: 3.10+
- VCS Support: Git (including AWS CodeCommit), Mercurial (hg), Subversion (svn)
- License: MIT
Links & Resources
- Documentation: libvcs.git-pull.com
- Source Code: github.com/vcs-python/libvcs
- Issue Tracker: GitHub Issues
- Changelog: History
- PyPI: pypi.org/project/libvcs
Support
Your donations fund development of new features, testing, and support.
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 libvcs-0.46.0.tar.gz.
File metadata
- Download URL: libvcs-0.46.0.tar.gz
- Upload date:
- Size: 689.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
044736940c9c7db30ca070c87c681249933667eae603e46e75ac7519a3f4414c
|
|
| MD5 |
406e3e9a6e89acd234d48feff6cd5db0
|
|
| BLAKE2b-256 |
a2156a18d8dc2c44ce4f11fac06d03a2ea307c216deb32b4dbfc1cf3b986fb9b
|
Provenance
The following attestation bundles were made for libvcs-0.46.0.tar.gz:
Publisher:
tests.yml on vcs-python/libvcs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
libvcs-0.46.0.tar.gz -
Subject digest:
044736940c9c7db30ca070c87c681249933667eae603e46e75ac7519a3f4414c - Sigstore transparency entry: 2652558530
- Sigstore integration time:
-
Permalink:
vcs-python/libvcs@352d9fda5d333ff4bad0a263b80dd1040b2c2e50 -
Branch / Tag:
refs/tags/v0.46.0 - Owner: https://github.com/vcs-python
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@352d9fda5d333ff4bad0a263b80dd1040b2c2e50 -
Trigger Event:
push
-
Statement type:
File details
Details for the file libvcs-0.46.0-py3-none-any.whl.
File metadata
- Download URL: libvcs-0.46.0-py3-none-any.whl
- Upload date:
- Size: 108.1 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 |
285f4e4c87db31922dd7ab523a306492a4618fd7c50274c14cd7229d3a634e9b
|
|
| MD5 |
50ea52fe083e769152dd0e465f9db6f0
|
|
| BLAKE2b-256 |
bd4e004f622d8b2865ebcb00870b0254ccc20de177b7fd35fca26f6afbb04056
|
Provenance
The following attestation bundles were made for libvcs-0.46.0-py3-none-any.whl:
Publisher:
tests.yml on vcs-python/libvcs
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
libvcs-0.46.0-py3-none-any.whl -
Subject digest:
285f4e4c87db31922dd7ab523a306492a4618fd7c50274c14cd7229d3a634e9b - Sigstore transparency entry: 2652558549
- Sigstore integration time:
-
Permalink:
vcs-python/libvcs@352d9fda5d333ff4bad0a263b80dd1040b2c2e50 -
Branch / Tag:
refs/tags/v0.46.0 - Owner: https://github.com/vcs-python
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
tests.yml@352d9fda5d333ff4bad0a263b80dd1040b2c2e50 -
Trigger Event:
push
-
Statement type: