NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1993 most downloaded on PyPI
Python bindings for libgit2.
Last release 6 days ago
12 Sep 2026
Ships fairly regularly
a new release about every 2 months
Nearly every release is documented
notes for 59 of the last 60 stable releases
1 version withdrawn
withdrawn after publishing
15 years old
91 releases · first in 2012
Now Commit.tree raises an error if tree is not found #682
Unit tests pass on Windows, integration with AppVeyor #641 #655 #657 #659 #660 #661 #667
One column per quarter.
New Repository.path_is_ignored(path) #589
New Repository.create_blob_fromiobase(...) #490 #577
Unify callbacks system for remotes and clone #568
TreeEntry._name
#570Tag._message
#572API changes to clone:
# Before
clone_repository(..., credentials, certificate)
# Now
callbacks = RemoteCallbacks(credentials, certificate)
clone_repository(..., callbacks)
API changes to remote:
# Before
def transfer_progress(stats):
...
remote.credentials = credentials
remote.transfer_progress = transfer_progress
remote.fetch()
remote.push(specs)
# Now
class MyCallbacks(RemoteCallbacks):
def transfer_progress(self, stats):
...
callbacks = MyCallbacks(credentials)
remote.fetch(callbacks=callbacks)
remote.push(specs, callbacks=callbacks)
Now Repository.merge_base(...) returns None if no merge base is found #550
Repository.merge_base(...) returns None if no merge base is
found #550API changes:
How to set identity (aka signature) in a reflog has changed:
# Before
signature = Signature('foo', 'bar')
...
reference.set_target(target, signature=signature, message=message)
repo.set_head(target, signature=signature)
remote.fetch(signature=signature)
remote.push(signature=signature)
# Now
repo.set_ident('foo', 'bar')
...
reference.set_target(target, message=message)
repo.set_head(target)
remote.push()
# The current identity can be get with
repo.ident
Some remote setters have been replaced by methods:
# Before # Now
Remote.url = url Repository.remotes.set_url(name, url)
Remote.push_url = url Repository.remotes.set_push_url(name, url)
Remote.add_fetch(refspec) Repository.remotes.add_fetch(name, refspec)
Remote.add_push(refspec) Repository.remotes.add_push(name, refspec)
Remote.fetch_refspecs = [...] removed, use the config API instead
Remote.push_refspecs = [...] removed, use the config API instead
Diff interface refactoring #346 (in progress):
Diff interface refactoring #346 (in progress):
New iter(pygit2.Blame)
New pygit2.DiffDelta, pygit2.DiffFile and pygit.DiffLine
API changes, translation table:
Hunk => DiffHunk
Patch.old_file_path => Patch.delta.old_file.path
Patch.new_file_path => Patch.delta.new_file.path
Patch.old_id => Patch.delta.old_file.id
Patch.new_id => Patch.delta.new_file.id
Patch.status => Patch.delta.status
Patch.similarity => Patch.delta.similarity
Patch.is_binary => Patch.delta.is_binary
Patch.additions => Patch.line_stats[1]
Patch.deletions => Patch.line_stats[2]
DiffHunk.lines is now a list of DiffLine objects, not tuples
New features:
Repository.expand_id(...) and Repository.ahead_behind(...)
#448prefix parameter in Repository.write_archive
#481Repository.merge_trees(...)
#489Repository.cherrypick(...)
#436
#492Repository.merge_file_from_index(...)
#503Repository.diff supports diffing two blobs
#508fetch parameter in Remote.create
#526pygit2.DiffStats
#406
#525Repository.get_attr(...)
#528level optional parameter in Index.remove
#533repr(TreeEntry)
#543Build and install improvements:
Bugs fixed:
Repository.write_archive fix handling of symlinks
#480Diff[...]
#495Other:
Add support for libgit2 feature detection (new pygit2.features and pygit2.GIT_FEATURE_*) #475
New:
pygit2.features and
pygit2.GIT_FEATURE_*)
#475Repository.remotes (RemoteCollection)
#447API Changes:
clone_repository changed, check documentationclone_into, use clone_repository with callbacks insteadRepository.remotes.rename(name, new_name) instead of
Remote.rename(new_name)Repository.remotes.delete(name) instead of Remote.delete()Remote.push(...) takes a list of refspecs instead of just onePatch.old_id, Patch.new_id, Note.annotated_id,
RefLogEntry.oid_old and RefLogEntry.oid_new to be Oid objects
instead of strings
#449Other:
Fix credentials callback not set when pushing #431 #435 #437 #438
Repository.diff(...) when treeish is "empty"
#432Reference.peel(...) renders Reference.get_object() obsolete
#434Repository.merge_commits(...)
#445Now Repository.blame(...) returns Oid instead of string #413
Breaking changes:
Repository.blame(...) returns Oid instead of string
#413Reference.set_target(...) replaces the Reference.target
setter and Reference.log_append(...)
#414Repository.set_head(...) replaces the Repository.head setter
#414Repository.merge(...) now uses the SAFE_CREATE strategy by
default #417Other changes:
Remote.delete()
#418
#420Repository.write_archive(...)
#421Repository.checkout(...) accepts branch objects
#408clone_repository(...)
#399
#411
#425
#426pip install pygit2 installs cffi first
#380
#407Fix regression with Python 2, IndexEntry.path returns str (bytes in Python 2 and unicode in Python 3)
IndexEntry.path returns str (bytes
in Python 2 and unicode in Python 3)IndexEntry.oid for backwards compatibilityDiff.find_similar supports new threshold arguments
#396Documentation improved, including #383 #385 #388
Repository.state_cleanup()
#386Index.conflicts
#345
#389Backward incompatible changes:
Now the checkout strategy must be a keyword argument.
Change Repository.checkout(refname, strategy) to
Repository.checkout(refname, strategy=strategy)
Idem for checkout_head, checkout_index and checkout_tree
Drop official support for Python 2.6, and add support for Python 3.4 #376
Highlights:
Backward incompatible changes:
oid by id through the API to follow libgit2 conventions.Remote.rename(...) replaces Remote.name = ...Remote.fetch() returns a TransferProgress object.Config.get_multivar(...) returns an iterator instead of a
list.New features:
Config.snapshot() and Repository.config_snapshot()Config methods: get_bool(...), get_int(...),
parse_bool(...) and parse_int(...)
#357clone_into(...) function
#368Index can be used alone, without a repository
#372init_repository
#347Repository.workdir = ... and support setting detached
heads Repository.head = <Oid>
#377Other:
A number of memory issues fixed #328 #348 #353 #355 #356
Repository.walk(...) optional
#337Object.peel(...)
#342Index.add_all(...)
#344Repository objects
#352New str(Oid) deprecates Oid.hex #322
Repository:
Repository.default_signature
#310Oid:
str(Oid) deprecates Oid.hex
#322Object:
Object.id deprecates Object.oid
#322TreeEntry.id deprecates TreeEntry.oid
#322Blob.diff(...) and Blob.diff_to_buffer(...)
#307Commit.tree_id and Commit.parent_ids
#73
#311Tree.__contains__(key) supports paths
#306
#316Index:
IndexEntry(...)
#325IndexEntry.path, IndexEntry.oid and IndexEntry.mode are
writable #325Index.add(...) accepts an IndexEntry too
#325Index.write_tree(...) is able to write to a different
repository #325IndexEntry.path setter
#335Config:
Remote:
Refspec
#314Remote.push_url
#315Remote.add_push and Remote.add_fetch
#255
#318Remote.fetch_refspecs replaces Remote.get_fetch_refspecs()
and Remote.set_fetch_refspecs(...)
#319Remote.push_refspecs replaces Remote.get_push_refspecs() and
Remote.set_push_refspecs(...)
#319Remote.progress, Remote.transfer_progress and
Remote.update_tips
#274
#324TransferProgress
#274
#324Repository.remotes
#321
#332Other: #331
New Repository.reset(...): #292, #294
Repository.reset(...):
#292,
#294GIT_DIFF_MINIMAL:
#293Repository.merge(...):
#295Repository.blame argument handling:
#297Diff.patch returns None if no patch:
#232,
#303Walker.simplify_first_parent():
#304Upgrade to libgit2 v0.20.0: #288
Repository.head_is_unborn replaces
Repository.head_is_orphanedpygit2.clone_repository(...). Drop push_url,
fetch_spec and push_spec parameters. Add ignore_cert_errors.Patch.additions and Patch.deletions:
#275Patch.is_binary:
#276Reference.log_append(...):
#277Blob.is_binary:
#278len(Diff) shows the number of patches:
#281Repository.status():
#283Reference.shorthand:
#284Repository.blame(...):
#285Repository.listall_references() and
Repository.listall_branches() return a list, not a tuple:
#289Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →