pygit2 1.15.0__tar.gz → 1.15.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 (188) hide show
  1. {pygit2-1.15.0 → pygit2-1.15.1}/CHANGELOG.md +28 -0
  2. {pygit2-1.15.0 → pygit2-1.15.1}/PKG-INFO +3 -1
  3. {pygit2-1.15.0 → pygit2-1.15.1}/README.md +2 -0
  4. {pygit2-1.15.0 → pygit2-1.15.1}/SPONSORS.md +2 -0
  5. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/_build.py +1 -1
  6. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/_pygit2.pyi +2 -2
  7. pygit2-1.15.1/pygit2/decl/revert.h +21 -0
  8. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/repository.py +14 -1
  9. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/submodules.py +33 -8
  10. {pygit2-1.15.0 → pygit2-1.15.1}/src/diff.c +1 -1
  11. {pygit2-1.15.0 → pygit2-1.15.1}/src/pygit2.c +26 -24
  12. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_diff.py +2 -0
  13. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_remote.py +2 -3
  14. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_repository.py +22 -1
  15. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_submodule.py +71 -6
  16. pygit2-1.15.0/pygit2/decl/revert.h +0 -7
  17. {pygit2-1.15.0 → pygit2-1.15.1}/AUTHORS.md +1 -1
  18. {pygit2-1.15.0 → pygit2-1.15.1}/COPYING +0 -0
  19. {pygit2-1.15.0 → pygit2-1.15.1}/Makefile +0 -0
  20. {pygit2-1.15.0 → pygit2-1.15.1}/build.sh +0 -0
  21. {pygit2-1.15.0 → pygit2-1.15.1}/build_tag.py +0 -0
  22. {pygit2-1.15.0 → pygit2-1.15.1}/mypy-stubtest.ini +0 -0
  23. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/__init__.py +0 -0
  24. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/_run.py +0 -0
  25. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/blame.py +0 -0
  26. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/blob.py +0 -0
  27. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/branches.py +0 -0
  28. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/callbacks.py +0 -0
  29. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/config.py +0 -0
  30. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/credentials.py +0 -0
  31. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/attr.h +0 -0
  32. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/blame.h +0 -0
  33. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/buffer.h +0 -0
  34. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/callbacks.h +0 -0
  35. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/checkout.h +0 -0
  36. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/clone.h +0 -0
  37. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/commit.h +0 -0
  38. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/common.h +0 -0
  39. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/config.h +0 -0
  40. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/describe.h +0 -0
  41. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/diff.h +0 -0
  42. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/errors.h +0 -0
  43. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/graph.h +0 -0
  44. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/index.h +0 -0
  45. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/indexer.h +0 -0
  46. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/merge.h +0 -0
  47. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/net.h +0 -0
  48. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/oid.h +0 -0
  49. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/pack.h +0 -0
  50. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/proxy.h +0 -0
  51. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/refspec.h +0 -0
  52. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/remote.h +0 -0
  53. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/repository.h +0 -0
  54. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/stash.h +0 -0
  55. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/strarray.h +0 -0
  56. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/submodule.h +0 -0
  57. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/transport.h +0 -0
  58. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/decl/types.h +0 -0
  59. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/enums.py +0 -0
  60. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/errors.py +0 -0
  61. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/ffi.py +0 -0
  62. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/filter.py +0 -0
  63. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/index.py +0 -0
  64. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/legacyenums.py +0 -0
  65. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/packbuilder.py +0 -0
  66. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/references.py +0 -0
  67. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/refspec.py +0 -0
  68. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/remotes.py +0 -0
  69. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/settings.py +0 -0
  70. {pygit2-1.15.0 → pygit2-1.15.1}/pygit2/utils.py +0 -0
  71. {pygit2-1.15.0 → pygit2-1.15.1}/pyproject.toml +0 -0
  72. {pygit2-1.15.0 → pygit2-1.15.1}/pytest.ini +0 -0
  73. {pygit2-1.15.0 → pygit2-1.15.1}/requirements-test.txt +0 -0
  74. {pygit2-1.15.0 → pygit2-1.15.1}/requirements.txt +0 -0
  75. {pygit2-1.15.0 → pygit2-1.15.1}/setup.cfg +0 -0
  76. {pygit2-1.15.0 → pygit2-1.15.1}/setup.py +0 -0
  77. {pygit2-1.15.0 → pygit2-1.15.1}/src/blob.c +0 -0
  78. {pygit2-1.15.0 → pygit2-1.15.1}/src/branch.c +0 -0
  79. {pygit2-1.15.0 → pygit2-1.15.1}/src/branch.h +0 -0
  80. {pygit2-1.15.0 → pygit2-1.15.1}/src/commit.c +0 -0
  81. {pygit2-1.15.0 → pygit2-1.15.1}/src/diff.h +0 -0
  82. {pygit2-1.15.0 → pygit2-1.15.1}/src/error.c +0 -0
  83. {pygit2-1.15.0 → pygit2-1.15.1}/src/error.h +0 -0
  84. {pygit2-1.15.0 → pygit2-1.15.1}/src/filter.c +0 -0
  85. {pygit2-1.15.0 → pygit2-1.15.1}/src/filter.h +0 -0
  86. {pygit2-1.15.0 → pygit2-1.15.1}/src/mailmap.c +0 -0
  87. {pygit2-1.15.0 → pygit2-1.15.1}/src/mailmap.h +0 -0
  88. {pygit2-1.15.0 → pygit2-1.15.1}/src/note.c +0 -0
  89. {pygit2-1.15.0 → pygit2-1.15.1}/src/note.h +0 -0
  90. {pygit2-1.15.0 → pygit2-1.15.1}/src/object.c +0 -0
  91. {pygit2-1.15.0 → pygit2-1.15.1}/src/object.h +0 -0
  92. {pygit2-1.15.0 → pygit2-1.15.1}/src/odb.c +0 -0
  93. {pygit2-1.15.0 → pygit2-1.15.1}/src/odb.h +0 -0
  94. {pygit2-1.15.0 → pygit2-1.15.1}/src/odb_backend.c +0 -0
  95. {pygit2-1.15.0 → pygit2-1.15.1}/src/odb_backend.h +0 -0
  96. {pygit2-1.15.0 → pygit2-1.15.1}/src/oid.c +0 -0
  97. {pygit2-1.15.0 → pygit2-1.15.1}/src/oid.h +0 -0
  98. {pygit2-1.15.0 → pygit2-1.15.1}/src/options.c +0 -0
  99. {pygit2-1.15.0 → pygit2-1.15.1}/src/options.h +0 -0
  100. {pygit2-1.15.0 → pygit2-1.15.1}/src/patch.c +0 -0
  101. {pygit2-1.15.0 → pygit2-1.15.1}/src/patch.h +0 -0
  102. {pygit2-1.15.0 → pygit2-1.15.1}/src/refdb.c +0 -0
  103. {pygit2-1.15.0 → pygit2-1.15.1}/src/refdb.h +0 -0
  104. {pygit2-1.15.0 → pygit2-1.15.1}/src/refdb_backend.c +0 -0
  105. {pygit2-1.15.0 → pygit2-1.15.1}/src/refdb_backend.h +0 -0
  106. {pygit2-1.15.0 → pygit2-1.15.1}/src/reference.c +0 -0
  107. {pygit2-1.15.0 → pygit2-1.15.1}/src/reference.h +0 -0
  108. {pygit2-1.15.0 → pygit2-1.15.1}/src/repository.c +0 -0
  109. {pygit2-1.15.0 → pygit2-1.15.1}/src/repository.h +0 -0
  110. {pygit2-1.15.0 → pygit2-1.15.1}/src/revspec.c +0 -0
  111. {pygit2-1.15.0 → pygit2-1.15.1}/src/revspec.h +0 -0
  112. {pygit2-1.15.0 → pygit2-1.15.1}/src/signature.c +0 -0
  113. {pygit2-1.15.0 → pygit2-1.15.1}/src/signature.h +0 -0
  114. {pygit2-1.15.0 → pygit2-1.15.1}/src/stash.c +0 -0
  115. {pygit2-1.15.0 → pygit2-1.15.1}/src/tag.c +0 -0
  116. {pygit2-1.15.0 → pygit2-1.15.1}/src/tree.c +0 -0
  117. {pygit2-1.15.0 → pygit2-1.15.1}/src/tree.h +0 -0
  118. {pygit2-1.15.0 → pygit2-1.15.1}/src/treebuilder.c +0 -0
  119. {pygit2-1.15.0 → pygit2-1.15.1}/src/treebuilder.h +0 -0
  120. {pygit2-1.15.0 → pygit2-1.15.1}/src/types.h +0 -0
  121. {pygit2-1.15.0 → pygit2-1.15.1}/src/utils.c +0 -0
  122. {pygit2-1.15.0 → pygit2-1.15.1}/src/utils.h +0 -0
  123. {pygit2-1.15.0 → pygit2-1.15.1}/src/walker.c +0 -0
  124. {pygit2-1.15.0 → pygit2-1.15.1}/src/walker.h +0 -0
  125. {pygit2-1.15.0 → pygit2-1.15.1}/src/wildmatch.c +0 -0
  126. {pygit2-1.15.0 → pygit2-1.15.1}/src/wildmatch.h +0 -0
  127. {pygit2-1.15.0 → pygit2-1.15.1}/src/worktree.c +0 -0
  128. {pygit2-1.15.0 → pygit2-1.15.1}/src/worktree.h +0 -0
  129. {pygit2-1.15.0 → pygit2-1.15.1}/test/__init__.py +0 -0
  130. {pygit2-1.15.0 → pygit2-1.15.1}/test/conftest.py +0 -0
  131. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/barerepo.zip +0 -0
  132. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/binaryfilerepo.zip +0 -0
  133. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/blameflagsrepo.zip +0 -0
  134. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/dirtyrepo.zip +0 -0
  135. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/emptyrepo.zip +0 -0
  136. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/encoding.zip +0 -0
  137. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/gpgsigned.zip +0 -0
  138. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/submodulerepo.zip +0 -0
  139. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/testrepo.zip +0 -0
  140. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/testrepoformerging.zip +0 -0
  141. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/testrepopacked.zip +0 -0
  142. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/trailerrepo.zip +0 -0
  143. {pygit2-1.15.0 → pygit2-1.15.1}/test/data/utf8branchrepo.zip +0 -0
  144. {pygit2-1.15.0 → pygit2-1.15.1}/test/keys/pygit2_empty +0 -0
  145. {pygit2-1.15.0 → pygit2-1.15.1}/test/keys/pygit2_empty.pub +0 -0
  146. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_apply_diff.py +0 -0
  147. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_archive.py +0 -0
  148. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_attributes.py +0 -0
  149. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_blame.py +0 -0
  150. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_blob.py +0 -0
  151. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_branch.py +0 -0
  152. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_branch_empty.py +0 -0
  153. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_cherrypick.py +0 -0
  154. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_commit.py +0 -0
  155. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_commit_gpg.py +0 -0
  156. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_commit_trailer.py +0 -0
  157. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_config.py +0 -0
  158. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_credentials.py +0 -0
  159. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_describe.py +0 -0
  160. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_diff_binary.py +0 -0
  161. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_filter.py +0 -0
  162. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_index.py +0 -0
  163. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_mailmap.py +0 -0
  164. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_merge.py +0 -0
  165. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_note.py +0 -0
  166. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_object.py +0 -0
  167. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_odb.py +0 -0
  168. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_odb_backend.py +0 -0
  169. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_oid.py +0 -0
  170. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_options.py +0 -0
  171. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_packbuilder.py +0 -0
  172. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_patch.py +0 -0
  173. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_patch_encoding.py +0 -0
  174. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_refdb_backend.py +0 -0
  175. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_refs.py +0 -0
  176. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_remote_prune.py +0 -0
  177. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_remote_utf8.py +0 -0
  178. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_repository_bare.py +0 -0
  179. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_repository_custom.py +0 -0
  180. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_repository_empty.py +0 -0
  181. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_revparse.py +0 -0
  182. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_revwalk.py +0 -0
  183. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_signature.py +0 -0
  184. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_status.py +0 -0
  185. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_tag.py +0 -0
  186. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_tree.py +0 -0
  187. {pygit2-1.15.0 → pygit2-1.15.1}/test/test_treebuilder.py +0 -0
  188. {pygit2-1.15.0 → pygit2-1.15.1}/test/utils.py +0 -0
@@ -1,3 +1,31 @@
1
+ # 1.15.1 (2024-07-07)
2
+
3
+ - New `Repository.revert(...)`
4
+ [#1297](https://github.com/libgit2/pygit2/pull/1297)
5
+
6
+ - New optional `depth` argument in submodules `add()` and `update()` methods
7
+ [#1296](https://github.com/libgit2/pygit2/pull/1296)
8
+
9
+ - Now `Submodule.url` returns `None` when the submodule does not have a url
10
+ [#1294](https://github.com/libgit2/pygit2/pull/1294)
11
+
12
+ - Fix use after free bug in error reporting
13
+ [#1299](https://github.com/libgit2/pygit2/pull/1299)
14
+
15
+ - Fix `Submodule.head_id` when the submodule is not in the current HEAD tree
16
+ [#1300](https://github.com/libgit2/pygit2/pull/1300)
17
+
18
+ - Fix `Submodule.open()` when subclassing `Repository`
19
+ [#1295](https://github.com/libgit2/pygit2/pull/1295)
20
+
21
+ - Fix error in the test suite when running with address sanitizer
22
+ [#1304](https://github.com/libgit2/pygit2/pull/1304)
23
+ [#1301](https://github.com/libgit2/pygit2/issues/1301)
24
+
25
+ - Annotations and documentation fixes
26
+ [#1293](https://github.com/libgit2/pygit2/pull/1293)
27
+
28
+
1
29
  # 1.15.0 (2024-05-18)
2
30
 
3
31
  - Many deprecated features have been removed, see below
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pygit2
3
- Version: 1.15.0
3
+ Version: 1.15.1
4
4
  Summary: Python bindings for libgit2.
5
5
  Home-page: https://github.com/libgit2/pygit2
6
6
  Maintainer: J. David Ibáñez
@@ -47,6 +47,8 @@ Supports Python 3.9 to 3.12 and PyPy3 7.3+
47
47
 
48
48
  ## Sponsors
49
49
 
50
+ - [Microsoft](https://github.com/microsoft)
51
+
50
52
  Add your name and link here, [become a
51
53
  sponsor](https://github.com/sponsors/jdavid).
52
54
 
@@ -18,6 +18,8 @@ Supports Python 3.9 to 3.12 and PyPy3 7.3+
18
18
 
19
19
  ## Sponsors
20
20
 
21
+ - [Microsoft](https://github.com/microsoft)
22
+
21
23
  Add your name and link here, [become a
22
24
  sponsor](https://github.com/sponsors/jdavid).
23
25
 
@@ -1,5 +1,6 @@
1
1
  Friends of pygit2:
2
2
 
3
+ - [Microsoft](https://github.com/microsoft)
3
4
 
4
5
  Add your name to the list,
5
6
  [become a friend of pygit2](https://github.com/sponsors/jdavid).
@@ -8,4 +9,5 @@ Past sponsors:
8
9
 
9
10
  - [Iterative](https://iterative.ai/)
10
11
  - [SourceHut](https://sourcehut.org)
12
+ - [GitHub](https://github.com/github)
11
13
  - [omniproc](https://github.com/omniproc)
@@ -34,7 +34,7 @@ from pathlib import Path
34
34
  #
35
35
  # The version number of pygit2
36
36
  #
37
- __version__ = '1.15.0'
37
+ __version__ = '1.15.1'
38
38
 
39
39
 
40
40
  #
@@ -4,12 +4,12 @@ from . import Index, Submodule
4
4
  from .enums import (
5
5
  ApplyLocation,
6
6
  BranchType,
7
+ DeltaStatus,
7
8
  DiffFind,
8
9
  DiffFlag,
9
10
  DiffOption,
10
11
  DiffStatsFormat,
11
12
  FileMode,
12
- FileStatus,
13
13
  MergeAnalysis,
14
14
  MergePreference,
15
15
  ObjectType,
@@ -171,7 +171,7 @@ class DiffDelta:
171
171
  new_file: DiffFile
172
172
  old_file: DiffFile
173
173
  similarity: int
174
- status: FileStatus
174
+ status: DeltaStatus
175
175
  def status_char(self) -> str: ...
176
176
 
177
177
  class DiffFile:
@@ -0,0 +1,21 @@
1
+ #define GIT_REVERT_OPTIONS_VERSION ...
2
+
3
+ typedef struct {
4
+ unsigned int version;
5
+ unsigned int mainline;
6
+ git_merge_options merge_opts;
7
+ git_checkout_options checkout_opts;
8
+ } git_revert_options;
9
+
10
+ int git_revert(
11
+ git_repository *repo,
12
+ git_commit *commit,
13
+ const git_revert_options *given_opts);
14
+
15
+ int git_revert_commit(
16
+ git_index **out,
17
+ git_repository *repo,
18
+ git_commit *revert_commit,
19
+ git_commit *our_commit,
20
+ unsigned int mainline,
21
+ const git_merge_options *merge_options);
@@ -1343,6 +1343,19 @@ class BaseRepository(_Repository):
1343
1343
  err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email))
1344
1344
  check_error(err)
1345
1345
 
1346
+ def revert(self, commit: Commit):
1347
+ """
1348
+ Revert the given commit, producing changes in the index and working
1349
+ directory.
1350
+
1351
+ This operation updates the repository's state and prepared message
1352
+ (MERGE_MSG).
1353
+ """
1354
+ commit_ptr = ffi.new('git_commit **')
1355
+ ffi.buffer(commit_ptr)[:] = commit._pointer[:]
1356
+ err = C.git_revert(self._repo, commit_ptr[0], ffi.NULL)
1357
+ check_error(err)
1358
+
1346
1359
  def revert_commit(self, revert_commit, our_commit, mainline=0):
1347
1360
  """
1348
1361
  Revert the given Commit against the given "our" Commit, producing an
@@ -1548,6 +1561,6 @@ class Repository(BaseRepository):
1548
1561
  cptr = ffi.new('git_repository **')
1549
1562
  cptr[0] = ptr
1550
1563
  repo = cls.__new__(cls)
1551
- super(cls, repo)._from_c(bytes(ffi.buffer(cptr)[:]), owned)
1564
+ BaseRepository._from_c(repo, bytes(ffi.buffer(cptr)[:]), owned)
1552
1565
  repo._common_init()
1553
1566
  return repo
@@ -31,7 +31,7 @@ from .callbacks import git_fetch_options, RemoteCallbacks
31
31
  from .enums import SubmoduleIgnore, SubmoduleStatus
32
32
  from .errors import check_error
33
33
  from .ffi import ffi, C
34
- from .utils import to_bytes
34
+ from .utils import to_bytes, maybe_string
35
35
 
36
36
  # Need BaseRepository for type hints, but don't let it cause a circular dependency
37
37
  if TYPE_CHECKING:
@@ -73,7 +73,9 @@ class Submodule:
73
73
  err = C.git_submodule_init(self._subm, int(overwrite))
74
74
  check_error(err)
75
75
 
76
- def update(self, init: bool = False, callbacks: RemoteCallbacks = None):
76
+ def update(
77
+ self, init: bool = False, callbacks: RemoteCallbacks = None, depth: int = 0
78
+ ):
77
79
  """
78
80
  Update a submodule. This will clone a missing submodule and checkout
79
81
  the subrepository to the commit specified in the index of the
@@ -90,12 +92,17 @@ class Submodule:
90
92
 
91
93
  callbacks
92
94
  Optional RemoteCallbacks to clone or fetch the submodule.
95
+
96
+ depth
97
+ Number of commits to fetch.
98
+ The default is 0 (full commit history).
93
99
  """
94
100
 
95
101
  opts = ffi.new('git_submodule_update_options *')
96
102
  C.git_submodule_update_options_init(
97
103
  opts, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION
98
104
  )
105
+ opts.fetch_opts.depth = depth
99
106
 
100
107
  with git_fetch_options(callbacks, opts=opts.fetch_opts) as payload:
101
108
  err = C.git_submodule_update(self._subm, int(init), opts)
@@ -129,10 +136,10 @@ class Submodule:
129
136
  return ffi.string(path).decode('utf-8')
130
137
 
131
138
  @property
132
- def url(self):
139
+ def url(self) -> Union[str, None]:
133
140
  """URL of the submodule."""
134
141
  url = C.git_submodule_url(self._subm)
135
- return ffi.string(url).decode('utf-8')
142
+ return maybe_string(url)
136
143
 
137
144
  @property
138
145
  def branch(self):
@@ -141,10 +148,17 @@ class Submodule:
141
148
  return ffi.string(branch).decode('utf-8')
142
149
 
143
150
  @property
144
- def head_id(self):
145
- """Head of the submodule."""
151
+ def head_id(self) -> Union[Oid, None]:
152
+ """
153
+ The submodule's HEAD commit id (as recorded in the superproject's
154
+ current HEAD tree).
155
+ Returns None if the superproject's HEAD doesn't contain the submodule.
156
+ """
157
+
146
158
  head = C.git_submodule_head_id(self._subm)
147
- return Oid(raw=bytes(ffi.buffer(head)[:]))
159
+ if head == ffi.NULL:
160
+ return None
161
+ return Oid(raw=bytes(ffi.buffer(head.id)[:]))
148
162
 
149
163
 
150
164
  class SubmoduleCollection:
@@ -188,6 +202,7 @@ class SubmoduleCollection:
188
202
  path: str,
189
203
  link: bool = True,
190
204
  callbacks: Optional[RemoteCallbacks] = None,
205
+ depth: int = 0,
191
206
  ) -> Submodule:
192
207
  """
193
208
  Add a submodule to the index.
@@ -208,6 +223,10 @@ class SubmoduleCollection:
208
223
 
209
224
  callbacks
210
225
  Optional RemoteCallbacks to clone the submodule.
226
+
227
+ depth
228
+ Number of commits to fetch.
229
+ The default is 0 (full commit history).
211
230
  """
212
231
  csub = ffi.new('git_submodule **')
213
232
  curl = ffi.new('char[]', to_bytes(url))
@@ -226,6 +245,7 @@ class SubmoduleCollection:
226
245
  C.git_submodule_update_options_init(
227
246
  opts, C.GIT_SUBMODULE_UPDATE_OPTIONS_VERSION
228
247
  )
248
+ opts.fetch_opts.depth = depth
229
249
 
230
250
  with git_fetch_options(callbacks, opts=opts.fetch_opts) as payload:
231
251
  crepo = ffi.new('git_repository **')
@@ -268,6 +288,7 @@ class SubmoduleCollection:
268
288
  submodules: Optional[Iterable[str]] = None,
269
289
  init: bool = False,
270
290
  callbacks: Optional[RemoteCallbacks] = None,
291
+ depth: int = 0,
271
292
  ):
272
293
  """
273
294
  Update submodules. This will clone a missing submodule and checkout
@@ -289,6 +310,10 @@ class SubmoduleCollection:
289
310
 
290
311
  callbacks
291
312
  Optional RemoteCallbacks to clone or fetch the submodule.
313
+
314
+ depth
315
+ Number of commits to fetch.
316
+ The default is 0 (full commit history).
292
317
  """
293
318
  if submodules is None:
294
319
  submodules = self._repository.listall_submodules()
@@ -296,7 +321,7 @@ class SubmoduleCollection:
296
321
  instances = [self[s] for s in submodules]
297
322
 
298
323
  for submodule in instances:
299
- submodule.update(init, callbacks)
324
+ submodule.update(init, callbacks, depth)
300
325
 
301
326
  def status(
302
327
  self, name: str, ignore: SubmoduleIgnore = SubmoduleIgnore.UNSPECIFIED
@@ -323,7 +323,7 @@ DiffDelta_is_binary__get__(DiffDelta *self)
323
323
  }
324
324
 
325
325
  PyDoc_STRVAR(DiffDelta_status__doc__,
326
- "An enums.FileStatus constant."
326
+ "An enums.DeltaStatus constant."
327
327
  );
328
328
 
329
329
  PyObject *
@@ -109,6 +109,7 @@ discover_repository(PyObject *self, PyObject *args)
109
109
  const char *ceiling_dirs = NULL;
110
110
  PyObject *py_repo_path = NULL;
111
111
  int err;
112
+ PyObject *result = NULL;
112
113
 
113
114
  if (!PyArg_ParseTuple(args, "O&|IO&", PyUnicode_FSConverter, &py_path, &across_fs,
114
115
  PyUnicode_FSConverter, &py_ceiling_dirs))
@@ -122,18 +123,20 @@ discover_repository(PyObject *self, PyObject *args)
122
123
  memset(&repo_path, 0, sizeof(git_buf));
123
124
  err = git_repository_discover(&repo_path, path, across_fs, ceiling_dirs);
124
125
 
125
- Py_XDECREF(py_path);
126
- Py_XDECREF(py_ceiling_dirs);
127
-
128
- if (err == GIT_ENOTFOUND)
129
- Py_RETURN_NONE;
130
- if (err < 0)
131
- return Error_set_str(err, path);
126
+ if (err == GIT_OK) {
127
+ py_repo_path = PyUnicode_DecodeFSDefault(repo_path.ptr);
128
+ git_buf_dispose(&repo_path);
129
+ result = py_repo_path;
130
+ } else if (err == GIT_ENOTFOUND) {
131
+ result = Py_None;
132
+ } else {
133
+ result = Error_set_str(err, path);
134
+ }
132
135
 
133
- py_repo_path = PyUnicode_DecodeFSDefault(repo_path.ptr);
134
- git_buf_dispose(&repo_path);
136
+ Py_XDECREF(py_ceiling_dirs);
137
+ Py_XDECREF(py_path);
135
138
 
136
- return py_repo_path;
139
+ return result;
137
140
  };
138
141
 
139
142
  PyDoc_STRVAR(hashfile__doc__,
@@ -200,6 +203,7 @@ init_file_backend(PyObject *self, PyObject *args)
200
203
  unsigned int flags = 0;
201
204
  int err = GIT_OK;
202
205
  git_repository *repository = NULL;
206
+ PyObject *result = NULL;
203
207
 
204
208
  if (!PyArg_ParseTuple(args, "O&|I", PyUnicode_FSConverter, &py_path, &flags))
205
209
  return NULL;
@@ -208,25 +212,23 @@ init_file_backend(PyObject *self, PyObject *args)
208
212
 
209
213
  err = git_repository_open_ext(&repository, path, flags, NULL);
210
214
 
211
- Py_XDECREF(py_path);
212
-
213
- if (err < 0) {
215
+ if (err == GIT_OK) {
216
+ result = PyCapsule_New(repository, "backend", NULL);
217
+ } else {
218
+ result = NULL;
214
219
  Error_set_str(err, path);
215
- goto cleanup;
216
- }
217
-
218
- return PyCapsule_New(repository, "backend", NULL);
219
220
 
220
- cleanup:
221
- if (repository) {
222
- git_repository_free(repository);
223
- }
221
+ if (repository) {
222
+ git_repository_free(repository);
223
+ }
224
224
 
225
- if (err == GIT_ENOTFOUND) {
226
- PyErr_Format(GitError, "Repository not found at %s", path);
225
+ if (err == GIT_ENOTFOUND) {
226
+ PyErr_Format(GitError, "Repository not found at %s", path);
227
+ }
227
228
  }
228
229
 
229
- return NULL;
230
+ Py_XDECREF(py_path);
231
+ return result;
230
232
  }
231
233
 
232
234
 
@@ -339,6 +339,8 @@ def test_deltas(barerepo):
339
339
  assert len(deltas) == len(patches)
340
340
  for i, delta in enumerate(deltas):
341
341
  patch_delta = patches[i].delta
342
+ assert isinstance(delta.status, DeltaStatus)
343
+ assert isinstance(patch_delta.status, DeltaStatus)
342
344
  assert delta.status == patch_delta.status
343
345
  assert delta.similarity == patch_delta.similarity
344
346
  assert delta.nfiles == patch_delta.nfiles
@@ -373,10 +373,9 @@ def test_push_options(mock_callbacks, origin, clone, remote):
373
373
  remote.push(['refs/heads/master'], push_options=['foo'])
374
374
  remote_push_options = mock_callbacks.return_value.push_options.remote_push_options
375
375
  assert remote_push_options.count == 1
376
- assert ffi.string(remote_push_options.strings[0]) == b'foo'
376
+ # strings pointed to by remote_push_options.strings[] are already freed
377
377
 
378
378
  remote.push(['refs/heads/master'], push_options=['Option A', 'Option B'])
379
379
  remote_push_options = mock_callbacks.return_value.push_options.remote_push_options
380
380
  assert remote_push_options.count == 2
381
- assert ffi.string(remote_push_options.strings[0]) == b'Option A'
382
- assert ffi.string(remote_push_options.strings[1]) == b'Option B'
381
+ # strings pointed to by remote_push_options.strings[] are already freed
@@ -39,6 +39,7 @@ from pygit2.enums import (
39
39
  FileStatus,
40
40
  ObjectType,
41
41
  RepositoryOpenFlag,
42
+ RepositoryState,
42
43
  ResetMode,
43
44
  StashApplyProgress,
44
45
  )
@@ -538,7 +539,7 @@ def test_stash_apply_checkout_options(testrepo):
538
539
  assert f.read() == 'stashed content'
539
540
 
540
541
 
541
- def test_revert(testrepo):
542
+ def test_revert_commit(testrepo):
542
543
  master = testrepo.head.peel()
543
544
  commit_to_revert = testrepo['4ec4389a8068641da2d6578db0419484972284c8']
544
545
  parent = commit_to_revert.parents[0]
@@ -552,6 +553,26 @@ def test_revert(testrepo):
552
553
  assert revert_diff_stats.files_changed == commit_diff_stats.files_changed
553
554
 
554
555
 
556
+ def test_revert(testrepo):
557
+ hello_txt = Path(testrepo.workdir) / 'hello.txt'
558
+ commit_to_revert = testrepo['4ec4389a8068641da2d6578db0419484972284c8']
559
+
560
+ assert testrepo.state() == RepositoryState.NONE
561
+ assert not testrepo.message
562
+ assert 'bonjour le monde' in hello_txt.read_text()
563
+
564
+ # Revert addition of French line in hello.txt
565
+ testrepo.revert(commit_to_revert)
566
+
567
+ assert 'bonjour le monde' not in hello_txt.read_text()
568
+ assert testrepo.status()['hello.txt'] == FileStatus.INDEX_MODIFIED
569
+ assert testrepo.state() == RepositoryState.REVERT
570
+ assert (
571
+ testrepo.message
572
+ == f'Revert "Say hello in French"\n\nThis reverts commit {commit_to_revert.id}.\n'
573
+ )
574
+
575
+
555
576
  def test_default_signature(testrepo):
556
577
  config = testrepo.config
557
578
  config['user.name'] = 'Random J Hacker'
@@ -38,6 +38,7 @@ SUBM_NAME = 'TestGitRepository'
38
38
  SUBM_PATH = 'TestGitRepository'
39
39
  SUBM_URL = 'https://github.com/libgit2/TestGitRepository'
40
40
  SUBM_HEAD_SHA = '49322bb17d3acc9146f98c97d078513228bbf3c0'
41
+ SUBM_BOTTOM_SHA = '6c8b137b1c652731597c89668f417b8695f28dd7'
41
42
 
42
43
 
43
44
  @pytest.fixture
@@ -91,6 +92,20 @@ def test_submodule_open(repo):
91
92
  assert r.head.target == SUBM_HEAD_SHA
92
93
 
93
94
 
95
+ @utils.requires_network
96
+ def test_submodule_open_from_repository_subclass(repo):
97
+ class CustomRepoClass(pygit2.Repository):
98
+ pass
99
+
100
+ custom_repo = CustomRepoClass(repo.workdir)
101
+ s = custom_repo.submodules[SUBM_PATH]
102
+ custom_repo.submodules.init()
103
+ custom_repo.submodules.update()
104
+ r = s.open()
105
+ assert isinstance(r, CustomRepoClass)
106
+ assert r.head.target == SUBM_HEAD_SHA
107
+
108
+
94
109
  def test_name(repo):
95
110
  s = repo.submodules[SUBM_PATH]
96
111
  assert SUBM_NAME == s.name
@@ -106,6 +121,15 @@ def test_url(repo):
106
121
  assert SUBM_URL == s.url
107
122
 
108
123
 
124
+ def test_missing_url(repo):
125
+ # Remove "url" from .gitmodules
126
+ with open(Path(repo.workdir, '.gitmodules'), 'wt') as f:
127
+ f.write('[submodule "TestGitRepository"]\n')
128
+ f.write('\tpath = TestGitRepository\n')
129
+ s = repo.submodules[SUBM_PATH]
130
+ assert not s.url
131
+
132
+
109
133
  @utils.requires_network
110
134
  def test_init_and_update(repo):
111
135
  subrepo_file_path = Path(repo.workdir) / SUBM_PATH / 'master.txt'
@@ -143,27 +167,43 @@ def test_update_instance(repo):
143
167
 
144
168
 
145
169
  @utils.requires_network
146
- def test_oneshot_update(repo):
170
+ @pytest.mark.parametrize('depth', [0, 1])
171
+ def test_oneshot_update(repo, depth):
147
172
  status = repo.submodules.status(SUBM_NAME)
148
173
  assert status == (SS.IN_HEAD | SS.IN_INDEX | SS.IN_CONFIG | SS.WD_UNINITIALIZED)
149
174
 
150
175
  subrepo_file_path = Path(repo.workdir) / SUBM_PATH / 'master.txt'
151
176
  assert not subrepo_file_path.exists()
152
- repo.submodules.update(init=True)
177
+ repo.submodules.update(init=True, depth=depth)
153
178
  assert subrepo_file_path.exists()
154
179
 
155
180
  status = repo.submodules.status(SUBM_NAME)
156
181
  assert status == (SS.IN_HEAD | SS.IN_INDEX | SS.IN_CONFIG | SS.IN_WD)
157
182
 
183
+ sm_repo = repo.submodules[SUBM_NAME].open()
184
+ if depth == 0:
185
+ sm_repo[SUBM_BOTTOM_SHA] # full history must be available
186
+ else:
187
+ with pytest.raises(KeyError):
188
+ sm_repo[SUBM_BOTTOM_SHA] # shallow clone
189
+
158
190
 
159
191
  @utils.requires_network
160
- def test_oneshot_update_instance(repo):
192
+ @pytest.mark.parametrize('depth', [0, 1])
193
+ def test_oneshot_update_instance(repo, depth):
161
194
  subrepo_file_path = Path(repo.workdir) / SUBM_PATH / 'master.txt'
162
195
  assert not subrepo_file_path.exists()
163
196
  sm = repo.submodules[SUBM_NAME]
164
- sm.update(init=True)
197
+ sm.update(init=True, depth=depth)
165
198
  assert subrepo_file_path.exists()
166
199
 
200
+ sm_repo = sm.open()
201
+ if depth == 0:
202
+ sm_repo[SUBM_BOTTOM_SHA] # full history must be available
203
+ else:
204
+ with pytest.raises(KeyError):
205
+ sm_repo[SUBM_BOTTOM_SHA] # shallow clone
206
+
167
207
 
168
208
  @utils.requires_network
169
209
  def test_head_id(repo):
@@ -171,9 +211,28 @@ def test_head_id(repo):
171
211
 
172
212
 
173
213
  @utils.requires_network
174
- def test_add_submodule(repo):
214
+ def test_head_id_null(repo):
215
+ gitmodules_newlines = (
216
+ '\n'
217
+ '[submodule "uncommitted_submodule"]\n'
218
+ ' path = pygit2\n'
219
+ ' url = https://github.com/libgit2/pygit2\n'
220
+ '\n'
221
+ )
222
+ with open(Path(repo.workdir, '.gitmodules'), 'a') as f:
223
+ f.write(gitmodules_newlines)
224
+
225
+ subm = repo.submodules['uncommitted_submodule']
226
+
227
+ # The submodule isn't in the HEAD yet, so head_id should be None
228
+ assert subm.head_id is None
229
+
230
+
231
+ @utils.requires_network
232
+ @pytest.mark.parametrize('depth', [0, 1])
233
+ def test_add_submodule(repo, depth):
175
234
  sm_repo_path = 'test/testrepo'
176
- sm = repo.submodules.add(SUBM_URL, sm_repo_path)
235
+ sm = repo.submodules.add(SUBM_URL, sm_repo_path, depth=depth)
177
236
 
178
237
  status = repo.submodules.status(sm_repo_path)
179
238
  assert status == (SS.IN_INDEX | SS.IN_CONFIG | SS.IN_WD | SS.INDEX_ADDED)
@@ -183,6 +242,12 @@ def test_add_submodule(repo):
183
242
  assert SUBM_URL == sm.url
184
243
  assert not sm_repo.is_empty
185
244
 
245
+ if depth == 0:
246
+ sm_repo[SUBM_BOTTOM_SHA] # full history must be available
247
+ else:
248
+ with pytest.raises(KeyError):
249
+ sm_repo[SUBM_BOTTOM_SHA] # shallow clone
250
+
186
251
 
187
252
  @utils.requires_network
188
253
  def test_submodule_status(repo):
@@ -1,7 +0,0 @@
1
- int git_revert_commit(
2
- git_index **out,
3
- git_repository *repo,
4
- git_commit *revert_commit,
5
- git_commit *our_commit,
6
- unsigned int mainline,
7
- const git_merge_options *merge_options);
@@ -50,6 +50,7 @@ Authors:
50
50
  Dan Sully
51
51
  David Versmisse
52
52
  Grégory Herrero
53
+ Michał Kępień
53
54
  Mikhail Yushkovskiy
54
55
  Robin Stocker
55
56
  Rohit Sanjay
@@ -72,7 +73,6 @@ Authors:
72
73
  Jason Ziglar
73
74
  Leonardo Rhodes
74
75
  Mark Adams
75
- Michał Kępień
76
76
  Nika Layzell
77
77
  Peter-Yi Zhang
78
78
  Petr Viktorin
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes