Use the Rust version declared in Cargo.toml, CPython 3.11 or newer, and the maturin version required by pyproject.toml. Free-threaded builds require CPython 3.14 or newer, as required by PyO3; CI checks 3.14t separately. The Rust dependencies must not compile C or C++ sources; a system linker and the normal Rust target libraries are still needed.
Git is a test reference implementation and fixture-creation tool, not a runtime implementation dependency. Tests must create disposable repositories and isolate inherited Git configuration and environment variables.
GitHub CI setup is authorized for this repository, including pushing the committed project and CI fixes to origin/main. Package publication, PyPI interaction, and changes to the upstream Gitoxide remote remain outside the task. Use cached dependencies when practical. For tools whose default cache is outside the writable workspace, choose a task-owned cache under /private/tmp or the repository.
The manifest pins public Gitoxide main revision
09f85be4e3fda42f3e8fd19c53a63758fdf6fb3d, which merged the Python binding
prerequisites in Gitoxide PR #3054.
No vendored crates or Cargo patches are needed. The integrated fixes provide:
| Crate | Behavior |
|---|---|
gix-transport |
Per-client reqwest TLS configuration with cached/lazy initialization and redirect policy. |
gix-ref |
Preserve raw reflog message bytes. |
gix-submodule |
Query submodule configuration using literal byte names. |
The latest crates.io release checked on 2026-10-12, gix 0.89.0, does not yet
contain these fixes. Package builds therefore use the public Git revision until
a compatible release includes them. The source distribution builds independently
of the developer's sibling checkout.
Opt in persistently for Python development builds:
export GIXPYTHON_GITOXIDE_PATH=/Users/byron/dev/github.com/GitoxideLabs/gitoxide.pygix
python3 etc/build.py
PYTHONPATH=python python3 -m unittest discover -s testsThis mode needs Cargo 1.97+ for its separate lockfile. Ordinary builds retain the
Rust 1.89 minimum. --gitoxide-path PATH overrides the environment selection;
--packaged ignores it and builds the pinned release dependencies. The two flags
are mutually exclusive. Invalid checkouts, older Cargo, and failed builds stop
with an error; they never fall back to release dependencies.
The builder patches Gitoxide crates for that command and compiles directly from
the checkout, including uncommitted edits. It seeds .cache/gitoxide-local/Cargo.lock
once from the committed lockfile, then lets Cargo update that development copy.
It does not edit Cargo.toml, the committed Cargo.lock, or .cargo/config.toml.
Only etc/build.py (and just recipes using it) consumes this selection; direct
Cargo lint/test commands and maturin package builds use release dependencies.
Local gix.__gix_revision__ reports checkout HEAD. Uncommitted changes are included
in the build but do not change that revision string. Every local invocation reads
HEAD again; Cargo tracks the revision environment value to rebuild provenance
when switching checkouts or returning to packaged mode. Packaged builds report
the pinned public revision containing all three fixes.
Continue using the local switch for upstream development. Once compatible
gix and gix-archive releases on crates.io contain
all three prerequisites, switch the manifest to those published versions,
update the committed lockfile and packaged revision in build.rs. The local
selector derives patch sources from the manifest, so it continues working with
crates.io dependencies.
Revalidate the supported feature groups and builds without C/C++ compilers at
that migration. macOS binary wheels and an independently buildable source
distribution remain the release artifacts.
See the local validation record for tested interpreters, artifacts, feature selections, and the limits of the checks performed.
The local builder uses Cargo and the selected interpreter directly; it does not query a Python package index:
python3 etc/build.py
PYTHONPATH=python python3 -m unittest discover -s tests
cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked --libThe justfile groups common commands under Development, Tests, and Releases,
following Gitoxide. Run just to list them. just build, just test, just check,
just fmt, just unit-tests, and just helper-tests cover the usual development
loop. Set PYTHON to select an installed interpreter.
just test-free-threaded /path/to/python3.14t builds and tests the free-threaded ABI with PYTHON_GIL=0.
The package test also verifies importing the extension keeps the GIL disabled.
With uv installed, open an IPython prompt with gix already imported and Tab
completion available, or run a Python command:
just run-release
just run-release 0.1.0
just run-release latest -c 'import gix; print(gix.__version__, gix.build_features())'
just run-release 0.1.0 /path/to/script.pyThis recipe downloads the latest compatible stable release, or the given version,
into an isolated uv virtualenv. It refreshes release resolution on each invocation,
uses the installed PYTHON interpreter, and requires a matching binary wheel;
it does not build sources or install build tools. Python runs in isolated mode
so inherited PYTHONPATH and the checkout's extension cannot shadow the release.
Interactive sessions also install IPython into that virtualenv and skip loading
IPython startup files and configuration. Script and -c arguments continue to
use ordinary Python without installing IPython.
Pass latest before any Python arguments; set PYTHON to an installed
free-threaded interpreter to try its wheel. These commands read PyPI when invoked.
Development builds continue using the local selection described above.
Use native cached fixtures through gix.testtools when
tests only inspect stable repositories. Python closures can create fixtures
or post-process scripted fixtures; writable helpers provide disposable copies
for mutations. Do not write into shared read-only fixture directories.
Each new binding should have a focused Python integration check against a disposable repository. Verify errors as well as success, both supported hash kinds, and any meaningful reduced feature configuration. Compare with Git when it provides an appropriate reference result.
Threading checks share repository handles between Python threads and verify actual work with the GIL disabled. Lazy-API checks consume only a prefix and confirm that later results have not been eagerly produced. Long-running operations expose pollable Progress.snapshot() and CancellationToken; they must propagate Python interruption and release resources when stopped.
Reference-update tests retain an old target, change the reference independently, and verify that the stale update fails. Expected targets must never be re-resolved at mutation time. Preserve the engine's documented transaction guarantees; do not claim stronger atomicity.
Keep native names and semantics. For example, Rust Repository::commit() creates a commit; Python must not reuse that name for a revision lookup. Native object-ID arguments may accept str/bytes revspecs through a shared private converter, without automatic peeling. Expected old targets in reference comparisons remain captured literal values.
Keep Python type information synchronized with bindings. Distinguish byte content from text, missing values from errors, and lazily yielded results from operations that inherently compute complete outcomes. Document compile-time capability choices without claiming that every enabled Rust feature is already bound.
The GitHub workflows run on pushes to main and pull requests targeting main, with manual dispatch also available. They use pinned actions, minimal token permissions, and checkouts without persisted credentials. A stable Tests pass check collects the required CI results.
Private repositories run zizmor with workflow annotations instead of code-scanning uploads. CodeQL runs only for public repositories; enabling it here while private requires GitHub Advanced Security and an update to its job condition.
The artifact workflow builds macOS 11+ candidates for Apple Silicon and Intel, for both the stable and free-threaded ABIs. It does not upload to PyPI, create a GitHub release, or change package/account settings. Ordinary CPython and free-threaded CPython require their respective ABI configurations. Linux and Windows CI provide portability checks only. They are not supported release platforms. Each release wheel is built from the source archive and tested after installation. See RELEASING.md for the separate manual publishing workflow and required account setup.
max-pure is the default aggregate. The independently selectable groups are declared in Cargo.toml; dependent features enable their required native capabilities automatically. Parallelism is unconditional. Select at least one of sha1 and sha256. signing enables native signing configuration and execution without requiring network support. http adds the blocking HTTP transport, and https adds the pure Rust TLS provider. The maturin configuration enables abi3 by default for ordinary CPython. PyO3 ignores that feature on free-threaded interpreters and builds their version-specific ABI instead.
python3 etc/build.py --no-default-features --features sha1
python3 etc/build.py --no-default-features --features sha256,revision,index
CC=/usr/bin/false CXX=/usr/bin/false CARGO_TARGET_DIR=target/no-c cargo build --lockedThe last command performs a fresh build with C and C++ compilation disabled; it still uses the system linker. Graviola supports selected x86-64 and AArch64 CPU features; unsupported hardware receives a clear HTTPS configuration error before a provider operation. Builds without HTTPS do not need that provider.
With maturin installed, these commands create local candidates without a Python index:
maturin build --locked --release --out dist --interpreter python3
maturin build --locked --release --out dist --interpreter /path/to/python3.14t
maturin sdist --out distInstall a matching wheel into a disposable environment with uv pip install --no-index --no-deps, then run the test suite without PYTHONPATH=python. Rebuild the wheel from the unpacked sdist to verify its support files and independent dependency resolution. The artifact workflow automates these checks. The stable ABI and free-threaded ABI are separate compatibility contracts; a wheel filename and successful import on one interpreter do not validate another ABI.