gitoxide-python
Fast, safe, pure-Rust Git for Python — bindings to the gitoxide engine, and a modern alternative to GitPython.
gitoxide (the gix crate) is a next-generation, pure-Rust implementation of
Git. This project exposes that engine to Python through PyO3
and ships as pre-built wheels via maturin, so you get:
| GitPython | pygit2 | gitoxide-python | |
|---|---|---|---|
| Backend | shells out to the git CLI |
C libgit2 |
pure-Rust gix |
| Walk 10,000 commits | 323 ms (a git subprocess, then parsing) |
389 ms | 129 ms |
| Install | needs git on PATH |
needs a C toolchain / system libgit2 |
pip install, self-contained wheels |
| Memory safety | n/a (subprocess) | C | Rust |
Nothing here shells out to the git CLI. A repository that configures a
clean/smudge filter (Git LFS, say) will still have that filter program executed
when blame reads such a file — exactly as git itself would.
Status: alpha. The binding surface is small but real. It currently covers read-oriented workflows (open/discover, HEAD, history walk, refs, branches, tags, blob reads) — the operations DevOps tooling reaches for most. See Scope for what is and isn't wrapped yet.
Installation
pip install gitoxide
Pre-built wheels are published for Linux (manylinux, x86_64 + aarch64), macOS
(x86_64 + Apple Silicon), and Windows — no Rust toolchain or system libgit2
required.
Quick start
import gitoxide
repo = gitoxide.open(".") # or gitoxide.discover(".")
print(repo.git_dir) # .../my-project/.git
print(repo.workdir) # .../my-project (None if bare)
print(repo.is_bare) # False
print(repo.head_name) # 'main' (None if detached)
# The commit at HEAD
head = repo.head_commit()
print(head.short_id, head.summary)
print(head.author.name, head.author.email, head.author.time)
# Walk history (reverse-chronological), like `git log`
for commit in repo.commits(max_count=10):
print(commit.short_id, commit.author.name, commit.summary)
# Resolve a revspec to an object id
print(repo.rev_parse("HEAD~2"))
print(repo.rev_parse("main"))
# Branches, tags, and all references
print(repo.branches()) # ['main', 'dev', ...]
print(repo.tags()) # ['v1.0.0', ...]
for ref in repo.references():
print(ref.name, "->", ref.target)
# Read a file's content at a revision
readme = repo.read_blob("HEAD:README.md")
print(readme.decode())
# Blame a file: which commit last touched each line
for hunk in repo.blame("README.md"):
print(f"{hunk.start_line}-{hunk.end_line}\t{hunk.short_id}")
Performance
Median time per operation on a full clone of python/cpython — 130,654 commits, 531 references — on an Apple M2:
| Operation | GitPython | pygit2 | gitoxide-python |
|---|---|---|---|
| Walk 10,000 commits | 323 ms | 389 ms | 129 ms |
| List 531 references | 74.4 ms | 1.31 ms | 3.45 ms |
| Read a 8.7 KB blob | 179 µs | 188 µs | 48.8 µs |
Resolve HEAD~100 |
3.02 ms | 28.2 µs | 602 µs |
| Read the HEAD commit | 87.3 µs | 22.6 µs | 34.2 µs |
| Open the repository | 129 µs | 111 µs | 146 µs |
| Blame a 475-line file | 1.07 s | 28.4 s | 1.85 s |
Faster than GitPython on five of these seven, a tie on open, and a loss on
blame — where GitPython is really git's own C implementation in a subprocess,
and gix's younger blame has not caught it yet. Against pygit2 the split runs the
other way: history walking and blame are several times faster here, while
pygit2 still wins the single-object lookups it has spent fifteen years tuning.
The three libraries are checked against each other on every operation — same
commit ids, same blob bytes, same line count — so a fast wrong answer can't win.
benchmarks/ has the exact call made against each library, the
caveats, and a one-command way to reproduce it on your own machine.
Migrating from GitPython
Common operations, side by side:
| GitPython | gitoxide-python |
|---|---|
from git import Repo |
import gitoxide |
repo = Repo(path) |
repo = gitoxide.open(path) |
Repo(path, search_parent_directories=True) |
gitoxide.discover(path) |
repo.head.commit |
repo.head_commit() |
repo.active_branch.name |
repo.head_name |
repo.iter_commits("main", max_count=10) |
repo.commits("main", max_count=10) |
repo.commit("HEAD~2") |
repo.commit("HEAD~2") |
repo.rev_parse("main").hexsha |
repo.rev_parse("main") |
[b.name for b in repo.branches] |
repo.branches() |
[t.name for t in repo.tags] |
repo.tags() |
c.hexsha, c.summary, c.author.name |
c.id, c.summary, c.author.name |
The key difference is what happens underneath: GitPython's iter_commits spawns
a git rev-list subprocess; gitoxide-python walks the object database
in-process in Rust.
API
Module functions
gitoxide.open(path) -> Repositorygitoxide.discover(path) -> Repository— searchpathand its parentsgitoxide.init(path, bare=False) -> Repositorygitoxide.gix_version() -> str
Repository
Properties: git_dir, workdir, is_bare, is_shallow, head_id,
head_name, head_is_detached.
Note:
head_nameandhead_is_detachedaccess theHEADreference and may raiseGitoxideErrorif it is inaccessible (e.g., corrupted repository).is_shallowmay raiseGitoxideErrorif the configured shallow-file path cannot be represented on the platform. Other properties never raise.
Methods: head_commit(), rev_parse(spec), commit(rev),
commits(rev=None, max_count=None), references(), branches(), tags(),
read_blob(rev), blame(path, rev=None).
Commit
id, short_id, tree_id, message, summary, author, committer,
parents.
Signature
name, email, time (Unix seconds), offset (UTC offset seconds).
Reference
name, shorthand, target.
BlameHunk
start_line, end_line, line_count, orig_start_line, commit_id,
short_id. Line numbers are 1-based and inclusive, matching git blame.
Consecutive lines from the same commit are grouped into one hunk.
All errors (from any function or method) are raised as
gitoxide.GitoxideError.
Scope
This is a binding, not a reimplementation: it exposes a slice of what the gix
engine already does. Today that slice is:
- Wrapped: open / discover / init, HEAD, history walk, rev-parse, references, branches, tags, blob reads, and blame.
- Not wrapped yet: diff & status, tree listing, writing commits and the index, and clone / remote operations.
The engine supports much more; these are simply the parts this binding hasn't
surfaced yet. Issues and pull requests that expose more of gix are welcome —
see Contributing.
Contributing
The binding layer lives in a single src/lib.rs and maps closely
onto the gix API, so adding a method is usually a small, self-contained change.
Building from source requires a Rust toolchain (this is also the path used when installing the sdist on a platform without a pre-built wheel):
python -m venv .venv && source .venv/bin/activate
pip install maturin pytest
maturin develop # build the extension into the venv
pytest -q # run the test suite
cargo fmt --all # format Rust
cargo clippy --all-targets -- -D warnings
The tests generate a throwaway git repository on the fly (see
tests/conftest.py), so they need git on PATH but
touch nothing outside a temp directory.
License
Licensed under either of Apache License 2.0 or MIT license at your option, to match the upstream gitoxide project.
Metadata
Release files for gitoxide 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gitoxide-0.4.1.tar.gz | 47.4 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| gitoxide-0.4.1-cp39-abi3-win_amd64.whl | CPython 3.9 | abi3 | Windows x86-64 | Details |
| gitoxide-0.4.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| gitoxide-0.4.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| gitoxide-0.4.1-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
| gitoxide-0.4.1-cp39-abi3-macosx_10_12_x86_64.whl | CPython 3.9 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 10.8 MB
Release files / gitoxide-0.4.1.tar.gz
| Download URL | gitoxide-0.4.1.tar.gz |
|---|---|
| Size | 47.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
487850e4bbe4619a0d310c31d76a8c59cf3d7d383b63d9cbc197127f987a7643
|
|
BLAKE2b-256 checksum How to use checksums |
a4f9687bdf34a6b0bf9cec20de9e1a39fb3194bbee612cdb8c075f4a869722de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / gitoxide-0.4.1-cp39-abi3-win_amd64.whl
| Download URL | gitoxide-0.4.1-cp39-abi3-win_amd64.whl |
|---|---|
| Size | 2.1 MB |
| Tags | CPython 3.9 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
4dca362a16ad739a00c2c494efe21fe3d7e77142bc4c6ac0cbcb1c23d2382fb3
|
|
BLAKE2b-256 checksum How to use checksums |
b978aaa438c673f7811e09f8daa9986496ec60a523fe393978a08da611703aa4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / gitoxide-0.4.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | gitoxide-0.4.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.2 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
067be1934f7db7b130f5a28cc7404b05afa80aeb62f590eff0f0ed3f3c8741be
|
|
BLAKE2b-256 checksum How to use checksums |
d95eeab1a57bd0d72c783c20e2f6716231fcd9b730b5dcbcccd0b336e5c8d28f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / gitoxide-0.4.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | gitoxide-0.4.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 2.2 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
92568dc19d6dcd8a3c1f1ce418ad8ad45557481311eed77c6ade8e2046c3895f
|
|
BLAKE2b-256 checksum How to use checksums |
71c57f156a13f5c51086d9a8a1b550da9d4c714eca88f022aa74084d9bfbed0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / gitoxide-0.4.1-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | gitoxide-0.4.1-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
2412c0c3b74468d3785303f2d1f02f0f9a5c00e83fdfc9ff0b0e6ccf8c45dcec
|
|
BLAKE2b-256 checksum How to use checksums |
1d25fc07a838b21f938e645a9167b2279469de8108751010eca8a8788b76a124
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / gitoxide-0.4.1-cp39-abi3-macosx_10_12_x86_64.whl
| Download URL | gitoxide-0.4.1-cp39-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 2.1 MB |
| Tags | CPython 3.9 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
d8fc5faf13b3b82cb08d6f586e5b898d6e76fccf499ddae91d8c0f0c1f0250ef
|
|
BLAKE2b-256 checksum How to use checksums |
a7f470648c5fdc5f169e68ce414e3889ca036c44a0930a738c7a81621228ef4d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency log