Dulwich
Dulwich is a pure-Python implementation of Git, providing an interface to both local and remote Git repositories without relying on the `git` executable or native code like `pygit2`. It offers both lower-level "plumbing" and higher-level "porcelain" APIs for interacting with Git objects and operations. The current version is 1.1.0, and it generally releases new versions every few weeks to months.
Warnings
- breaking Dulwich 1.0.0 removed several deprecated functions. Code relying on these removed functions will break.
- breaking Version 0.25.0 introduced significant changes to public APIs, particularly the `dulwich.porcelain` module which was reorganized into submodules (e.g., `dulwich.porcelain.tags`, `dulwich.porcelain.notes`). While the main `dulwich.porcelain` module re-exports functions for backward compatibility, direct imports from old submodule paths or reliance on the previous internal structure may break in future releases, especially after 1.0.0.
- gotcha Dulwich requires Python 3.10 or newer for recent versions. Running with older Python 3 versions (e.g., 3.9 or earlier) will lead to compatibility issues or errors.
- gotcha While Dulwich is a pure-Python Git implementation, its performance for low-level operations can be significantly improved by installing with optional Rust bindings (formerly C extensions). Without these, operations might be noticeably slower.
Install
-
pip install dulwich -
pip install --no-binary dulwich dulwich --config-settings "--build-option=--pure"
Imports
- Repo
from dulwich.repo import Repo
- porcelain
from dulwich import porcelain
Quickstart
import os
from dulwich.repo import Repo
from dulwich import porcelain
from tempfile import TemporaryDirectory
# Create a temporary directory for the repository
with TemporaryDirectory() as temp_dir:
repo_path = os.path.join(temp_dir, 'my_repo')
# Initialize a new repository
repo = porcelain.init(repo_path)
print(f"Initialized repository at: {repo_path}")
# Create a file
file_path = os.path.join(repo_path, 'README.md')
with open(file_path, 'w') as f:
f.write('# My Dulwich Repo\n')
print(f"Created file: {file_path}")
# Add the file to the index and commit
porcelain.add(repo_path, ['README.md'])
porcelain.commit(repo_path, message=b'Initial commit: Add README')
print("Committed initial README.md")
# Log the commit
for entry in porcelain.log(repo_path, max_entries=1):
print(f"Latest commit: {entry.commit.message.decode().strip()}")
# Example of low-level (plumbing) API to get commit message
low_level_repo = Repo(repo_path)
head_id = low_level_repo.head()
latest_commit = low_level_repo[head_id]
print(f"Low-level API: Latest commit message: {latest_commit.message.decode().strip()}")