pygit2 1.20.0__tar.gz → 1.20.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. {pygit2-1.20.0 → pygit2-1.20.1}/AGENTS.md +8 -6
  2. {pygit2-1.20.0 → pygit2-1.20.1}/AUTHORS.md +3 -0
  3. {pygit2-1.20.0 → pygit2-1.20.1}/CHANGELOG.md +41 -0
  4. {pygit2-1.20.0 → pygit2-1.20.1}/Makefile +1 -1
  5. {pygit2-1.20.0 → pygit2-1.20.1}/PKG-INFO +1 -1
  6. {pygit2-1.20.0 → pygit2-1.20.1}/SPONSORS.md +2 -0
  7. pygit2-1.20.1/build.ps1 +51 -0
  8. {pygit2-1.20.0 → pygit2-1.20.1}/build.sh +45 -42
  9. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/__init__.py +17 -4
  10. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/_build.py +1 -1
  11. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/_pygit2.pyi +10 -3
  12. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/blob.py +14 -4
  13. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/errors.py +50 -8
  14. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/submodules.py +6 -2
  15. {pygit2-1.20.0 → pygit2-1.20.1}/pyproject.toml +2 -2
  16. {pygit2-1.20.0 → pygit2-1.20.1}/src/blob.c +9 -4
  17. {pygit2-1.20.0 → pygit2-1.20.1}/src/commit.c +2 -2
  18. {pygit2-1.20.0 → pygit2-1.20.1}/src/diff.c +61 -6
  19. {pygit2-1.20.0 → pygit2-1.20.1}/src/diff.h +1 -1
  20. {pygit2-1.20.0 → pygit2-1.20.1}/src/error.c +35 -5
  21. {pygit2-1.20.0 → pygit2-1.20.1}/src/odb.c +12 -9
  22. {pygit2-1.20.0 → pygit2-1.20.1}/src/odb_backend.c +46 -17
  23. {pygit2-1.20.0 → pygit2-1.20.1}/src/patch.c +7 -2
  24. {pygit2-1.20.0 → pygit2-1.20.1}/src/pygit2.c +13 -2
  25. {pygit2-1.20.0 → pygit2-1.20.1}/src/refdb_backend.c +4 -2
  26. {pygit2-1.20.0 → pygit2-1.20.1}/src/reference.c +4 -2
  27. {pygit2-1.20.0 → pygit2-1.20.1}/src/repository.c +3 -1
  28. {pygit2-1.20.0 → pygit2-1.20.1}/src/tree.c +1 -1
  29. {pygit2-1.20.0 → pygit2-1.20.1}/src/types.h +2 -0
  30. {pygit2-1.20.0 → pygit2-1.20.1}/src/utils.h +13 -0
  31. {pygit2-1.20.0 → pygit2-1.20.1}/test/conftest.py +6 -0
  32. pygit2-1.20.1/test/data/bigrepo.zip +0 -0
  33. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_blob.py +54 -1
  34. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_diff.py +1 -3
  35. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_diff_binary.py +6 -0
  36. pygit2-1.20.1/test/test_errors.py +126 -0
  37. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_nonunicode.py +8 -0
  38. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_odb_backend.py +108 -0
  39. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_refdb_backend.py +61 -13
  40. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_refs.py +22 -0
  41. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_status.py +44 -0
  42. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_submodule.py +19 -0
  43. pygit2-1.20.0/build.ps1 +0 -23
  44. {pygit2-1.20.0 → pygit2-1.20.1}/CONTRIBUTING.md +0 -0
  45. {pygit2-1.20.0 → pygit2-1.20.1}/COPYING +0 -0
  46. {pygit2-1.20.0 → pygit2-1.20.1}/README.md +0 -0
  47. {pygit2-1.20.0 → pygit2-1.20.1}/build_tag.py +0 -0
  48. {pygit2-1.20.0 → pygit2-1.20.1}/mypy-stubtest.ini +0 -0
  49. {pygit2-1.20.0 → pygit2-1.20.1}/mypy.ini +0 -0
  50. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/_libgit2/ffi.pyi +0 -0
  51. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/_run.py +0 -0
  52. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/blame.py +0 -0
  53. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/branches.py +0 -0
  54. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/callbacks.py +0 -0
  55. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/config.py +0 -0
  56. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/credentials.py +0 -0
  57. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/attr.h +0 -0
  58. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/blame.h +0 -0
  59. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/buffer.h +0 -0
  60. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/callbacks.h +0 -0
  61. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/checkout.h +0 -0
  62. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/clone.h +0 -0
  63. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/commit.h +0 -0
  64. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/common.h +0 -0
  65. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/config.h +0 -0
  66. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/describe.h +0 -0
  67. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/diff.h +0 -0
  68. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/errors.h +0 -0
  69. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/filter.h +0 -0
  70. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/graph.h +0 -0
  71. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/index.h +0 -0
  72. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/indexer.h +0 -0
  73. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/merge.h +0 -0
  74. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/net.h +0 -0
  75. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/oid.h +0 -0
  76. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/options.h +0 -0
  77. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/pack.h +0 -0
  78. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/proxy.h +0 -0
  79. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/rebase.h +0 -0
  80. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/refspec.h +0 -0
  81. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/remote.h +0 -0
  82. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/repository.h +0 -0
  83. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/revert.h +0 -0
  84. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/stash.h +0 -0
  85. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/strarray.h +0 -0
  86. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/submodule.h +0 -0
  87. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/transaction.h +0 -0
  88. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/transport.h +0 -0
  89. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/decl/types.h +0 -0
  90. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/enums.py +0 -0
  91. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/ffi.py +0 -0
  92. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/filter.py +0 -0
  93. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/index.py +0 -0
  94. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/options.py +0 -0
  95. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/packbuilder.py +0 -0
  96. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/py.typed +0 -0
  97. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/rebase.py +0 -0
  98. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/references.py +0 -0
  99. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/refspec.py +0 -0
  100. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/remotes.py +0 -0
  101. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/repository.py +0 -0
  102. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/settings.py +0 -0
  103. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/transaction.py +0 -0
  104. {pygit2-1.20.0 → pygit2-1.20.1}/pygit2/utils.py +0 -0
  105. {pygit2-1.20.0 → pygit2-1.20.1}/pytest.ini +0 -0
  106. {pygit2-1.20.0 → pygit2-1.20.1}/requirements-test.txt +0 -0
  107. {pygit2-1.20.0 → pygit2-1.20.1}/requirements-typing.txt +0 -0
  108. {pygit2-1.20.0 → pygit2-1.20.1}/requirements-wheel.txt +0 -0
  109. {pygit2-1.20.0 → pygit2-1.20.1}/requirements.txt +0 -0
  110. {pygit2-1.20.0 → pygit2-1.20.1}/setup.cfg +0 -0
  111. {pygit2-1.20.0 → pygit2-1.20.1}/setup.py +0 -0
  112. {pygit2-1.20.0 → pygit2-1.20.1}/src/branch.c +0 -0
  113. {pygit2-1.20.0 → pygit2-1.20.1}/src/branch.h +0 -0
  114. {pygit2-1.20.0 → pygit2-1.20.1}/src/error.h +0 -0
  115. {pygit2-1.20.0 → pygit2-1.20.1}/src/filter.c +0 -0
  116. {pygit2-1.20.0 → pygit2-1.20.1}/src/filter.h +0 -0
  117. {pygit2-1.20.0 → pygit2-1.20.1}/src/mailmap.c +0 -0
  118. {pygit2-1.20.0 → pygit2-1.20.1}/src/mailmap.h +0 -0
  119. {pygit2-1.20.0 → pygit2-1.20.1}/src/note.c +0 -0
  120. {pygit2-1.20.0 → pygit2-1.20.1}/src/note.h +0 -0
  121. {pygit2-1.20.0 → pygit2-1.20.1}/src/object.c +0 -0
  122. {pygit2-1.20.0 → pygit2-1.20.1}/src/object.h +0 -0
  123. {pygit2-1.20.0 → pygit2-1.20.1}/src/odb.h +0 -0
  124. {pygit2-1.20.0 → pygit2-1.20.1}/src/odb_backend.h +0 -0
  125. {pygit2-1.20.0 → pygit2-1.20.1}/src/oid.c +0 -0
  126. {pygit2-1.20.0 → pygit2-1.20.1}/src/oid.h +0 -0
  127. {pygit2-1.20.0 → pygit2-1.20.1}/src/patch.h +0 -0
  128. {pygit2-1.20.0 → pygit2-1.20.1}/src/refdb.c +0 -0
  129. {pygit2-1.20.0 → pygit2-1.20.1}/src/refdb.h +0 -0
  130. {pygit2-1.20.0 → pygit2-1.20.1}/src/refdb_backend.h +0 -0
  131. {pygit2-1.20.0 → pygit2-1.20.1}/src/reference.h +0 -0
  132. {pygit2-1.20.0 → pygit2-1.20.1}/src/repository.h +0 -0
  133. {pygit2-1.20.0 → pygit2-1.20.1}/src/revspec.c +0 -0
  134. {pygit2-1.20.0 → pygit2-1.20.1}/src/revspec.h +0 -0
  135. {pygit2-1.20.0 → pygit2-1.20.1}/src/signature.c +0 -0
  136. {pygit2-1.20.0 → pygit2-1.20.1}/src/signature.h +0 -0
  137. {pygit2-1.20.0 → pygit2-1.20.1}/src/stash.c +0 -0
  138. {pygit2-1.20.0 → pygit2-1.20.1}/src/tag.c +0 -0
  139. {pygit2-1.20.0 → pygit2-1.20.1}/src/tree.h +0 -0
  140. {pygit2-1.20.0 → pygit2-1.20.1}/src/treebuilder.c +0 -0
  141. {pygit2-1.20.0 → pygit2-1.20.1}/src/treebuilder.h +0 -0
  142. {pygit2-1.20.0 → pygit2-1.20.1}/src/utils.c +0 -0
  143. {pygit2-1.20.0 → pygit2-1.20.1}/src/walker.c +0 -0
  144. {pygit2-1.20.0 → pygit2-1.20.1}/src/walker.h +0 -0
  145. {pygit2-1.20.0 → pygit2-1.20.1}/src/wildmatch.c +0 -0
  146. {pygit2-1.20.0 → pygit2-1.20.1}/src/wildmatch.h +0 -0
  147. {pygit2-1.20.0 → pygit2-1.20.1}/src/worktree.c +0 -0
  148. {pygit2-1.20.0 → pygit2-1.20.1}/src/worktree.h +0 -0
  149. {pygit2-1.20.0 → pygit2-1.20.1}/test/__init__.py +0 -0
  150. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/barerepo.zip +0 -0
  151. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/binaryfilerepo.zip +0 -0
  152. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/blameflagsrepo.zip +0 -0
  153. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/dirtyrepo.zip +0 -0
  154. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/emptyrepo.zip +0 -0
  155. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/encoding.zip +0 -0
  156. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/gpgsigned.zip +0 -0
  157. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/submodulerepo.zip +0 -0
  158. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/testrepo.zip +0 -0
  159. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/testrepoformerging.zip +0 -0
  160. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/testrepopacked.zip +0 -0
  161. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/trailerrepo.zip +0 -0
  162. {pygit2-1.20.0 → pygit2-1.20.1}/test/data/utf8branchrepo.zip +0 -0
  163. {pygit2-1.20.0 → pygit2-1.20.1}/test/keys/pygit2_empty +0 -0
  164. {pygit2-1.20.0 → pygit2-1.20.1}/test/keys/pygit2_empty.pub +0 -0
  165. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_apply_diff.py +0 -0
  166. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_archive.py +0 -0
  167. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_attributes.py +0 -0
  168. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_blame.py +0 -0
  169. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_branch.py +0 -0
  170. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_branch_empty.py +0 -0
  171. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_cherrypick.py +0 -0
  172. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_commit.py +0 -0
  173. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_commit_gpg.py +0 -0
  174. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_commit_trailer.py +0 -0
  175. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_config.py +0 -0
  176. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_credentials.py +0 -0
  177. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_describe.py +0 -0
  178. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_filter.py +0 -0
  179. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_index.py +0 -0
  180. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_mailmap.py +0 -0
  181. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_merge.py +0 -0
  182. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_note.py +0 -0
  183. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_object.py +0 -0
  184. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_odb.py +0 -0
  185. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_oid.py +0 -0
  186. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_options.py +0 -0
  187. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_packbuilder.py +0 -0
  188. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_patch.py +0 -0
  189. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_patch_encoding.py +0 -0
  190. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_rebase.py +0 -0
  191. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_remote.py +0 -0
  192. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_remote_prune.py +0 -0
  193. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_remote_utf8.py +0 -0
  194. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_repository.py +0 -0
  195. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_repository_bare.py +0 -0
  196. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_repository_custom.py +0 -0
  197. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_repository_empty.py +0 -0
  198. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_revparse.py +0 -0
  199. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_revwalk.py +0 -0
  200. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_settings.py +0 -0
  201. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_signature.py +0 -0
  202. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_tag.py +0 -0
  203. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_transaction.py +0 -0
  204. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_tree.py +0 -0
  205. {pygit2-1.20.0 → pygit2-1.20.1}/test/test_treebuilder.py +0 -0
  206. {pygit2-1.20.0 → pygit2-1.20.1}/test/utils.py +0 -0
@@ -11,7 +11,7 @@ and a high-level, Pythonic API for repository manipulation.
11
11
  - **License**: GPLv2 with linking exception (see `COPYING`)
12
12
  - **Maintainer**: J. David Ibáñez
13
13
  - **Python Support**: 3.11 – 3.14 and PyPy3 7.3+
14
- - **libgit2 Version**: 1.9.6
14
+ - **libgit2 Version**: 1.9.7
15
15
  - **Homepage**: <https://www.pygit2.org/>
16
16
  - **Repository**: <https://github.com/libgit2/pygit2>
17
17
 
@@ -107,7 +107,7 @@ handles libgit2 compilation via CMake.
107
107
  make
108
108
 
109
109
  # Or manually:
110
- LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.6 sh build.sh
110
+ LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.7 sh build.sh
111
111
 
112
112
  # Build a wheel and bundle the shared libraries into it
113
113
  sh build.sh wheel
@@ -139,8 +139,8 @@ Variables consumed by `build.sh`:
139
139
 
140
140
  - `LIBGIT2_VERSION` — If set, download and build this libgit2 version.
141
141
  - `LIBSSH2_VERSION` — If set, download and build libssh2 with SSH support.
142
- - `OPENSSL_VERSION` — If set, download and build OpenSSL (mainly used for
143
- macOS universal builds on CI).
142
+ - `OPENSSL_VERSION` — If set, download and build OpenSSL (used on Linux and
143
+ macOS CI builds).
144
144
  - `ZLIB_VERSION` — If set, download and build zlib.
145
145
  - `BUILD_TYPE` — CMake build type (default: `Debug`).
146
146
  - `PYTHON` — Python interpreter to use (default: `python3`).
@@ -242,7 +242,8 @@ GitHub Actions workflows live in `.github/workflows/`:
242
242
  `sh build.sh mypy`.
243
243
  - **`wheels.yml`** — Uses `cibuildwheel` (`~=3.3`) to build wheels for Linux
244
244
  (amd64, arm64, ppc64le and riscv64 via QEMU, musl), macOS (intel, arm64,
245
- PyPy), and Windows (x64, x86, arm64). It also builds an sdist, runs a
245
+ PyPy), and Windows (x64, x86, arm64). Linux, macOS and Windows jobs cache
246
+ the compiled dependencies between runs. It also builds an sdist, runs a
246
247
  `twine check` (skipped on version tags), publishes to PyPI, and creates a
247
248
  GitHub Release on version tags (`v*`), with release notes parsed from
248
249
  `CHANGELOG.md` by `.github/workflows/parse_release_notes.py`.
@@ -250,7 +251,7 @@ GitHub Actions workflows live in `.github/workflows/`:
250
251
 
251
252
  The `cibuildwheel` configuration in `pyproject.toml` pins:
252
253
 
253
- - `LIBGIT2_VERSION="1.9.6"`
254
+ - `LIBGIT2_VERSION="1.9.7"`
254
255
  - `LIBSSH2_VERSION="1.11.1"`
255
256
  - `OPENSSL_VERSION="3.5.7"`
256
257
 
@@ -272,6 +273,7 @@ and skips `*musllinux_ppc64le` plus testing on `*-*linux_ppc64le`,
272
273
 
273
274
  ## Git Commits
274
275
 
276
+ - Do not run `git commit` or create commits unless the user explicitly asks for it.
275
277
  - Commits created by an AI agent must end with the `Assisted-by:` trailer.
276
278
  Human-authored commits do not need it.
277
279
 
@@ -126,6 +126,7 @@ Authors:
126
126
  Marcel Waldvogel
127
127
  Masud Rahman
128
128
  Michael Sondergaard
129
+ Michal Koutný
129
130
  Natanael Arndt
130
131
  Nick Williams
131
132
  Ondřej Nový
@@ -201,6 +202,7 @@ Authors:
201
202
  Lance Eftink
202
203
  Legorooj
203
204
  Lukas Berk
205
+ Marius Gedminas
204
206
  Martin von Zweigbergk
205
207
  Mathieu Bridon
206
208
  Mathieu Pillard
@@ -227,6 +229,7 @@ Authors:
227
229
  Remy Suen
228
230
  Ridge Kennedy
229
231
  Rodrigo Bistolfi
232
+ Roshan Ramani
230
233
  Ross Nicoll
231
234
  Rui Abreu Ferreira
232
235
  Rui Chen
@@ -1,3 +1,44 @@
1
+ # 1.20.1 (2026-09-12)
2
+
3
+ - Update wheels to libgit2 1.9.7
4
+
5
+ - New exception hierarchy: `AlreadyExistsError`, `InvalidSpecError`,
6
+ `InvalidError`, `NotFoundError`, `AmbiguousError`, `AuthError`, and
7
+ `CertificateError` all inherit from `GitError` and the appropriate Python
8
+ built-in exception (`ValueError`/`KeyError`) for backward compatibility
9
+ [#830](https://github.com/libgit2/pygit2/issues/830)
10
+
11
+ - Fix `DiffDelta.is_binary` and `DiffDelta.flags` returning stale values for
12
+ deltas obtained from `Diff.deltas`; flags are now loaded lazily
13
+ [#962](https://github.com/libgit2/pygit2/issues/962)
14
+ [#1100](https://github.com/libgit2/pygit2/pull/1100)
15
+
16
+ - Fix `repo.submodules.get()` and `name in repo.submodules` raising
17
+ `AlreadyExistsError` when a repository exists at the submodule path but was
18
+ never registered as a submodule; they now return `None` and `False`
19
+ respectively as documented
20
+ [#1487](https://github.com/libgit2/pygit2/pull/1487)
21
+
22
+ - Fix `BlobIO` cleanup deadlock on partial reads
23
+ [#1488](https://github.com/libgit2/pygit2/issues/1488)
24
+ [#1491](https://github.com/libgit2/pygit2/pull/1491)
25
+
26
+ - Fix leaks and crashes in error paths
27
+ [#1478](https://github.com/libgit2/pygit2/issues/1478)
28
+ [#1479](https://github.com/libgit2/pygit2/issues/1479)
29
+ [#1480](https://github.com/libgit2/pygit2/issues/1480)
30
+ [#1481](https://github.com/libgit2/pygit2/issues/1481)
31
+
32
+ - Fix custom ODB and refdb backend callbacks overwriting a pending Python
33
+ exception (e.g. `RuntimeError`) with a stale libgit2 error message.
34
+
35
+ - Documentation fixes
36
+ [#1490](https://github.com/libgit2/pygit2/pull/1490)
37
+
38
+ - CI (macOS): build architecture-specific OpenSSL/libssh2/libgit2
39
+ dependencies instead of universal binaries, producing smaller wheels.
40
+
41
+
1
42
  # 1.20.0 (2026-08-08)
2
43
 
3
44
  - New `RemoteCallbacks.custom_headers()`
@@ -1,7 +1,7 @@
1
1
  .PHONY: build html
2
2
 
3
3
  build:
4
- OPENSSL_VERSION=3.5.7 LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.6 sh build.sh
4
+ OPENSSL_VERSION=3.5.7 LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.7 sh build.sh
5
5
 
6
6
  html: build
7
7
  make -C docs html
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygit2
3
- Version: 1.20.0
3
+ Version: 1.20.1
4
4
  Summary: Python bindings for libgit2.
5
5
  Home-page: https://github.com/libgit2/pygit2
6
6
  Maintainer: J. David Ibáñez
@@ -1,5 +1,7 @@
1
1
  Friends of pygit2:
2
2
 
3
+ - [William Bowers](https://github.com/ralian)
4
+
3
5
  - Add your name to the list,
4
6
  [become a friend of pygit2](https://github.com/sponsors/jdavid).
5
7
 
@@ -0,0 +1,51 @@
1
+ $ErrorActionPreference = 'Stop'
2
+
3
+ $LIBGIT2_VERSION = $env:LIBGIT2_VERSION
4
+ $LIBGIT2_SRC = $env:LIBGIT2_SRC
5
+ if (-not $LIBGIT2_SRC) {
6
+ $LIBGIT2_SRC = "build/libgit2_src"
7
+ }
8
+
9
+ # Prefer CMAKE_INSTALL_PREFIX, then LIBGIT2, then the default Program Files location.
10
+ $INSTALL_PREFIX = $env:CMAKE_INSTALL_PREFIX
11
+ if (-not $INSTALL_PREFIX) {
12
+ $INSTALL_PREFIX = $env:LIBGIT2
13
+ }
14
+ if (-not $INSTALL_PREFIX) {
15
+ $INSTALL_PREFIX = "$env:ProgramFiles\libgit2"
16
+ }
17
+
18
+ # Use cached dependencies if they match the requested version.
19
+ if ((Test-Path -Path "$INSTALL_PREFIX\versions.txt") -and $LIBGIT2_VERSION) {
20
+ $cached = Get-Content "$INSTALL_PREFIX\versions.txt"
21
+ $matches = $cached | Select-String "^LIBGIT2_VERSION=$LIBGIT2_VERSION$"
22
+ if ($matches) {
23
+ Write-Host "Using cached dependencies"
24
+ exit 0
25
+ }
26
+ }
27
+
28
+ if (!(Test-Path -Path "build")) {
29
+ # in case the pygit2 package build/ workspace has not been created by cibuildwheel yet
30
+ mkdir build
31
+ }
32
+ if (Test-Path -Path "$LIBGIT2_SRC") {
33
+ Set-Location "$LIBGIT2_SRC"
34
+ # for local runs, reuse build/libgit_src if it exists
35
+ if (Test-Path -Path build) {
36
+ # purge previous build env (likely for a different arch type)
37
+ Remove-Item -Recurse -Force build
38
+ }
39
+ # ensure we are checked out to the right version
40
+ git fetch --depth=1 --tags
41
+ git checkout "v$LIBGIT2_VERSION"
42
+ } else {
43
+ # from a fresh run (like in CI)
44
+ git clone --depth=1 -b "v$LIBGIT2_VERSION" https://github.com/libgit2/libgit2.git $LIBGIT2_SRC
45
+ Set-Location "$LIBGIT2_SRC"
46
+ }
47
+ cmake -B build -S . -DBUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX"
48
+ cmake --build build/ --config=Release --target install
49
+
50
+ # Record version so the cache can be reused.
51
+ "LIBGIT2_VERSION=$LIBGIT2_VERSION" | Set-Content "$INSTALL_PREFIX\versions.txt" -NoNewline
@@ -14,7 +14,7 @@
14
14
  # LIBSSH2_VERSION=<Version> - Build the given version of libssh2
15
15
  # LIBGIT2_VERSION=<Version> - Build the given version of libgit2
16
16
  # OPENSSL_VERSION=<Version> - Build the given version of OpenSSL
17
- # (only needed for Mac universal on CI)
17
+ # (used on Linux and macOS CI builds)
18
18
  #
19
19
  # Examples.
20
20
  #
@@ -22,14 +22,14 @@
22
22
  #
23
23
  # sh build.sh
24
24
  #
25
- # Build libgit2 1.9.6 (will use libssh2 if available), then build pygit2
25
+ # Build libgit2 1.9.7 (will use libssh2 if available), then build pygit2
26
26
  # inplace:
27
27
  #
28
- # LIBGIT2_VERSION=1.9.6 sh build.sh
28
+ # LIBGIT2_VERSION=1.9.7 sh build.sh
29
29
  #
30
- # Build libssh2 1.11.1 and libgit2 1.9.6, then build pygit2 inplace:
30
+ # Build libssh2 1.11.1 and libgit2 1.9.7, then build pygit2 inplace:
31
31
  #
32
- # LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.6 sh build.sh
32
+ # LIBSSH2_VERSION=1.11.1 LIBGIT2_VERSION=1.9.7 sh build.sh
33
33
  #
34
34
  # Build inplace and run the tests:
35
35
  #
@@ -82,8 +82,20 @@ if [ "$CIBUILDWHEEL" = "1" ]; then
82
82
  apk add --no-cache perl
83
83
  fi
84
84
  fi
85
- rm -rf ci
86
- mkdir ci || true
85
+
86
+ # Use cached dependencies if they match the requested versions.
87
+ if [ -f ci/versions.txt ] && \
88
+ grep -q "^LIBGIT2_VERSION=$LIBGIT2_VERSION$" ci/versions.txt && \
89
+ grep -q "^LIBSSH2_VERSION=$LIBSSH2_VERSION$" ci/versions.txt && \
90
+ grep -q "^OPENSSL_VERSION=$OPENSSL_VERSION$" ci/versions.txt; then
91
+ echo "Using cached dependencies"
92
+ exit 0
93
+ fi
94
+
95
+ # The ci directory may be a bind-mount (e.g. inside cibuildwheel), so
96
+ # remove its contents but keep the directory itself.
97
+ rm -rf ci/* ci/.[!.]* ci/..?* 2>/dev/null || true
98
+ mkdir -p ci
87
99
  cd ci
88
100
  else
89
101
  # Create a virtual environment
@@ -110,31 +122,24 @@ if [ -n "$OPENSSL_VERSION" ]; then
110
122
  wget https://www.openssl.org/source/$FILENAME.tar.gz -N --no-check-certificate
111
123
 
112
124
  if [ "$KERNEL" = "Darwin" ]; then
125
+ # Build OpenSSL for the host architecture only.
113
126
  tar xf $FILENAME.tar.gz
114
- mv $FILENAME openssl-x86
115
-
116
- tar xf $FILENAME.tar.gz
117
- mv $FILENAME openssl-arm
118
-
119
- cd openssl-x86
120
- ./Configure darwin64-x86_64-cc shared
121
- make
122
- cd ../openssl-arm
123
- ./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
127
+ cd $FILENAME
128
+ if [ "$ARCH" = "arm64" ]; then
129
+ ./Configure enable-rc5 zlib darwin64-arm64-cc no-asm shared --prefix=$PREFIX --libdir=$PREFIX/lib
130
+ else
131
+ ./Configure darwin64-x86_64-cc shared --prefix=$PREFIX --libdir=$PREFIX/lib
132
+ fi
124
133
  make
125
- cd ..
126
-
127
- mkdir openssl-universal
128
-
129
- LIBSSL=$(basename openssl-x86/libssl.*.dylib)
130
- lipo -create openssl-x86/libssl.*.dylib openssl-arm/libssl.*.dylib -output openssl-universal/$LIBSSL
131
- LIBCRYPTO=$(basename openssl-x86/libcrypto.*.dylib)
132
- lipo -create openssl-x86/libcrypto.*.dylib openssl-arm/libcrypto.*.dylib -output openssl-universal/$LIBCRYPTO
133
- cd openssl-universal
134
- install_name_tool -id "@rpath/$LIBSSL" $LIBSSL
135
- install_name_tool -id "@rpath/$LIBCRYPTO" $LIBCRYPTO
136
- OPENSSL_PREFIX=$(pwd)
137
- cd ..
134
+ make install
135
+ OPENSSL_PREFIX=$PREFIX
136
+ # Set install names so delocate can bundle the libraries.
137
+ cd $PREFIX/lib
138
+ LIBSSL=$(find . -maxdepth 1 -name 'libssl.*.dylib' -type f | head -n1 | sed 's|^\./||')
139
+ LIBCRYPTO=$(find . -maxdepth 1 -name 'libcrypto.*.dylib' -type f | head -n1 | sed 's|^\./||')
140
+ install_name_tool -id "@rpath/$LIBSSL" "$LIBSSL"
141
+ install_name_tool -id "@rpath/$LIBCRYPTO" "$LIBCRYPTO"
142
+ cd ../..
138
143
  else
139
144
  # Linux
140
145
  tar xf $FILENAME.tar.gz
@@ -154,14 +159,11 @@ if [ -n "$LIBSSH2_VERSION" ]; then
154
159
  tar xf $FILENAME.tar.gz
155
160
  cd $FILENAME
156
161
  if [ "$KERNEL" = "Darwin" ] && [ "$CIBUILDWHEEL" = "1" ]; then
157
- cmake . \
162
+ CMAKE_PREFIX_PATH=$PREFIX cmake . \
158
163
  -DCMAKE_INSTALL_PREFIX=$PREFIX \
159
164
  -DBUILD_SHARED_LIBS=ON \
160
165
  -DBUILD_EXAMPLES=OFF \
161
- -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
162
- -DOPENSSL_CRYPTO_LIBRARY="../openssl-universal/$LIBCRYPTO" \
163
- -DOPENSSL_SSL_LIBRARY="../openssl-universal/$LIBSSL" \
164
- -DOPENSSL_INCLUDE_DIR="../openssl-x86/include" \
166
+ -DCMAKE_OSX_ARCHITECTURES="$ARCH" \
165
167
  -DBUILD_TESTING=OFF
166
168
  else
167
169
  cmake . \
@@ -186,14 +188,11 @@ if [ -n "$LIBGIT2_VERSION" ]; then
186
188
  mkdir -p build
187
189
  cd build
188
190
  if [ "$KERNEL" = "Darwin" ] && [ "$CIBUILDWHEEL" = "1" ]; then
189
- CMAKE_PREFIX_PATH=$OPENSSL_PREFIX:$PREFIX cmake .. \
191
+ CMAKE_PREFIX_PATH=$PREFIX cmake .. \
190
192
  -DBUILD_SHARED_LIBS=ON \
191
193
  -DBUILD_TESTS=OFF \
192
194
  -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
193
- -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
194
- -DOPENSSL_CRYPTO_LIBRARY="../openssl-universal/$LIBCRYPTO" \
195
- -DOPENSSL_SSL_LIBRARY="../openssl-universal/$LIBSSL" \
196
- -DOPENSSL_INCLUDE_DIR="../openssl-x86/include" \
195
+ -DCMAKE_OSX_ARCHITECTURES="$ARCH" \
197
196
  -DCMAKE_INSTALL_PREFIX=$PREFIX \
198
197
  -DUSE_SSH=$USE_SSH
199
198
  else
@@ -212,9 +211,13 @@ if [ -n "$LIBGIT2_VERSION" ]; then
212
211
  fi
213
212
 
214
213
  if [ "$CIBUILDWHEEL" = "1" ]; then
214
+ # Record versions so the cache can be reused.
215
+ cat > $PREFIX/versions.txt <<EOF
216
+ LIBGIT2_VERSION=$LIBGIT2_VERSION
217
+ LIBSSH2_VERSION=$LIBSSH2_VERSION
218
+ OPENSSL_VERSION=$OPENSSL_VERSION
219
+ EOF
215
220
  if [ "$KERNEL" = "Darwin" ]; then
216
- cp $OPENSSL_PREFIX/*.dylib $PREFIX/lib/
217
- cp $OPENSSL_PREFIX/*.dylib $PREFIX/lib/
218
221
  echo "PREFIX " $PREFIX
219
222
  echo "OPENSSL_PREFIX" $OPENSSL_PREFIX
220
223
  ls -l $PREFIX
@@ -248,7 +248,6 @@ from ._pygit2 import (
248
248
  LIBGIT2_VER_MINOR,
249
249
  LIBGIT2_VER_REVISION,
250
250
  LIBGIT2_VERSION,
251
- AlreadyExistsError,
252
251
  Blob,
253
252
  Branch,
254
253
  Commit,
@@ -259,8 +258,6 @@ from ._pygit2 import (
259
258
  DiffLine,
260
259
  DiffStats,
261
260
  FilterSource,
262
- GitError,
263
- InvalidSpecError,
264
261
  Mailmap,
265
262
  Note,
266
263
  Object,
@@ -306,7 +303,18 @@ from .callbacks import (
306
303
  )
307
304
  from .config import Config
308
305
  from .credentials import *
309
- from .errors import Passthrough, check_error
306
+ from .errors import (
307
+ AlreadyExistsError,
308
+ AmbiguousError,
309
+ AuthError,
310
+ CertificateError,
311
+ GitError,
312
+ InvalidError,
313
+ InvalidSpecError,
314
+ NotFoundError,
315
+ Passthrough,
316
+ check_error,
317
+ )
310
318
  from .ffi import C, ffi
311
319
  from .filter import Filter
312
320
  from .index import Index, IndexEntry
@@ -592,8 +600,11 @@ __all__ = (
592
600
  'Object',
593
601
  'Reference',
594
602
  'AlreadyExistsError',
603
+ 'AmbiguousError',
604
+ 'AuthError',
595
605
  'Blob',
596
606
  'Branch',
607
+ 'CertificateError',
597
608
  'Commit',
598
609
  'Diff',
599
610
  'DiffDelta',
@@ -602,9 +613,11 @@ __all__ = (
602
613
  'DiffLine',
603
614
  'DiffStats',
604
615
  'GitError',
616
+ 'InvalidError',
605
617
  'InvalidSpecError',
606
618
  'Mailmap',
607
619
  'Note',
620
+ 'NotFoundError',
608
621
  'Odb',
609
622
  'OdbBackend',
610
623
  'OdbBackendLoose',
@@ -34,7 +34,7 @@ from pathlib import Path
34
34
  #
35
35
  # The version number of pygit2
36
36
  #
37
- __version__ = '1.20.0'
37
+ __version__ = '1.20.1'
38
38
 
39
39
 
40
40
  #
@@ -331,7 +331,10 @@ class Reference:
331
331
  def __lt__(self, other, /) -> bool: ...
332
332
  def __ne__(self, other, /) -> bool: ...
333
333
 
334
- class AlreadyExistsError(ValueError): ...
334
+ class AlreadyExistsError(GitError, ValueError): ...
335
+ class AmbiguousError(GitError, ValueError): ...
336
+ class AuthError(GitError): ...
337
+ class InvalidError(GitError, ValueError): ...
335
338
 
336
339
  @final
337
340
  class Blob(Object):
@@ -376,6 +379,8 @@ class Branch(Reference): # type: ignore[misc]
376
379
  def is_head(self) -> bool: ...
377
380
  def rename(self, name: str, force: bool = False) -> 'Branch': ... # type: ignore[override]
378
381
 
382
+ class CertificateError(GitError): ...
383
+
379
384
  @final
380
385
  class Commit(_ObjectBase[GitCommitC]):
381
386
  _pointer: _Pointer[GitCommitC]
@@ -421,7 +426,7 @@ class Diff:
421
426
  @final
422
427
  class DiffDelta:
423
428
  flags: DiffFlag
424
- is_binary: bool
429
+ is_binary: bool | None
425
430
  nfiles: int
426
431
  new_file: DiffFile
427
432
  old_file: DiffFile
@@ -476,7 +481,7 @@ class FilterSource:
476
481
  flags: int
477
482
 
478
483
  class GitError(Exception): ...
479
- class InvalidSpecError(ValueError): ...
484
+ class InvalidSpecError(GitError, ValueError): ...
480
485
 
481
486
  @final
482
487
  class Mailmap:
@@ -505,6 +510,8 @@ class Note:
505
510
  self, author: Signature, committer: Signature, ref: str = 'refs/notes/commits'
506
511
  ) -> None: ...
507
512
 
513
+ class NotFoundError(GitError, KeyError): ...
514
+
508
515
  @final
509
516
  class Odb:
510
517
  backends: Iterator[OdbBackend]
@@ -86,10 +86,20 @@ class _BlobIO(io.RawIOBase):
86
86
 
87
87
  def close(self) -> None:
88
88
  try:
89
- self._ready.wait()
90
- self._writer_closed.wait()
91
- while self._queue is not None and not self._queue.empty():
92
- self._queue.get()
89
+ # The writer thread may be blocked in queue.put() because the
90
+ # queue (maxsize=1) still holds a chunk that was never consumed
91
+ # (e.g. the reader stopped before reaching EOF). Draining the
92
+ # queue must happen *before* (not after) waiting for
93
+ # `_writer_closed`, otherwise the writer can never make progress
94
+ # to reach its close callback and this would deadlock.
95
+ while True:
96
+ self._ready.wait()
97
+ while self._queue is not None and not self._queue.empty():
98
+ self._queue.get()
99
+ if self._writer_closed.is_set():
100
+ # Done
101
+ break
102
+ self._ready.clear()
93
103
  self._thread.join()
94
104
  except KeyboardInterrupt:
95
105
  pass
@@ -24,12 +24,39 @@
24
24
  # Boston, MA 02110-1301, USA.
25
25
 
26
26
  # Import from pygit2
27
- from ._pygit2 import GitError
27
+ from ._pygit2 import (
28
+ AlreadyExistsError,
29
+ AmbiguousError,
30
+ AuthError,
31
+ CertificateError,
32
+ GitError,
33
+ InvalidError,
34
+ InvalidSpecError,
35
+ NotFoundError,
36
+ )
28
37
  from .ffi import C, ffi
29
38
 
30
- __all__ = ['GitError']
39
+ __all__ = [
40
+ 'AlreadyExistsError',
41
+ 'AmbiguousError',
42
+ 'AuthError',
43
+ 'CertificateError',
44
+ 'GitError',
45
+ 'InvalidError',
46
+ 'InvalidSpecError',
47
+ 'NotFoundError',
48
+ 'Passthrough',
49
+ ]
31
50
 
32
- value_errors = set([C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EAMBIGUOUS])
51
+ # Docstrings for C-defined exception classes
52
+ GitError.__doc__ = 'Generic libgit2 error.'
53
+ AlreadyExistsError.__doc__ = 'Object already exists.'
54
+ InvalidSpecError.__doc__ = 'Invalid name/ref spec.'
55
+ NotFoundError.__doc__ = 'Requested object could not be found.'
56
+ AmbiguousError.__doc__ = 'More than one object matches.'
57
+ AuthError.__doc__ = 'Authentication error.'
58
+ CertificateError.__doc__ = 'Server certificate is invalid.'
59
+ InvalidError.__doc__ = 'Invalid operation or input.'
33
60
 
34
61
 
35
62
  def check_error(err: int, io: bool = False) -> None:
@@ -48,17 +75,32 @@ def check_error(err: int, io: bool = False) -> None:
48
75
  message = f'err {err} (no message provided)'
49
76
 
50
77
  # Translate to Python errors
51
- if err in value_errors:
78
+ if err == C.GIT_EEXISTS:
79
+ raise AlreadyExistsError(message)
80
+
81
+ if err == C.GIT_EINVALIDSPEC:
82
+ raise InvalidSpecError(message)
83
+
84
+ if err == C.GIT_EINVALID:
85
+ raise InvalidError(message)
86
+
87
+ if err == C.GIT_EAMBIGUOUS:
88
+ raise AmbiguousError(message)
89
+
90
+ if err == C.GIT_EBUFS:
52
91
  raise ValueError(message)
53
92
 
93
+ if err == C.GIT_EAUTH:
94
+ raise AuthError(message)
95
+
96
+ if err == C.GIT_ECERTIFICATE:
97
+ raise CertificateError(message)
98
+
54
99
  if err == C.GIT_ENOTFOUND:
55
100
  if io:
56
101
  raise IOError(message)
57
102
 
58
- raise KeyError(message)
59
-
60
- if err == C.GIT_EINVALIDSPEC:
61
- raise ValueError(message)
103
+ raise NotFoundError(message)
62
104
 
63
105
  if err == C.GIT_ITEROVER:
64
106
  raise StopIteration()
@@ -32,7 +32,7 @@ from typing import TYPE_CHECKING, Optional
32
32
  from ._pygit2 import Oid
33
33
  from .callbacks import RemoteCallbacks, git_fetch_options
34
34
  from .enums import SubmoduleIgnore, SubmoduleStatus
35
- from .errors import check_error
35
+ from .errors import AlreadyExistsError, check_error
36
36
  from .ffi import C, ffi
37
37
  from .utils import decode_fs_path, decode_string, encode_string
38
38
 
@@ -210,7 +210,11 @@ class SubmoduleCollection:
210
210
  """
211
211
  try:
212
212
  return self[name]
213
- except KeyError:
213
+ except (KeyError, AlreadyExistsError):
214
+ # libgit2 reports GIT_EEXISTS, which check_error turns into
215
+ # AlreadyExistsError, when a repository exists at the path but was
216
+ # never registered as a submodule. There is still no submodule by
217
+ # that name, so report it the same way as a missing one.
214
218
  return None
215
219
 
216
220
  def add(
@@ -9,7 +9,7 @@ skip = "*musllinux_ppc64le"
9
9
  archs = ["native"]
10
10
  build-frontend = "default"
11
11
  dependency-versions = "pinned"
12
- environment = {LIBGIT2="$(pwd)/ci", LIBGIT2_VERSION="1.9.6", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.7"}
12
+ environment = {LIBGIT2="$(pwd)/ci", LIBGIT2_VERSION="1.9.7", LIBSSH2_VERSION="1.11.1", OPENSSL_VERSION="3.5.7"}
13
13
 
14
14
  before-all = "sh build.sh"
15
15
  test-command = "pytest"
@@ -32,7 +32,7 @@ repair-wheel-command = "DYLD_LIBRARY_PATH={package}/ci/lib delocate-wheel --requ
32
32
 
33
33
  [tool.cibuildwheel.windows]
34
34
  environment.LIBGIT2_SRC = "build/libgit2_src"
35
- environment.LIBGIT2_VERSION = "1.9.6"
35
+ environment.LIBGIT2_VERSION = "1.9.7"
36
36
  before-all = "powershell -File build.ps1"
37
37
  before-build = ""
38
38
 
@@ -190,6 +190,7 @@ static int blob_filter_stream_write(
190
190
  err = GIT_ERROR;
191
191
  goto done;
192
192
  }
193
+ Py_DECREF(result);
193
194
  pos += chunk_size;
194
195
  }
195
196
 
@@ -202,7 +203,7 @@ static int blob_filter_stream_close(git_writestream *s)
202
203
  {
203
204
  struct blob_filter_stream *stream = (struct blob_filter_stream *)s;
204
205
  PyGILState_STATE gil = PyGILState_Ensure();
205
- PyObject *result;
206
+ PyObject *result = NULL;
206
207
  int err = 0;
207
208
 
208
209
  /* Signal closed and then ready in that order so consumers can block on
@@ -214,6 +215,7 @@ static int blob_filter_stream_close(git_writestream *s)
214
215
  git_error_set(GIT_ERROR_OS, "failed to signal writer closed");
215
216
  err = GIT_ERROR;
216
217
  }
218
+ Py_XDECREF(result);
217
219
  result = PyObject_CallMethod(stream->py_ready, "set", NULL);
218
220
  if (result == NULL)
219
221
  {
@@ -221,6 +223,7 @@ static int blob_filter_stream_close(git_writestream *s)
221
223
  git_error_set(GIT_ERROR_OS, "failed to signal queue ready");
222
224
  err = GIT_ERROR;
223
225
  }
226
+ Py_XDECREF(result);
224
227
 
225
228
  PyGILState_Release(gil);
226
229
  return err;
@@ -316,9 +319,11 @@ Blob__write_to_queue(Blob *self, PyObject *args, PyObject *kwds)
316
319
  {
317
320
  if (py_oid != NULL && py_oid != Py_None)
318
321
  {
319
- err = py_oid_to_git_oid(py_oid, &opts.attr_commit_id);
320
- if (err < 0)
321
- return Error_set(err);
322
+ size_t len = py_oid_to_git_oid(py_oid, &opts.attr_commit_id);
323
+ if (len == 0) {
324
+ git_blob_free(blob);
325
+ return NULL;
326
+ }
322
327
  }
323
328
 
324
329
  if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)