summaryrefslogtreecommitdiffstats
path: root/vendor/gix-commitgraph
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-commitgraph')
-rw-r--r--vendor/gix-commitgraph/.cargo-checksum.json1
-rw-r--r--vendor/gix-commitgraph/CHANGELOG.md603
-rw-r--r--vendor/gix-commitgraph/Cargo.toml80
-rw-r--r--vendor/gix-commitgraph/LICENSE-APACHE191
-rw-r--r--vendor/gix-commitgraph/LICENSE-MIT21
-rw-r--r--vendor/gix-commitgraph/src/access.rs97
-rw-r--r--vendor/gix-commitgraph/src/file/access.rs138
-rw-r--r--vendor/gix-commitgraph/src/file/commit.rs258
-rw-r--r--vendor/gix-commitgraph/src/file/init.rs257
-rw-r--r--vendor/gix-commitgraph/src/file/mod.rs46
-rw-r--r--vendor/gix-commitgraph/src/file/verify.rs173
-rw-r--r--vendor/gix-commitgraph/src/init.rs130
-rw-r--r--vendor/gix-commitgraph/src/lib.rs77
-rw-r--r--vendor/gix-commitgraph/src/verify.rs205
14 files changed, 2277 insertions, 0 deletions
diff --git a/vendor/gix-commitgraph/.cargo-checksum.json b/vendor/gix-commitgraph/.cargo-checksum.json
new file mode 100644
index 000000000..541d4f00c
--- /dev/null
+++ b/vendor/gix-commitgraph/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"59a48c496d4494d0823b0aae6c2849e160be5cf032b565bf6ad52d13f1755108","Cargo.toml":"c3618823ed996b8a7c7b6460ea64f3a7f944062b5af08309fb954721e7a764cb","LICENSE-APACHE":"cb4780590812826851ba250f90bed0ed19506ec98f6865a0e2e20bbf62391ff9","LICENSE-MIT":"49df47913ab2beafe8dc45607877ae64198bf0eee64aaad3e82ed9e4d27424e8","src/access.rs":"8e4773363e488c88d619a7249203e75054ea6151056b24ce98c2e6554f8d66e8","src/file/access.rs":"450f98c15438cdfbce5cce6e74357a2a6c46da71bd6ee99273dc381f49337110","src/file/commit.rs":"cc279b9f180c29b3515cb0f64f3e745a32000e615bed5dd24d014d45f6a4fd1d","src/file/init.rs":"8d93d50c71ac0d868a383b48b0d00abd9383db2b2184688cfa04ba640a159696","src/file/mod.rs":"c8bc1c0e89918c48c8a7b316bdb31213401b9f5e20b682be726d4a73e18c817c","src/file/verify.rs":"c7ba0082a33d31feb2d0b9ab653d7a46c9d68bdbb7f785727b1ae6a8630b1824","src/init.rs":"efd014b6c5b2052a207ba36f97d5ad2a5d78d9f60f96718fa66b582a8ab53045","src/lib.rs":"2f0a6d72f383a483c92b16428739a46e42556ee16fc36ab8dd6001ea8c287919","src/verify.rs":"72ce3945017c51af03e3ca6b0268717203aa5280297b4f38c91263d56d2cdf60"},"package":"e8490ae1b3d55c47e6a71d247c082304a2f79f8d0332c1a2f5693d42a2021a09"} \ No newline at end of file
diff --git a/vendor/gix-commitgraph/CHANGELOG.md b/vendor/gix-commitgraph/CHANGELOG.md
new file mode 100644
index 000000000..a431e56d6
--- /dev/null
+++ b/vendor/gix-commitgraph/CHANGELOG.md
@@ -0,0 +1,603 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## 0.16.0 (2023-06-06)
+
+### New Features
+
+ - <csr-id-50b45dc1e48eca69ec0ac6679b56712c9bc6e744/> add `at()` function on module level.
+ That way it's more similar to `gix_odb::at()` as there is effectively only one
+ important type.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 10 commits contributed to the release over the course of 17 calendar days.
+ - 18 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Prepare changelogs prior to release ([`8f15cec`](https://github.com/Byron/gitoxide/commit/8f15cec1ec7d5a9d56bb158f155011ef2bb3539b))
+ - Merge branch 'integrate-gix-negotiate' ([`ae845de`](https://github.com/Byron/gitoxide/commit/ae845dea6cee6523c88a23d7a14293589cf8092f))
+ - Add note about corrected generation dates ([`f3193c9`](https://github.com/Byron/gitoxide/commit/f3193c9729c935be844df8faeb2e696844ba8d1f))
+ - Merge branch 'fix-docs' ([`420553a`](https://github.com/Byron/gitoxide/commit/420553a10d780e0b2dc466cac120989298a5f187))
+ - Cleaning up documentation ([`2578e57`](https://github.com/Byron/gitoxide/commit/2578e576bfa365d194a23a1fb0bf09be230873de))
+ - Merge branch 'main' into auto-clippy ([`3ef5c90`](https://github.com/Byron/gitoxide/commit/3ef5c90aebce23385815f1df674c1d28d58b4b0d))
+ - Merge branch 'blinxen/main' ([`9375cd7`](https://github.com/Byron/gitoxide/commit/9375cd75b01aa22a0e2eed6305fe45fabfd6c1ac))
+ - Include license files in all crates ([`facaaf6`](https://github.com/Byron/gitoxide/commit/facaaf633f01c857dcf2572c6dbe0a92b7105c1c))
+ - Merge branch 'consecutive-negotiation' ([`97b3f7e`](https://github.com/Byron/gitoxide/commit/97b3f7e2eaddea20c98f2f7ab6a0d2e2117b0793))
+ - Add `at()` function on module level. ([`50b45dc`](https://github.com/Byron/gitoxide/commit/50b45dc1e48eca69ec0ac6679b56712c9bc6e744))
+</details>
+
+## 0.15.0 (2023-05-19)
+
+<csr-id-967f3b954e9fb4fc7757f8920998173caf0491ab/>
+
+### New Features (BREAKING)
+
+ - <csr-id-ed258da9015d2d68734aeac485dd009760fc4da4/> `describe` usees commitgraph.
+ With it it can leverage the commitgraph data structure would would be more prominent
+ on server-side applications, presumably.
+
+### Refactor (BREAKING)
+
+ - <csr-id-967f3b954e9fb4fc7757f8920998173caf0491ab/> make API more consistent with other `gix-*` crates.
+ For that, we remove duplicate import paths for types.
+ We also improve lifetimes around parent iteration, and make the type explicit.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 4 commits contributed to the release over the course of 1 calendar day.
+ - 21 days passed between releases.
+ - 2 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Release gix-commitgraph v0.15.0, gix-revision v0.14.0, gix-negotiate v0.1.0, safety bump 7 crates ([`92832ca`](https://github.com/Byron/gitoxide/commit/92832ca2899cd2f222f4c7b1cc9e766178f55806))
+ - Merge branch 'consecutive-negotiation' ([`4507f94`](https://github.com/Byron/gitoxide/commit/4507f94984c811ea098e43472e5f54ec4dbb90c1))
+ - `describe` usees commitgraph. ([`ed258da`](https://github.com/Byron/gitoxide/commit/ed258da9015d2d68734aeac485dd009760fc4da4))
+ - Make API more consistent with other `gix-*` crates. ([`967f3b9`](https://github.com/Byron/gitoxide/commit/967f3b954e9fb4fc7757f8920998173caf0491ab))
+</details>
+
+## 0.14.0 (2023-04-27)
+
+### New Features (BREAKING)
+
+ - <csr-id-b83ee366a3c65c717beb587ad809268f1c54b8ad/> Rename `serde1` cargo feature to `serde` and use the weak-deps cargo capability.
+ With it it's possible to not automatically declare all optional dependencies externally visible
+ features, and thus re-use feature names that oterwise are also a crate name.
+
+ Previously I thought that `serde1` is for future-proofing and supporting multiple serde versions
+ at the same time. However, it's most definitely a burden I wouldn't want anyway, so using
+ `serde` seems to be the way to go into the future.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 10 commits contributed to the release over the course of 57 calendar days.
+ - 61 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 1 unique issue was worked on: [#814](https://github.com/Byron/gitoxide/issues/814)
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **[#814](https://github.com/Byron/gitoxide/issues/814)**
+ - Rename `serde1` cargo feature to `serde` and use the weak-deps cargo capability. ([`b83ee36`](https://github.com/Byron/gitoxide/commit/b83ee366a3c65c717beb587ad809268f1c54b8ad))
+ * **Uncategorized**
+ - Release gix-commitgraph v0.14.0, gitoxide-core v0.26.0, gitoxide v0.24.0 ([`9f2317f`](https://github.com/Byron/gitoxide/commit/9f2317f2514872001168d2be6e33e2ee2872420e))
+ - Release gix-hash v0.11.1, gix-path v0.7.4, gix-glob v0.6.0, gix-attributes v0.11.0, gix-config-value v0.11.0, gix-fs v0.1.1, gix-tempfile v5.0.3, gix-utils v0.1.1, gix-lock v5.0.1, gix-object v0.29.1, gix-ref v0.28.0, gix-sec v0.7.0, gix-config v0.21.0, gix-prompt v0.4.0, gix-url v0.17.0, gix-credentials v0.13.0, gix-diff v0.29.0, gix-discover v0.17.0, gix-hashtable v0.2.0, gix-ignore v0.1.0, gix-bitmap v0.2.3, gix-traverse v0.25.0, gix-index v0.16.0, gix-mailmap v0.12.0, gix-pack v0.34.0, gix-odb v0.44.0, gix-packetline v0.16.0, gix-transport v0.30.0, gix-protocol v0.31.0, gix-revision v0.13.0, gix-refspec v0.10.0, gix-worktree v0.16.0, gix v0.44.0, safety bump 7 crates ([`91134a1`](https://github.com/Byron/gitoxide/commit/91134a11c8ba0e942f692488ec9bce9fa1086324))
+ - Release gix-utils v0.1.0, gix-hash v0.11.0, gix-date v0.5.0, gix-features v0.29.0, gix-actor v0.20.0, gix-object v0.29.0, gix-archive v0.1.0, gix-fs v0.1.0, safety bump 25 crates ([`8dbd0a6`](https://github.com/Byron/gitoxide/commit/8dbd0a60557a85acfa231800a058cbac0271a8cf))
+ - Merge branch 'main' into dev ([`cdef398`](https://github.com/Byron/gitoxide/commit/cdef398c4a3bd01baf0be2c27a3f77a400172b0d))
+ - Rename the serde1 feature to serde ([`19338d9`](https://github.com/Byron/gitoxide/commit/19338d934b6712b7d6bd3fa3b2e4189bf7e6c8a1))
+ - Release gix-hash v0.10.4, gix-hashtable v0.1.3 ([`b574a39`](https://github.com/Byron/gitoxide/commit/b574a3904203762a6b9e475e16a7c358d7616599))
+ - Release gix-features v0.28.1, gix-tempfile v5.0.1, gix-ref v0.27.1, gix-pack v0.33.1, gix-packetline v0.15.0, gix-transport v0.29.0, gix-protocol v0.30.0, gix v0.42.0, safety bump 3 crates ([`c1f1bfb`](https://github.com/Byron/gitoxide/commit/c1f1bfb8dc0e73993678353e4492d0614b642ed1))
+ - Release gix-features v0.28.0, gix-actor v0.19.0, gix-object v0.28.0, gix-diff v0.28.0, gix-traverse v0.24.0, gix-pack v0.32.0, safety bump 20 crates ([`0f411e9`](https://github.com/Byron/gitoxide/commit/0f411e93ec812592bb9d3a52b751399dd86f76f7))
+ - Adjust manifests prior to release ([`addd789`](https://github.com/Byron/gitoxide/commit/addd78958fdd1e54eb702854e96079539d01965a))
+</details>
+
+## 0.13.1 (2023-02-24)
+
+### Bug Fixes
+
+ - <csr-id-135d317065aae87af302beb6c26bb6ca8e30b6aa/> compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`.
+ `as_ref()` relies on a known target type which isn't always present. However, once
+ there is only one implementation, that's no problem, but when that changes compilation
+ fails due to ambiguity.
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 4 commits contributed to the release over the course of 4 calendar days.
+ - 7 days passed between releases.
+ - 1 commit was understood as [conventional](https://www.conventionalcommits.org).
+ - 0 issues like '(#ID)' were seen in commit messages
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **Uncategorized**
+ - Release gix-object v0.26.4, gix-diff v0.26.3, gix v0.37.2, gix-commitgraph v0.13.1, gitoxide-core v0.25.0, gitoxide v0.23.0 ([`9982949`](https://github.com/Byron/gitoxide/commit/9982949cab401501d5ce3cba4e2ba900bc249c53))
+ - Prepare changelog for release ([`13a1ec1`](https://github.com/Byron/gitoxide/commit/13a1ec1803d677c2e94f3ea0461118c2426f8071))
+ - Release gix-date v0.4.3, gix-hash v0.10.3, gix-features v0.26.5, gix-actor v0.17.2, gix-glob v0.5.5, gix-path v0.7.2, gix-quote v0.4.2, gix-attributes v0.8.3, gix-validate v0.7.3, gix-object v0.26.2, gix-ref v0.24.1, gix-config v0.16.2, gix-command v0.2.4, gix-url v0.13.3, gix-credentials v0.9.2, gix-discover v0.13.1, gix-index v0.12.4, gix-mailmap v0.9.3, gix-pack v0.30.3, gix-packetline v0.14.3, gix-transport v0.25.6, gix-protocol v0.26.4, gix-revision v0.10.4, gix-refspec v0.7.3, gix-worktree v0.12.3, gix v0.36.1 ([`9604783`](https://github.com/Byron/gitoxide/commit/96047839a20a657a559376b0b14c65aeab96acbd))
+ - Compatibility with `bstr` v1.3, use `*.as_bytes()` instead of `.as_ref()`. ([`135d317`](https://github.com/Byron/gitoxide/commit/135d317065aae87af302beb6c26bb6ca8e30b6aa))
+</details>
+
+## 0.13.0 (2023-02-17)
+
+<csr-id-29bf8ca8399b6d4941aa242b9f08c74e59a179bb/>
+<csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/>
+
+### New Features (BREAKING)
+
+ - <csr-id-3d8fa8fef9800b1576beab8a5bc39b821157a5ed/> upgrade edition to 2021 in most crates.
+ MSRV for this is 1.56, and we are now at 1.60 so should be compatible.
+ This isn't more than a patch release as it should break nobody
+ who is adhering to the MSRV, but let's be careful and mark it
+ breaking.
+
+ Note that `git-features` and `git-pack` are still on edition 2018
+ as they make use of a workaround to support (safe) mutable access
+ to non-overlapping entries in a slice which doesn't work anymore
+ in edition 2021.
+
+### Changed (BREAKING)
+
+ - <csr-id-99905bacace8aed42b16d43f0f04cae996cb971c/> upgrade `bstr` to `1.0.1`
+ - <csr-id-2ef9a8424af51310db8c1e6df31dde9953ed3d21/> Change accessors named `hash_kind()` to `object_hash()` for consistency
+
+### Other
+
+ - <csr-id-29bf8ca8399b6d4941aa242b9f08c74e59a179bb/> try to disable GPG signing with environment variables…
+ …but it's not picked up at all even though it's definitely present.
+
+### New Features
+
+ - <csr-id-b1c40b0364ef092cd52d03b34f491b254816b18d/> use docsrs feature in code to show what is feature-gated automatically on docs.rs
+ - <csr-id-517677147f1c17304c62cf97a1dd09f232ebf5db/> pass --cfg docsrs when compiling for https://docs.rs
+ - <csr-id-265b8ec07fd5357df629f0d29fb2412d0186a287/> Add support for hashes of different size
+ Even though right now, there is only Sha1, in future it's easy to
+ support other hash sizes.
+
+### Chore
+
+ - <csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/> uniformize deny attributes
+
+### Documentation
+
+ - <csr-id-39ed9eda62b7718d5109135e5ad406fb1fe2978c/> fix typos
+
+### Commit Statistics
+
+<csr-read-only-do-not-edit/>
+
+ - 268 commits contributed to the release over the course of 911 calendar days.
+ - 9 commits were understood as [conventional](https://www.conventionalcommits.org).
+ - 10 unique issues were worked on: [#198](https://github.com/Byron/gitoxide/issues/198), [#222](https://github.com/Byron/gitoxide/issues/222), [#279](https://github.com/Byron/gitoxide/issues/279), [#293](https://github.com/Byron/gitoxide/issues/293), [#329](https://github.com/Byron/gitoxide/issues/329), [#384](https://github.com/Byron/gitoxide/issues/384), [#450](https://github.com/Byron/gitoxide/issues/450), [#470](https://github.com/Byron/gitoxide/issues/470), [#63](https://github.com/Byron/gitoxide/issues/63), [#691](https://github.com/Byron/gitoxide/issues/691)
+
+### Thanks Clippy
+
+<csr-read-only-do-not-edit/>
+
+[Clippy](https://github.com/rust-lang/rust-clippy) helped 6 times to make code idiomatic.
+
+### Commit Details
+
+<csr-read-only-do-not-edit/>
+
+<details><summary>view details</summary>
+
+ * **[#198](https://github.com/Byron/gitoxide/issues/198)**
+ - Maintenance release note to avoid being fully generated ([`56ef363`](https://github.com/Byron/gitoxide/commit/56ef363f0e7a8b9106765d96d0636e38b2bed550))
+ - Changelog for git-commitgraph ([`d981f1f`](https://github.com/Byron/gitoxide/commit/d981f1f18ecbc943202702ab25a31a371a4b294d))
+ * **[#222](https://github.com/Byron/gitoxide/issues/222)**
+ - Stabilize changelogs ([`920e832`](https://github.com/Byron/gitoxide/commit/920e83219911df1c440d3fe42fd5ec3a295b0bb8))
+ - Update changelogs prior to release ([`b3e2252`](https://github.com/Byron/gitoxide/commit/b3e2252f7461a003d9a4612da60ba931dd8c0bef))
+ * **[#279](https://github.com/Byron/gitoxide/issues/279)**
+ - Also consider the size of the fanout table as part of the min size ([`8190708`](https://github.com/Byron/gitoxide/commit/8190708bc2b6ac9900d5f98b6c7db8cb3f38a632))
+ - Use latest capabilities of `git-hash` ([`a489ac2`](https://github.com/Byron/gitoxide/commit/a489ac2ca19a9fbf64f590c0d36c02b55c1a0536))
+ - Cargo fmt ([`8b9da35`](https://github.com/Byron/gitoxide/commit/8b9da35b3e0d3458efcac150f7062c9d7382a6c4))
+ - Access pack-indices and pack-offsets of multi-pack indices ([`c2a6918`](https://github.com/Byron/gitoxide/commit/c2a69189f88c53ab555158245ce647fcd33fca6a))
+ - Adapt to changes in git-hash ([`5eb0230`](https://github.com/Byron/gitoxide/commit/5eb0230b58c25c0aa744eee0bd878dd91410dbe1))
+ - Change accessors named `hash_kind()` to `object_hash()` for consistency ([`2ef9a84`](https://github.com/Byron/gitoxide/commit/2ef9a8424af51310db8c1e6df31dde9953ed3d21))
+ - Adjust to changes in git-hash ([`9bf25cc`](https://github.com/Byron/gitoxide/commit/9bf25cc4f2e44821f93e85997677bc4e86a67bd4))
+ - Adjust to changes in git-hash and git-pack ([`0cae25b`](https://github.com/Byron/gitoxide/commit/0cae25b1bb3c902ec323f17a1d9743e42fe213d0))
+ - Add support for hashes of different size ([`265b8ec`](https://github.com/Byron/gitoxide/commit/265b8ec07fd5357df629f0d29fb2412d0186a287))
+ - Refactor ([`501b85b`](https://github.com/Byron/gitoxide/commit/501b85b0ba57873f13e3086983d3b7a8b20defdd))
+ - Refactor ([`8c9c7fc`](https://github.com/Byron/gitoxide/commit/8c9c7fc3bc46afa9c8567a8bc8079cac12ed8422))
+ - Use `git-chunk` crate for all chunk-related operations ([`0cd7f3b`](https://github.com/Byron/gitoxide/commit/0cd7f3b796fec9fe3eac953b6e56bd78b0ea18f9))
+ - First round of introducing git-chunk ([`51b991b`](https://github.com/Byron/gitoxide/commit/51b991b2ca5727deb3447a51b14088dfdad8e7fe))
+ - Adapt to latest changes to git-chunk ([`743d696`](https://github.com/Byron/gitoxide/commit/743d6967d6236a4bb6a9c8817f957e7604bc9264))
+ * **[#293](https://github.com/Byron/gitoxide/issues/293)**
+ - Remove byteorder dependency from git-commitgraph ([`c526811`](https://github.com/Byron/gitoxide/commit/c5268115d9193ba2e309a943ee1d3c9e5825562c))
+ - Use memmap2 in git-commitgraph ([`0c946f5`](https://github.com/Byron/gitoxide/commit/0c946f5cb9d6eb13615b6c3d1a7b479ab5874441))
+ * **[#329](https://github.com/Byron/gitoxide/issues/329)**
+ - Document all features related to serde1 ([`72b97f2`](https://github.com/Byron/gitoxide/commit/72b97f2ae4dc7642b160f183c6d5df4502dc186f))
+ * **[#384](https://github.com/Byron/gitoxide/issues/384)**
+ - No need to isolate archives by crate name ([`19d46f3`](https://github.com/Byron/gitoxide/commit/19d46f35440419b9911b6e2bca2cfc975865dce9))
+ - Add archive files via git-lfs ([`7202a1c`](https://github.com/Byron/gitoxide/commit/7202a1c4734ad904c026ee3e4e2143c0461d51a2))
+ - Auto-set commit.gpgsign=false when executing git ([`c23feb6`](https://github.com/Byron/gitoxide/commit/c23feb64ad157180cfba8a11c882b829733ea8f6))
+ * **[#450](https://github.com/Byron/gitoxide/issues/450)**
+ - Upgrade `bstr` to `1.0.1` ([`99905ba`](https://github.com/Byron/gitoxide/commit/99905bacace8aed42b16d43f0f04cae996cb971c))
+ * **[#470](https://github.com/Byron/gitoxide/issues/470)**
+ - Update changelogs prior to release ([`caa7a1b`](https://github.com/Byron/gitoxide/commit/caa7a1bdef74d7d3166a7e38127a59f5ab3cfbdd))
+ * **[#63](https://github.com/Byron/gitoxide/issues/63)**
+ - Impl == and != for common combinations of ObjectId/oid ([`2455178`](https://github.com/Byron/gitoxide/commit/24551781cee4fcf312567ca9270d54a95bc4d7ae))
+ - Git-commitgraph with a more convenient public interface with AsRef ([`ba04e4e`](https://github.com/Byron/gitoxide/commit/ba04e4ed673c654a8968532228571a93a3ebc8e2))
+ - Git-commitgraph uses `oid` now ([`0b72966`](https://github.com/Byron/gitoxide/commit/0b72966249523b97fce1bc7b29082ac68fa86a4f))
+ - Refactor; better errors for invalid hash sizes ([`be84b36`](https://github.com/Byron/gitoxide/commit/be84b36129694a2e89d1b81d932f2eba23aedf54))
+ - Make ObjectId/oid happen! ([`ca78d15`](https://github.com/Byron/gitoxide/commit/ca78d15373ec988d909be8f240baefe75555e077))
+ - Remove all public exports of git-hash types in git-object ([`accf89d`](https://github.com/Byron/gitoxide/commit/accf89d25560e5ded6f44a1c4a898ee65d14f8f6))
+ - Remove re-export of git_object::borrowed::Id ([`a3f2816`](https://github.com/Byron/gitoxide/commit/a3f28169c1268c1129852f279631d5a7f7540cdf))
+ * **[#691](https://github.com/Byron/gitoxide/issues/691)**
+ - Set `rust-version` to 1.64 ([`55066ce`](https://github.com/Byron/gitoxide/commit/55066ce5fd71209abb5d84da2998b903504584bb))
+ * **Uncategorized**
+ - Release gix-commitgraph v0.13.0, gitoxide-core v0.24.0, gitoxide v0.22.0 ([`3262cde`](https://github.com/Byron/gitoxide/commit/3262cdeee90f249fdb4b24aeb03f1bed60ed6fef))
+ - Update dependencies ([`cf74880`](https://github.com/Byron/gitoxide/commit/cf74880dfcf7cd4dd67f7fa8165843ecd82b1f7f))
+ - Update changelogs prior to `gitoxide` release. ([`3547e58`](https://github.com/Byron/gitoxide/commit/3547e585f4ca31048f877373d045e1e6a6487d4f))
+ - Merge branch 'rename-crates' into inform-about-gix-rename ([`c9275b9`](https://github.com/Byron/gitoxide/commit/c9275b99ea43949306d93775d9d78c98fb86cfb1))
+ - Rename `git-testtools` to `gix-testtools` ([`b65c33d`](https://github.com/Byron/gitoxide/commit/b65c33d256cfed65d11adeff41132e3e58754089))
+ - Adjust to renaming of `git-pack` to `gix-pack` ([`1ee81ad`](https://github.com/Byron/gitoxide/commit/1ee81ad310285ee4aa118118a2be3810dbace574))
+ - Adjust to renaming of `git-odb` to `gix-odb` ([`476e2ad`](https://github.com/Byron/gitoxide/commit/476e2ad1a64e9e3f0d7c8651d5bcbee36cd78241))
+ - Adjust to renaming of `git-index` to `gix-index` ([`86db5e0`](https://github.com/Byron/gitoxide/commit/86db5e09fc58ce66b252dc13b8d7e2c48e4d5062))
+ - Adjust to renaming of `git-diff` to `gix-diff` ([`49a163e`](https://github.com/Byron/gitoxide/commit/49a163ec8b18f0e5fcd05a315de16d5d8be7650e))
+ - Adjust to renaming of `git-commitgraph` to `gix-commitgraph` ([`f1dd0a3`](https://github.com/Byron/gitoxide/commit/f1dd0a3366e31259af029da73228e8af2f414244))
+ - Rename `git-commitgraph` to `gix-commitgraph` ([`21077da`](https://github.com/Byron/gitoxide/commit/21077da34c4c4c8adb2b58b8b7702de832a895a6))
+ - Adjust to renaming of `git-mailmap` to `gix-mailmap` ([`2e28c56`](https://github.com/Byron/gitoxide/commit/2e28c56bb9f70de6f97439818118d3a25859698f))
+ - Adjust to renaming of `git-discover` to `gix-discover` ([`53adfe1`](https://github.com/Byron/gitoxide/commit/53adfe1c34e9ea3b27067a97b5e7ac80b351c441))
+ - Adjust to renaming of `git-lfs` to `gix-lfs` ([`b9225c8`](https://github.com/Byron/gitoxide/commit/b9225c830daf1388484ee7e05f727990fdeff43c))
+ - Adjust to renaming of `git-chunk` to `gix-chunk` ([`59194e3`](https://github.com/Byron/gitoxide/commit/59194e3a07853eae0624ebc4907478d1de4f7599))
+ - Adjust to renaming of `git-bitmap` to `gix-bitmap` ([`75f2a07`](https://github.com/Byron/gitoxide/commit/75f2a079b17489f62bc43e1f1d932307375c4f9d))
+ - Adjust to renaming for `git-protocol` to `gix-protocol` ([`823795a`](https://github.com/Byron/gitoxide/commit/823795addea3810243cab7936cd8ec0137cbc224))
+ - Adjust to renaming of `git-refspec` to `gix-refspec` ([`c958802`](https://github.com/Byron/gitoxide/commit/c9588020561577736faa065e7e5b5bb486ca8fe1))
+ - Adjust to renaming of `git-revision` to `gix-revision` ([`ee0ee84`](https://github.com/Byron/gitoxide/commit/ee0ee84607c2ffe11ee75f27a31903db68afed02))
+ - Adjust to renaming of `git-transport` to `gix-transport` ([`b2ccf71`](https://github.com/Byron/gitoxide/commit/b2ccf716dc4425bb96651d4d58806a3cc2da219e))
+ - Adjust to renaming of `git-credentials` to `gix-credentials` ([`6b18abc`](https://github.com/Byron/gitoxide/commit/6b18abcf2856f02ab938d535a65e51ac282bf94a))
+ - Adjust to renaming of `git-prompt` to `gix-prompt` ([`6a4654e`](https://github.com/Byron/gitoxide/commit/6a4654e0d10ab773dd219cb4b731c0fc1471c36d))
+ - Adjust to renaming of `git-command` to `gix-command` ([`d26b8e0`](https://github.com/Byron/gitoxide/commit/d26b8e046496894ae06b0bbfdba77196976cd975))
+ - Adjust to renaming of `git-packetline` to `gix-packetline` ([`5cbd22c`](https://github.com/Byron/gitoxide/commit/5cbd22cf42efb760058561c6c3bbcd4dab8c8be1))
+ - Adjust to renaming of `git-worktree` to `gix-worktree` ([`73a1282`](https://github.com/Byron/gitoxide/commit/73a12821b3d9b66ec1714d07dd27eb7a73e3a544))
+ - Adjust to renamining of `git-hashtable` to `gix-hashtable` ([`26a0c98`](https://github.com/Byron/gitoxide/commit/26a0c98d0a389b03e3dc7bfc758b37155e285244))
+ - Adjust to renamining of `git-worktree` to `gix-worktree` ([`108bb1a`](https://github.com/Byron/gitoxide/commit/108bb1a634f4828853fb590e9fc125f79441dd38))
+ - Adjust to renaming of `git-url` to `gix-url` ([`b50817a`](https://github.com/Byron/gitoxide/commit/b50817aadb143e19f61f64e19b19ec1107d980c6))
+ - Adjust to renaming of `git-date` to `gix-date` ([`9a79ff2`](https://github.com/Byron/gitoxide/commit/9a79ff2d5cc74c1efad9f41e21095ae498cce00b))
+ - Adjust to renamining of `git-attributes` to `gix-attributes` ([`4a8b3b8`](https://github.com/Byron/gitoxide/commit/4a8b3b812ac26f2a2aee8ce8ca81591273383c84))
+ - Adjust to renaminig of `git-quote` to `gix-quote` ([`648025b`](https://github.com/Byron/gitoxide/commit/648025b7ca94411fdd0d90c53e5faede5fde6c8d))
+ - Adjust to renaming of `git-config` to `gix-config` ([`3a861c8`](https://github.com/Byron/gitoxide/commit/3a861c8f049f6502d3bcbdac752659aa1aeda46a))
+ - Adjust to renaming of `git-ref` to `gix-ref` ([`1f5f695`](https://github.com/Byron/gitoxide/commit/1f5f695407b034377d94b172465ff573562b3fc3))
+ - Adjust to renaming of `git-lock` to `gix-lock` ([`2028e78`](https://github.com/Byron/gitoxide/commit/2028e7884ae1821edeec81612f501e88e4722b17))
+ - Adjust to renaming of `git-tempfile` to `gix-tempfile` ([`b6cc3eb`](https://github.com/Byron/gitoxide/commit/b6cc3ebb5137084a6327af16a7d9364d8f092cc9))
+ - Adjust to renaming of `git-object` to `gix-object` ([`fc86a1e`](https://github.com/Byron/gitoxide/commit/fc86a1e710ad7bf076c25cc6f028ddcf1a5a4311))
+ - Adjust to renaming of `git-actor` to `gix-actor` ([`4dc9b44`](https://github.com/Byron/gitoxide/commit/4dc9b44dc52f2486ffa2040585c6897c1bf55df4))
+ - Adjust to renaming of `git-validate` to `gix-validate` ([`5e40ad0`](https://github.com/Byron/gitoxide/commit/5e40ad078af3d08cbc2ca81ce755c0ed8a065b4f))
+ - Adjust to renaming of `git-hash` to `gix-hash` ([`4a9d025`](https://github.com/Byron/gitoxide/commit/4a9d0257110c3efa61d08c8457c4545b200226d1))
+ - Adjust to renaming of `git-features` to `gix-features` ([`e2dd68a`](https://github.com/Byron/gitoxide/commit/e2dd68a417aad229e194ff20dbbfd77668096ec6))
+ - Adjust to renaming of `git-glob` to `gix-glob` ([`35b2a3a`](https://github.com/Byron/gitoxide/commit/35b2a3acbc8f2a03f151bc0a3863163844e0ca86))
+ - Adjust to renaming of `git-sec` to `gix-sec` ([`eabbb92`](https://github.com/Byron/gitoxide/commit/eabbb923bd5a32fc80fa80f96cfdc2ab7bb2ed17))
+ - Adapt to renaming of `git-path` to `gix-path` ([`d3bbcfc`](https://github.com/Byron/gitoxide/commit/d3bbcfccad80fc44ea8e7bf819f23adaca06ba2d))
+ - Adjust to rename of `git-config-value` to `gix-config-value` ([`622b3e1`](https://github.com/Byron/gitoxide/commit/622b3e1d0bffa0f8db73697960f9712024fac430))
+ - Release git-features v0.26.4 ([`109f434`](https://github.com/Byron/gitoxide/commit/109f434e66559a791d541f86876ded8df10766f1))
+ - Release git-features v0.26.3 ([`1ecfb7f`](https://github.com/Byron/gitoxide/commit/1ecfb7f8bfb24432690d8f31367488f2e59a642a))
+ - Release git-commitgraph v0.13.0, gitoxide-core v0.23.0, gitoxide v0.21.0 ([`230a11f`](https://github.com/Byron/gitoxide/commit/230a11f8fb9625587f7a1ce0911e54f0d8579fd6))
+ - Release git-date v0.4.2, git-hash v0.10.2, git-features v0.26.2, git-actor v0.17.1, git-glob v0.5.3, git-path v0.7.1, git-quote v0.4.1, git-attributes v0.8.2, git-config-value v0.10.1, git-tempfile v3.0.2, git-lock v3.0.2, git-validate v0.7.2, git-object v0.26.1, git-ref v0.24.0, git-sec v0.6.2, git-config v0.16.0, git-command v0.2.3, git-prompt v0.3.2, git-url v0.13.2, git-credentials v0.9.1, git-diff v0.26.1, git-discover v0.13.0, git-hashtable v0.1.1, git-bitmap v0.2.1, git-traverse v0.22.1, git-index v0.12.3, git-mailmap v0.9.2, git-chunk v0.4.1, git-pack v0.30.2, git-odb v0.40.2, git-packetline v0.14.2, git-transport v0.25.4, git-protocol v0.26.3, git-revision v0.10.2, git-refspec v0.7.2, git-worktree v0.12.2, git-repository v0.34.0, safety bump 3 crates ([`c196d20`](https://github.com/Byron/gitoxide/commit/c196d206d57a310b1ce974a1cf0e7e6d6db5c4d6))
+ - Merge branch 'Lioness100/main' ([`1e544e8`](https://github.com/Byron/gitoxide/commit/1e544e82455bf9ecb5e3c2146280eaf7ecd81f16))
+ - Fix typos ([`39ed9ed`](https://github.com/Byron/gitoxide/commit/39ed9eda62b7718d5109135e5ad406fb1fe2978c))
+ - Thanks clippy ([`bac57dd`](https://github.com/Byron/gitoxide/commit/bac57dd05ea2d5a4ee45ef9350fa3f2e19474bc0))
+ - Optimize usage of `hex_to_id()` ([`6fa950d`](https://github.com/Byron/gitoxide/commit/6fa950d0ab1991a5577c06385169be1b390dd88a))
+ - Release git-date v0.4.1, git-features v0.26.1, git-glob v0.5.2, git-attributes v0.8.1, git-tempfile v3.0.1, git-ref v0.23.1, git-sec v0.6.1, git-config v0.15.1, git-prompt v0.3.1, git-url v0.13.1, git-discover v0.12.1, git-index v0.12.2, git-mailmap v0.9.1, git-pack v0.30.1, git-odb v0.40.1, git-transport v0.25.3, git-protocol v0.26.2, git-revision v0.10.1, git-refspec v0.7.1, git-worktree v0.12.1, git-repository v0.33.0 ([`5b5b380`](https://github.com/Byron/gitoxide/commit/5b5b3809faa71c658db38b40dfc410224d08a367))
+ - Release git-features v0.26.0, git-actor v0.16.0, git-attributes v0.8.0, git-object v0.25.0, git-ref v0.22.0, git-config v0.14.0, git-command v0.2.1, git-url v0.13.0, git-credentials v0.9.0, git-diff v0.25.0, git-discover v0.11.0, git-traverse v0.21.0, git-index v0.11.0, git-mailmap v0.8.0, git-pack v0.29.0, git-odb v0.39.0, git-transport v0.25.0, git-protocol v0.26.0, git-revision v0.9.0, git-refspec v0.6.0, git-worktree v0.11.0, git-repository v0.31.0, safety bump 24 crates ([`5ac9fbe`](https://github.com/Byron/gitoxide/commit/5ac9fbe265a5b61c533a2a6b3abfed2bdf7f89ad))
+ - Release git-features v0.25.1, git-url v0.12.2, git-odb v0.38.1, git-transport v0.24.2, git-repository v0.30.2 ([`bb0a07b`](https://github.com/Byron/gitoxide/commit/bb0a07b5edd5f980989d1a92e74df7f183febe87))
+ - Release git-url v0.12.1, git-transport v0.24.1, git-protocol v0.25.1, git-repository v0.30.1, git-commitgraph v0.12.0, gitoxide-core v0.22.0, gitoxide v0.20.0 ([`08ec3a9`](https://github.com/Byron/gitoxide/commit/08ec3a93d77a1018439a5c41c23729ffed27c5a5))
+ - Prepare changelogs prior to release ([`68ce15d`](https://github.com/Byron/gitoxide/commit/68ce15d07b50cfacdac0d1e42fe7f5e6330ba523))
+ - Release git-date v0.3.1, git-features v0.25.0, git-actor v0.15.0, git-glob v0.5.1, git-path v0.7.0, git-attributes v0.7.0, git-config-value v0.10.0, git-lock v3.0.1, git-validate v0.7.1, git-object v0.24.0, git-ref v0.21.0, git-sec v0.6.0, git-config v0.13.0, git-prompt v0.3.0, git-url v0.12.0, git-credentials v0.8.0, git-diff v0.24.0, git-discover v0.10.0, git-traverse v0.20.0, git-index v0.10.0, git-mailmap v0.7.0, git-pack v0.28.0, git-odb v0.38.0, git-packetline v0.14.1, git-transport v0.24.0, git-protocol v0.25.0, git-revision v0.8.0, git-refspec v0.5.0, git-worktree v0.10.0, git-repository v0.30.0, safety bump 26 crates ([`e6b9906`](https://github.com/Byron/gitoxide/commit/e6b9906c486b11057936da16ed6e0ec450a0fb83))
+ - Merge branch 'main' into read-split-index ([`c57bdde`](https://github.com/Byron/gitoxide/commit/c57bdde6de37eca9672ea715962bbd02aa3eb055))
+ - Merge branch 'adjustments-for-cargo' ([`083909b`](https://github.com/Byron/gitoxide/commit/083909bc7eb902eeee2002034fdb6ed88280dc5c))
+ - Adjust to changes in `git-testtools` ([`4eb842c`](https://github.com/Byron/gitoxide/commit/4eb842c7150b980e1c2637217e1f9657a671cea7))
+ - Release git-hash v0.10.1, git-hashtable v0.1.0 ([`7717170`](https://github.com/Byron/gitoxide/commit/771717095d9a67b0625021eb0928828ab686e772))
+ - Merge branch 'main' into http-config ([`6b9632e`](https://github.com/Byron/gitoxide/commit/6b9632e16c416841ffff1b767ee7a6c89b421220))
+ - Release git-features v0.24.1, git-actor v0.14.1, git-index v0.9.1 ([`7893502`](https://github.com/Byron/gitoxide/commit/789350208efc9d5fc6f9bc4f113f77f9cb445156))
+ - Merge branch 'main' into http-config ([`bcd9654`](https://github.com/Byron/gitoxide/commit/bcd9654e56169799eb706646da6ee1f4ef2021a9))
+ - Release git-hash v0.10.0, git-features v0.24.0, git-date v0.3.0, git-actor v0.14.0, git-glob v0.5.0, git-path v0.6.0, git-quote v0.4.0, git-attributes v0.6.0, git-config-value v0.9.0, git-tempfile v3.0.0, git-lock v3.0.0, git-validate v0.7.0, git-object v0.23.0, git-ref v0.20.0, git-sec v0.5.0, git-config v0.12.0, git-command v0.2.0, git-prompt v0.2.0, git-url v0.11.0, git-credentials v0.7.0, git-diff v0.23.0, git-discover v0.9.0, git-bitmap v0.2.0, git-traverse v0.19.0, git-index v0.9.0, git-mailmap v0.6.0, git-chunk v0.4.0, git-pack v0.27.0, git-odb v0.37.0, git-packetline v0.14.0, git-transport v0.23.0, git-protocol v0.24.0, git-revision v0.7.0, git-refspec v0.4.0, git-worktree v0.9.0, git-repository v0.29.0, git-commitgraph v0.11.0, gitoxide-core v0.21.0, gitoxide v0.19.0, safety bump 28 crates ([`b2c301e`](https://github.com/Byron/gitoxide/commit/b2c301ef131ffe1871314e19f387cf10a8d2ac16))
+ - Prepare changelogs prior to release ([`e4648f8`](https://github.com/Byron/gitoxide/commit/e4648f827c97e9d13636d1bbdc83dd63436e6e5c))
+ - Merge branch 'version2021' ([`0e4462d`](https://github.com/Byron/gitoxide/commit/0e4462df7a5166fe85c23a779462cdca8ee013e8))
+ - Upgrade edition to 2021 in most crates. ([`3d8fa8f`](https://github.com/Byron/gitoxide/commit/3d8fa8fef9800b1576beab8a5bc39b821157a5ed))
+ - Release git-features v0.23.1, git-glob v0.4.1, git-config-value v0.8.1, git-tempfile v2.0.6, git-object v0.22.1, git-ref v0.18.0, git-sec v0.4.2, git-config v0.10.0, git-prompt v0.1.1, git-url v0.10.1, git-credentials v0.6.1, git-diff v0.21.0, git-discover v0.7.0, git-index v0.7.0, git-pack v0.25.0, git-odb v0.35.0, git-transport v0.21.1, git-protocol v0.22.0, git-refspec v0.3.1, git-worktree v0.7.0, git-repository v0.26.0, git-commitgraph v0.10.0, gitoxide-core v0.19.0, gitoxide v0.17.0, safety bump 9 crates ([`d071583`](https://github.com/Byron/gitoxide/commit/d071583c5576fdf5f7717765ffed5681792aa81f))
+ - Prepare changelogs prior to release ([`423af90`](https://github.com/Byron/gitoxide/commit/423af90c8202d62dc1ea4a76a0df6421d1f0aa06))
+ - Release git-hash v0.9.11, git-features v0.23.0, git-actor v0.13.0, git-attributes v0.5.0, git-object v0.22.0, git-ref v0.17.0, git-sec v0.4.1, git-config v0.9.0, git-url v0.10.0, git-credentials v0.6.0, git-diff v0.20.0, git-discover v0.6.0, git-traverse v0.18.0, git-index v0.6.0, git-mailmap v0.5.0, git-pack v0.24.0, git-odb v0.34.0, git-packetline v0.13.1, git-transport v0.21.0, git-protocol v0.21.0, git-revision v0.6.0, git-refspec v0.3.0, git-worktree v0.6.0, git-repository v0.25.0, safety bump 24 crates ([`104d922`](https://github.com/Byron/gitoxide/commit/104d922add61ab21c534c24ce8ed37cddf3e275a))
+ - Merge branch 'fix-git-features' ([`82fd251`](https://github.com/Byron/gitoxide/commit/82fd251ac80d07bc9da8a4d36e517aa35580d188))
+ - Merge branch 'diff' ([`25a7726`](https://github.com/Byron/gitoxide/commit/25a7726377fbe400ea3c4927d04e9dec99802b7b))
+ - Release git-command v0.1.0, git-prompt v0.1.0, git-url v0.9.0, git-credentials v0.5.0, git-diff v0.19.0, git-mailmap v0.4.0, git-chunk v0.3.2, git-pack v0.23.0, git-odb v0.33.0, git-packetline v0.13.0, git-transport v0.20.0, git-protocol v0.20.0, git-revision v0.5.0, git-refspec v0.2.0, git-repository v0.24.0, git-commitgraph v0.9.0, gitoxide-core v0.18.0, gitoxide v0.16.0 ([`f5c36d8`](https://github.com/Byron/gitoxide/commit/f5c36d85755d1f0f503b77d9a565fad6aecf6728))
+ - Release git-hash v0.9.10, git-features v0.22.5, git-date v0.2.0, git-actor v0.12.0, git-glob v0.4.0, git-path v0.5.0, git-quote v0.3.0, git-attributes v0.4.0, git-config-value v0.8.0, git-tempfile v2.0.5, git-validate v0.6.0, git-object v0.21.0, git-ref v0.16.0, git-sec v0.4.0, git-config v0.8.0, git-discover v0.5.0, git-traverse v0.17.0, git-index v0.5.0, git-worktree v0.5.0, git-testtools v0.9.0, git-command v0.1.0, git-prompt v0.1.0, git-url v0.9.0, git-credentials v0.5.0, git-diff v0.19.0, git-mailmap v0.4.0, git-chunk v0.3.2, git-pack v0.23.0, git-odb v0.33.0, git-packetline v0.13.0, git-transport v0.20.0, git-protocol v0.20.0, git-revision v0.5.0, git-refspec v0.2.0, git-repository v0.24.0, git-commitgraph v0.9.0, gitoxide-core v0.18.0, gitoxide v0.16.0, safety bump 28 crates ([`29a043b`](https://github.com/Byron/gitoxide/commit/29a043be6808a3e9199a9b26bd076fe843afe4f4))
+ - Merge branch 'filter-refs' ([`fd14489`](https://github.com/Byron/gitoxide/commit/fd14489f729172d615d0fa1e8dbd605e9eacf69d))
+ - Release git-features v0.22.6 ([`c9eda72`](https://github.com/Byron/gitoxide/commit/c9eda729d8f8bc266c7516c613d38acfb83a4743))
+ - Merge branch 'main' into filter-refs-by-spec ([`9aa1d3d`](https://github.com/Byron/gitoxide/commit/9aa1d3dc46d4b1c76af257f573aff3aeef2d3fa8))
+ - Release git-features v0.22.4, git-url v0.8.0, safety bump 4 crates ([`1d4600a`](https://github.com/Byron/gitoxide/commit/1d4600ae51475c2e225f96c16c41e2c4a2b3f2aa))
+ - Merge branch 'main' into filter-refs-by-spec ([`1f6e5ab`](https://github.com/Byron/gitoxide/commit/1f6e5ab15f5fd8d23719b13e6aea59cd231ac0fe))
+ - Merge branch 'fix-522' ([`5869e9f`](https://github.com/Byron/gitoxide/commit/5869e9ff2508d5a93c07635277af8764fcb57713))
+ - Release git-hash v0.9.9 ([`da0716f`](https://github.com/Byron/gitoxide/commit/da0716f8c27b4f29cfff0e5ce7fcb3d7240f4aeb))
+ - Merge branch 'main' into index-from-tree ([`bc64b96`](https://github.com/Byron/gitoxide/commit/bc64b96a2ec781c72d1d4daad38aa7fb8b74f99b))
+ - Merge branch 'main' into filter-refs-by-spec ([`cef0b51`](https://github.com/Byron/gitoxide/commit/cef0b51ade2a3301fa09ede7a425aa1fe3527e78))
+ - Release git-features v0.22.3, git-revision v0.4.4 ([`c2660e2`](https://github.com/Byron/gitoxide/commit/c2660e2503323531ba02519eaa51124ee22fec51))
+ - Merge branch 'main' into filter-refs-by-spec ([`cfa1440`](https://github.com/Byron/gitoxide/commit/cfa144031dbcac2707ab0cec012bc35e78f9c475))
+ - Merge branch 'fix-ci-installation' ([`9245083`](https://github.com/Byron/gitoxide/commit/92450839621a4d99cb22d08cbf9f9a89ff6b9e3f))
+ - Release git-date v0.1.0, git-actor v0.11.4, git-revision v0.4.3, git-repository v0.22.1, cargo-smart-release v0.11.0, git-commitgraph v0.8.2, gitoxide-core v0.17.0, gitoxide v0.15.0 ([`1fb931a`](https://github.com/Byron/gitoxide/commit/1fb931a7ea59f1cf895a6c1392fd8615b723c743))
+ - Update changelogs prior to release ([`23cb58f`](https://github.com/Byron/gitoxide/commit/23cb58f02043e0e5027136fd6e8e724c03a2efbe))
+ - Release git-date v0.0.5, git-hash v0.9.8, git-features v0.22.2, git-actor v0.11.3, git-glob v0.3.2, git-quote v0.2.1, git-attributes v0.3.2, git-tempfile v2.0.4, git-lock v2.1.1, git-validate v0.5.5, git-object v0.20.2, git-ref v0.15.2, git-sec v0.3.1, git-config v0.7.0, git-credentials v0.4.0, git-diff v0.17.2, git-discover v0.4.1, git-bitmap v0.1.2, git-index v0.4.2, git-mailmap v0.3.2, git-chunk v0.3.1, git-traverse v0.16.2, git-pack v0.21.2, git-odb v0.31.2, git-packetline v0.12.7, git-url v0.7.2, git-transport v0.19.2, git-protocol v0.19.0, git-revision v0.4.2, git-refspec v0.1.0, git-worktree v0.4.2, git-repository v0.22.0, safety bump 4 crates ([`4974eca`](https://github.com/Byron/gitoxide/commit/4974eca96d525d1ee4f8cad79bb713af7a18bf9d))
+ - Merge branch 'main' into remote-ls-refs ([`e2ee3de`](https://github.com/Byron/gitoxide/commit/e2ee3ded97e5c449933712883535b30d151c7c78))
+ - Merge branch 'docsrs-show-features' ([`31c2351`](https://github.com/Byron/gitoxide/commit/31c235140cad212d16a56195763fbddd971d87ce))
+ - Use docsrs feature in code to show what is feature-gated automatically on docs.rs ([`b1c40b0`](https://github.com/Byron/gitoxide/commit/b1c40b0364ef092cd52d03b34f491b254816b18d))
+ - Uniformize deny attributes ([`f7f136d`](https://github.com/Byron/gitoxide/commit/f7f136dbe4f86e7dee1d54835c420ec07c96cd78))
+ - Pass --cfg docsrs when compiling for https://docs.rs ([`5176771`](https://github.com/Byron/gitoxide/commit/517677147f1c17304c62cf97a1dd09f232ebf5db))
+ - Merge branch 'main' into remote-ls-refs ([`bd5f3e8`](https://github.com/Byron/gitoxide/commit/bd5f3e8db7e0bb4abfb7b0f79f585ab82c3a14ab))
+ - Release git-commitgraph v0.8.1, gitoxide-core v0.16.0, gitoxide v0.14.0 ([`183c048`](https://github.com/Byron/gitoxide/commit/183c0488a808ef760a9f6795f5c040e73926c3a8))
+ - Prepare for gitoxide release ([`6305d52`](https://github.com/Byron/gitoxide/commit/6305d52236c094c412b221967f59eb264c2c3038))
+ - Release git-hash v0.9.7, git-features v0.22.1 ([`232784a`](https://github.com/Byron/gitoxide/commit/232784a59ded3e8016e4257c7e146ad385cdd64a))
+ - Merge pull request #2 from SidneyDouw/main ([`ce885ad`](https://github.com/Byron/gitoxide/commit/ce885ad4c3324c09c83751c32e014f246c748766))
+ - Merge branch 'Byron:main' into main ([`9b9ea02`](https://github.com/Byron/gitoxide/commit/9b9ea0275f8ff5862f24cf5a4ca53bb1cd610709))
+ - Merge branch 'main' into rev-parse-delegate ([`6da8250`](https://github.com/Byron/gitoxide/commit/6da82507588d3bc849217c11d9a1d398b67f2ed6))
+ - Merge branch 'main' into pathspec ([`7b61506`](https://github.com/Byron/gitoxide/commit/7b615060712565f515515e35a3e8346278ad770c))
+ - Release git-worktree v0.4.0, git-repository v0.20.0, git-commitgraph v0.8.0, gitoxide-core v0.15.0, gitoxide v0.13.0 ([`d4df661`](https://github.com/Byron/gitoxide/commit/d4df661dbf60dad75d07002ef9979cabe8a86935))
+ - Release git-config v0.6.0, git-credentials v0.3.0, git-diff v0.17.0, git-discover v0.3.0, git-index v0.4.0, git-mailmap v0.3.0, git-traverse v0.16.0, git-pack v0.21.0, git-odb v0.31.0, git-url v0.7.0, git-transport v0.19.0, git-protocol v0.18.0, git-revision v0.3.0, git-worktree v0.4.0, git-repository v0.20.0, git-commitgraph v0.8.0, gitoxide-core v0.15.0, gitoxide v0.13.0 ([`aa639d8`](https://github.com/Byron/gitoxide/commit/aa639d8c43f3098cc4a5b50614c5ae94a8156928))
+ - Release git-hash v0.9.6, git-features v0.22.0, git-date v0.0.2, git-actor v0.11.0, git-glob v0.3.1, git-path v0.4.0, git-attributes v0.3.0, git-tempfile v2.0.2, git-object v0.20.0, git-ref v0.15.0, git-sec v0.3.0, git-config v0.6.0, git-credentials v0.3.0, git-diff v0.17.0, git-discover v0.3.0, git-index v0.4.0, git-mailmap v0.3.0, git-traverse v0.16.0, git-pack v0.21.0, git-odb v0.31.0, git-url v0.7.0, git-transport v0.19.0, git-protocol v0.18.0, git-revision v0.3.0, git-worktree v0.4.0, git-repository v0.20.0, git-commitgraph v0.8.0, gitoxide-core v0.15.0, gitoxide v0.13.0, safety bump 22 crates ([`4737b1e`](https://github.com/Byron/gitoxide/commit/4737b1eea1d4c9a8d5a69fb63ecac5aa5d378ae5))
+ - Prepare changelog prior to release ([`3c50625`](https://github.com/Byron/gitoxide/commit/3c50625fa51350ec885b0f38ec9e92f9444df0f9))
+ - Merge pull request #1 from Byron/main ([`085e76b`](https://github.com/Byron/gitoxide/commit/085e76b121291ed9bd324139105d2bd4117bedf8))
+ - Assure document-features are available in all 'usable' and 'early' crates ([`238581c`](https://github.com/Byron/gitoxide/commit/238581cc46c7288691eed37dc7de5069e3d86721))
+ - Merge branch 'main' into pathspec ([`89ea12b`](https://github.com/Byron/gitoxide/commit/89ea12b558bcc056b892193ee8fb44b8664b5da4))
+ - Merge branch 'main' into cont_include_if ([`41ea8ba`](https://github.com/Byron/gitoxide/commit/41ea8ba78e74f5c988148367386a1f4f304cb951))
+ - Release git-date v0.0.1, git-hash v0.9.5, git-features v0.21.1, git-actor v0.10.1, git-path v0.2.0, git-attributes v0.2.0, git-ref v0.14.0, git-sec v0.2.0, git-config v0.5.0, git-credentials v0.2.0, git-discover v0.2.0, git-pack v0.20.0, git-odb v0.30.0, git-url v0.6.0, git-transport v0.18.0, git-protocol v0.17.0, git-revision v0.2.1, git-worktree v0.3.0, git-repository v0.19.0, safety bump 13 crates ([`a417177`](https://github.com/Byron/gitoxide/commit/a41717712578f590f04a33d27adaa63171f25267))
+ - Update changelogs prior to release ([`bb424f5`](https://github.com/Byron/gitoxide/commit/bb424f51068b8a8e762696890a55ab48900ab980))
+ - Merge branch 'main' into SidneyDouw-pathspec ([`a22b1d8`](https://github.com/Byron/gitoxide/commit/a22b1d88a21311d44509018729c3ef1936cf052a))
+ - Merge branch 'main' into git_includeif ([`598c853`](https://github.com/Byron/gitoxide/commit/598c853087fcf8f77299aa5b9803bcec705c0cd0))
+ - Release git-hash v0.9.4, git-features v0.21.0, git-actor v0.10.0, git-glob v0.3.0, git-path v0.1.1, git-attributes v0.1.0, git-sec v0.1.0, git-config v0.3.0, git-credentials v0.1.0, git-validate v0.5.4, git-object v0.19.0, git-diff v0.16.0, git-lock v2.1.0, git-ref v0.13.0, git-discover v0.1.0, git-index v0.3.0, git-mailmap v0.2.0, git-traverse v0.15.0, git-pack v0.19.0, git-odb v0.29.0, git-packetline v0.12.5, git-url v0.5.0, git-transport v0.17.0, git-protocol v0.16.0, git-revision v0.2.0, git-worktree v0.2.0, git-repository v0.17.0, safety bump 20 crates ([`654cf39`](https://github.com/Byron/gitoxide/commit/654cf39c92d5aa4c8d542a6cadf13d4acef6a78e))
+ - Merge branch 'main' into repo-status ([`0eb2372`](https://github.com/Byron/gitoxide/commit/0eb23721dca78f6e6bf864c5c3a3e44df8b419f0))
+ - Merge branch 'test-archive-support' ([`350df01`](https://github.com/Byron/gitoxide/commit/350df01042d6ca8b93f8737fa101e69b50535a0f))
+ - Release git-commitgraph v0.7.0, gitoxide-core v0.13.0, gitoxide v0.11.0 ([`ab08a7f`](https://github.com/Byron/gitoxide/commit/ab08a7f066fb65671868424315d958ae985d76d8))
+ - Release git-hash v0.9.3, git-features v0.20.0, git-config v0.2.0, safety bump 12 crates ([`f0cbb24`](https://github.com/Byron/gitoxide/commit/f0cbb24b2e3d8f028be0e773f9da530da2656257))
+ - Release git-hash v0.9.2, git-object v0.17.1, git-pack v0.16.1 ([`0db19b8`](https://github.com/Byron/gitoxide/commit/0db19b8deaf11a4d4cbc03fa3ae40eea104bc302))
+ - Release git-hash v0.9.1, git-features v0.19.1, git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0, safety bump 4 crates ([`373cbc8`](https://github.com/Byron/gitoxide/commit/373cbc877f7ad60dac682e57c52a7b90f108ebe3))
+ - Release git-bitmap v0.0.1, git-hash v0.9.0, git-features v0.19.0, git-index v0.1.0, safety bump 9 crates ([`4624725`](https://github.com/Byron/gitoxide/commit/4624725f54a34dd6b35d3632fb3516965922f60a))
+ - Thanks clippy ([`53bd30f`](https://github.com/Byron/gitoxide/commit/53bd30fd56c971b2be5a5d22045b97dc5f216303))
+ - Thanks clippy ([`6cc1bd1`](https://github.com/Byron/gitoxide/commit/6cc1bd15a49d9ec67a4a381ee3f64d557850733c))
+ - Release git-chunk v0.2.0, safety bump 4 crates ([`b792fab`](https://github.com/Byron/gitoxide/commit/b792fabf9f5f93ab906ac5a5bb3e4f01c179290a))
+ - Thanks clippy ([`7dd2313`](https://github.com/Byron/gitoxide/commit/7dd2313d980fe7c058319ae66d313b3097e3ae5f))
+ - Release git-features v0.18.0, git-actor v0.7.0, git-config v0.1.9, git-object v0.16.0, git-diff v0.12.0, git-traverse v0.11.0, git-pack v0.15.0, git-odb v0.25.0, git-packetline v0.12.2, git-transport v0.14.0, git-protocol v0.13.0, git-ref v0.10.0, git-repository v0.13.0, cargo-smart-release v0.7.0, safety bump 12 crates ([`acd3737`](https://github.com/Byron/gitoxide/commit/acd37371dcd92ebac3d1f039224d02f2b4e9fa0b))
+ - Adjust changelogs prior to release ([`ec38950`](https://github.com/Byron/gitoxide/commit/ec3895005d141abe79764eaff7c0f04153e38d73))
+ - Release git-hash v0.8.0, git-features v0.17.0, git-actor v0.6.0, git-object v0.15.0, git-diff v0.11.0, git-traverse v0.10.0, git-pack v0.13.0, git-odb v0.23.0, git-packetline v0.12.0, git-transport v0.13.0, git-protocol v0.12.0, git-ref v0.9.0, git-repository v0.11.0, git-commitgraph v0.6.0, gitoxide-core v0.12.0, gitoxide v0.10.0, cargo-smart-release v0.5.0, safety bump 16 crates ([`0e02953`](https://github.com/Byron/gitoxide/commit/0e029537a7f6242d02ccf7e63d8d92f5246e6c5e))
+ - Release git-commitgraph v0.5.0, gitoxide-core v0.11.0, gitoxide v0.9.0 ([`960eb0e`](https://github.com/Byron/gitoxide/commit/960eb0e5e5a7df117ed2ae2a8e2ec167b074c332))
+ - Adjusting changelogs prior to release of git-hash v0.7.0, git-features v0.16.5, git-actor v0.5.3, git-validate v0.5.3, git-object v0.14.1, git-diff v0.10.0, git-tempfile v1.0.3, git-lock v1.0.1, git-traverse v0.9.0, git-pack v0.12.0, git-odb v0.22.0, git-packetline v0.11.0, git-url v0.3.4, git-transport v0.12.0, git-protocol v0.11.0, git-ref v0.8.0, git-repository v0.10.0, cargo-smart-release v0.4.0, safety bump 3 crates ([`a474395`](https://github.com/Byron/gitoxide/commit/a47439590e36b1cb8b516b6053fd5cbfc42efed7))
+ - Release git-commitgraph v0.4.4 ([`dec935c`](https://github.com/Byron/gitoxide/commit/dec935cd6ef9a70afd247e5fcf44983c97c1b10b))
+ - Merge branch 'repository-integration' ([`49f5453`](https://github.com/Byron/gitoxide/commit/49f5453629646ac24d752f53c532e5f67eb09374))
+ - Bump git-hash v0.6.0 ([`6efd90d`](https://github.com/Byron/gitoxide/commit/6efd90db54f7f7441b76159dba3be80c15657a3d))
+ - Release git-commitgraph v0.4.3 ([`7dfe16b`](https://github.com/Byron/gitoxide/commit/7dfe16bdebaf971b7101331ad037d1ca8ab491d2))
+ - [repository #165] refactor ([`1547d0b`](https://github.com/Byron/gitoxide/commit/1547d0b062e35bad2229dac532e6f30bf105db73))
+ - [smart-release #162] format everything ([`8ff83e5`](https://github.com/Byron/gitoxide/commit/8ff83e5c511ae29979348789bd6e7a2f72b16f1c))
+ - Release git-commitgraph v0.4.2 ([`847c456`](https://github.com/Byron/gitoxide/commit/847c4564d9b64c071db790979654d0883d7a38d0))
+ - Promote file-format constants to `git_commitgraph::file` module. ([`0afd354`](https://github.com/Byron/gitoxide/commit/0afd354f94fb1829d4c097b49cba503bac3d1c38))
+ - Apply nightly rustfmt rules. ([`5e0edba`](https://github.com/Byron/gitoxide/commit/5e0edbadb39673d4de640f112fa306349fb11814))
+ - Release git-commitgraph v0.4.1 ([`1776a0d`](https://github.com/Byron/gitoxide/commit/1776a0d7168f1f15a18e0f873a9918a6db33b94a))
+ - Remove dev-dependency cycles by removing their version ([`c40faca`](https://github.com/Byron/gitoxide/commit/c40faca41632cd2a226daf4ddf5293b65d1fdc82))
+ - (cargo-release) version 0.4.0 ([`70ef344`](https://github.com/Byron/gitoxide/commit/70ef3442775b54ba9e4ee9ebfffb37af9804cc5b))
+ - (cargo-release) version 0.5.0 ([`ae02dab`](https://github.com/Byron/gitoxide/commit/ae02dabae961089a92a21e6a60a7006de4b56dad))
+ - (cargo-release) version 0.16.0 ([`1231dbd`](https://github.com/Byron/gitoxide/commit/1231dbd16dacefb39adec8e067c312d313a82e3c))
+ - Thanks clippy ([`e1964e4`](https://github.com/Byron/gitoxide/commit/e1964e43979b3e32a5d4bfbe377a842d2c0b10ea))
+ - Change wording ([`6c82a16`](https://github.com/Byron/gitoxide/commit/6c82a16d340acb9b11c5cf56c917c9fe6f2cdf0e))
+ - Don't use ASM on windows for Sha1 as it fails to build there. ([`ba1fb7a`](https://github.com/Byron/gitoxide/commit/ba1fb7ab5bc03f5a23ece32ff1e144544e1eaeae))
+ - Remove unnecessary pub(crate) exports ([`3d2456e`](https://github.com/Byron/gitoxide/commit/3d2456e11709f0461b37c6df55ecc3861ca4cab5))
+ - Bump thiserror from 1.0.25 to 1.0.26 ([`9682590`](https://github.com/Byron/gitoxide/commit/9682590095dc3a502b0c84ccd206ca4797635092))
+ - (cargo-release) version 0.3.0 ([`6b33678`](https://github.com/Byron/gitoxide/commit/6b33678f83e6d261ca15c4a7634ff5b4e66d81dd))
+ - (cargo-release) version 0.2.0 ([`3286e42`](https://github.com/Byron/gitoxide/commit/3286e42547b59df6365087cbae9ce1c9c959faad))
+ - Fix git-commigraph build (broke after git-hash changed its ways) ([`08fd7a0`](https://github.com/Byron/gitoxide/commit/08fd7a08800d926bcfeb1cfe6faa1f02c0b8904e))
+ - (cargo-release) version 0.4.0 ([`866f86f`](https://github.com/Byron/gitoxide/commit/866f86f59e66652968dcafc1a57912f9849cb21d))
+ - (cargo-release) version 0.15.0 ([`d69d9fb`](https://github.com/Byron/gitoxide/commit/d69d9fb0931f8257cef96ef14a89da9340ad9738))
+ - Put 'sha1' behind a feature toggle ([`4f326bc`](https://github.com/Byron/gitoxide/commit/4f326bc261c4e7f0d5510df74ad4215da3580696))
+ - (cargo-release) version 0.14.0 ([`a760f8c`](https://github.com/Byron/gitoxide/commit/a760f8c013e13ba82daa1acf1a4a57e0818a008d))
+ - Prepare test utilities for release… ([`d35e654`](https://github.com/Byron/gitoxide/commit/d35e654747f96cec93bdecd1314ce325129cbc44))
+ - (cargo-release) version 0.3.0 ([`e9665c7`](https://github.com/Byron/gitoxide/commit/e9665c784ae7e5cdaf662151395ee2355e9b57b6))
+ - Revert "FAIL: try to disable GPG signing with environment variables…" ([`e326352`](https://github.com/Byron/gitoxide/commit/e326352eec7bd1aae13f770328979e5730ffc32b))
+ - Try to disable GPG signing with environment variables… ([`29bf8ca`](https://github.com/Byron/gitoxide/commit/29bf8ca8399b6d4941aa242b9f08c74e59a179bb))
+ - Set environment in testtools to freeze repositories generation scripts ([`eaad3ab`](https://github.com/Byron/gitoxide/commit/eaad3ab69338115439a553ba1062160dc3a08082))
+ - Faster repeated tests if fixtures don't change ([`792277f`](https://github.com/Byron/gitoxide/commit/792277f241446086dd6c9b78f688363d4e66e5a7))
+ - Git-commitgraph uses test-tools ([`5d30e5a`](https://github.com/Byron/gitoxide/commit/5d30e5a3474aabd67cb5d1afc826aa68957d2b7a))
+ - (cargo-release) version 0.13.0 ([`ac2eddb`](https://github.com/Byron/gitoxide/commit/ac2eddb06eb3d8a9a3dcdcd796eb54a7e45ab935))
+ - (cargo-release) version 0.4.0 ([`06612eb`](https://github.com/Byron/gitoxide/commit/06612eb12d4679bec7dae08a511dd87d80087151))
+ - (cargo-release) version 0.12.0 ([`3b71e7e`](https://github.com/Byron/gitoxide/commit/3b71e7e8416e550b47e5aed2259c1181497ac9e8))
+ - (cargo-release) version 0.2.0 ([`4ec09f4`](https://github.com/Byron/gitoxide/commit/4ec09f4d2239ea1d44f7145027e64191bf2c158c))
+ - (cargo-release) version 0.3.2 ([`d91dd9d`](https://github.com/Byron/gitoxide/commit/d91dd9d8c57688dc9c420460ef5800cd07b3c9b4))
+ - Merge pull request #43 from avoidscorn/docs ([`1469be4`](https://github.com/Byron/gitoxide/commit/1469be45240126f855c9fcc2a72647e319963ef7))
+ - [commitgraph] Tweak and expand documentation. ([`ac52867`](https://github.com/Byron/gitoxide/commit/ac5286772c0eefd994b3d85ab185e0d4960cdd0a))
+ - (cargo-release) version 0.11.0 ([`1aa1f5e`](https://github.com/Byron/gitoxide/commit/1aa1f5e84a07427d5d7f3231735fe9c1923f506f))
+ - (cargo-release) version 0.3.1 ([`89db50c`](https://github.com/Byron/gitoxide/commit/89db50ce01ea7cc83b7f90484e2f8736dba7ccde))
+ - Remaining docs for git-commitgraph crate ([`9146176`](https://github.com/Byron/gitoxide/commit/91461760884979218617fcfdc56efd8be73b9d6f))
+ - More commitgraph docs ([`a81ea67`](https://github.com/Byron/gitoxide/commit/a81ea6730f11f769caed9a70cad123cace96b625))
+ - All docs for git-commitgraph::file ([`8b26201`](https://github.com/Byron/gitoxide/commit/8b262011ceffaff74bea9f4ffc730682884fff64))
+ - Add missing '.' at end of doc comments ([`7136854`](https://github.com/Byron/gitoxide/commit/71368544f97369a4d371d43513607c4805bd0fd0))
+ - All crates use git-hash::Kind and its types, sometimes through git-object ([`124c171`](https://github.com/Byron/gitoxide/commit/124c171aaf546d8977e9913ff84e65383a80ee98))
+ - Use git-hash in git-features ([`5b307e0`](https://github.com/Byron/gitoxide/commit/5b307e076f6f5975592c8b177c122c91c1d809c6))
+ - (cargo-release) version 0.2.0 ([`d61ad88`](https://github.com/Byron/gitoxide/commit/d61ad884021d3c0a61a14ba1df4daadfa1a0b561))
+ - (cargo-release) version 0.9.0 ([`a89fdb9`](https://github.com/Byron/gitoxide/commit/a89fdb98f64bb0ca070fa79a1f58f1232bb14090))
+ - (cargo-release) version 0.5.0 ([`fc7d600`](https://github.com/Byron/gitoxide/commit/fc7d600ac2c438c8b6b91f67cb69b0ac5ec37675))
+ - (cargo-release) version 0.1.3 ([`a833fd1`](https://github.com/Byron/gitoxide/commit/a833fd18e1bc3a501e4f1ed66506f48673f79590))
+ - Thanks clippy ([`ba9b3c2`](https://github.com/Byron/gitoxide/commit/ba9b3c2345887353e02fc081be80733f1c5e22d9))
+ - (cargo-release) version 0.8.0 ([`47c00c2`](https://github.com/Byron/gitoxide/commit/47c00c2228cf25c79e1fa3eb4229c7ab24de91e5))
+ - Cargo clippy Rust 1.48 ([`475a68c`](https://github.com/Byron/gitoxide/commit/475a68ce33b895de911939c51afa159df534f7b8))
+ - (cargo-release) version 0.7.0 ([`7fa7bae`](https://github.com/Byron/gitoxide/commit/7fa7baeb3e7d008a25e4d714eff908e2516c828b))
+ - Merge branch 'commit-graph' into main ([`9cb09b2`](https://github.com/Byron/gitoxide/commit/9cb09b248796f0ff5c9d3f3e857de4731324cfd5))
+ - Note about why git_features::hash::bytes_of_file() is not yet used ([`ca48fc4`](https://github.com/Byron/gitoxide/commit/ca48fc4f7c00215acf95370fe894a6e585c18c13))
+ - Add and use borrowed::Id::null_sha1() ([`c717492`](https://github.com/Byron/gitoxide/commit/c717492d0038f55a6f21b48937b56a756890d214))
+ - Refactor ([`e4935e0`](https://github.com/Byron/gitoxide/commit/e4935e03040e1f4ded652ed43a1e0177eefb44f4))
+ - Replace 'ImpossibleVariantError' with 'std::convert::Infallible'` ([`c53638c`](https://github.com/Byron/gitoxide/commit/c53638ccd9e392af839b7eb03826fa6aab94faff))
+ - [commitgraph] Clean up `{file,graph}::verify::Error` types. ([`fa22cab`](https://github.com/Byron/gitoxide/commit/fa22cab259338dc140dd660f4f4b9bbc9d6cc3d0))
+ - [commitgraph] Implement basic commit-graph file verification. ([`2571113`](https://github.com/Byron/gitoxide/commit/2571113fea516737acedac08d66632ead499b474))
+ - [commitgraph] Loosen lifetime restrictions on return values. ([`701f33c`](https://github.com/Byron/gitoxide/commit/701f33c06b80deaabe7625b01d36e2a1b1af3a78))
+ - [commitgraph] Replace `T as U` with `U::from(T)` or `t.try_into()`. ([`28f94b4`](https://github.com/Byron/gitoxide/commit/28f94b4bccdf317c9f4ccb62e0e3f3314f3995c9))
+ - [commitgraph] Tweak `File::iter_base_graph_ids` implementation. ([`5b06780`](https://github.com/Byron/gitoxide/commit/5b067808a793e3515c0c12cf95c11b57beaa8d09))
+ - [commitgraph] Add `Graph::at` constructor. ([`a783052`](https://github.com/Byron/gitoxide/commit/a783052d0cc2d3c9fa1dda3ea77286a79690d2c1))
+ - [commitgraph] Validate trailer section when parsing files. ([`1b738ac`](https://github.com/Byron/gitoxide/commit/1b738ac0719ec20b24982d148a386d63ec4dc2d6))
+ - [commitgraph] Use `thiserror` instead of `quick_error`. ([`c8b1f74`](https://github.com/Byron/gitoxide/commit/c8b1f74328965708e38a689b865660ad36f22ecb))
+ - (cargo-release) version 0.1.2 ([`b401468`](https://github.com/Byron/gitoxide/commit/b40146828771d9837350e07250fb21851f700fcc))
+ - Merge remote-tracking branch 'origin/main' into main ([`f3d90d7`](https://github.com/Byron/gitoxide/commit/f3d90d7f65cdbcfed4281c0382f8c6766809afaa))
+ - (cargo-release) version 0.1.1 ([`04c7cdf`](https://github.com/Byron/gitoxide/commit/04c7cdf1418f43052390f5d67bd4e7e43ae8b2e6))
+ - Fix repository URL ([`d721f47`](https://github.com/Byron/gitoxide/commit/d721f478ab441db30585af747d9f47717443d7e1))
+ - Update commitgraph information ([`275cfde`](https://github.com/Byron/gitoxide/commit/275cfde06192c8b3a3d633b21e970b54ddc1a53f))
+ - [commitgraph] add size limit and prep for release ([`4eabf55`](https://github.com/Byron/gitoxide/commit/4eabf554dc7cc08416d1078fa29db606455dc031))
+ - [commitgraph] bump minor version for first release ([`76bb4d3`](https://github.com/Byron/gitoxide/commit/76bb4d355dd1570340fe7d05d2a3378e15a36d4e))
+ - [commitgraph] refactor file::init ([`8b003a0`](https://github.com/Byron/gitoxide/commit/8b003a01729e4bfcb433e34f32b8e450cbe75fea))
+ - [commitgraph] refactor ([`c4b14c1`](https://github.com/Byron/gitoxide/commit/c4b14c1eae8dfcdcb3637d64e3c81dc424e26607))
+ - [commitgraph] Rename LexPosition to 'file::Position' ([`6f90bee`](https://github.com/Byron/gitoxide/commit/6f90beeb418480f9cd8bb7ae3b5db678b24103cb))
+ - [commitgraph] refactor graph::init module ([`d2eec1d`](https://github.com/Byron/gitoxide/commit/d2eec1dbedac6e87cc281cdd84423d9c7cfba323))
+ - [commitgraph] refactor Graph, Position, and access module ([`3c8640e`](https://github.com/Byron/gitoxide/commit/3c8640e5baf4729f4394c569dc0aed9865121e7a))
+ - [commitgraph] refactor ([`2ed0037`](https://github.com/Byron/gitoxide/commit/2ed0037c87fa17fbdb560cab46f72bf64805623b))
+ - [commitgraph] refactor ([`7026961`](https://github.com/Byron/gitoxide/commit/7026961ab7de4ee66ae84bdfdeef359ae960d231))
+ - [commitgraph] Assure git doesn't try to sign commits when fixtures are created ([`9ae1f4b`](https://github.com/Byron/gitoxide/commit/9ae1f4b9bb05a19ba279a1242f3c84d439421f18))
+ - [commitgraph] Attempt to fix bash script execution on Windows. ([`5e78213`](https://github.com/Byron/gitoxide/commit/5e78213b1cd53986b8a39accf17da3456e496016))
+ - [commitgraph] Use crate::graph::Graph instead of crate::Graph. ([`21e4527`](https://github.com/Byron/gitoxide/commit/21e45275221505b30f466a3b0223534d5a2281e5))
+ - [commitgraph] Rearrange some `use` statements. ([`185d14b`](https://github.com/Byron/gitoxide/commit/185d14b25b8fc85308b1ba62391595dda51ce58a))
+ - [commitgraph] Don't export Commit symbol at crate level. ([`be0e845`](https://github.com/Byron/gitoxide/commit/be0e845649b87acd3197ea212c78af8e0f9e22bf))
+ - [commitgraph] Include Conor in crate manifest. ([`000748c`](https://github.com/Byron/gitoxide/commit/000748ccffc222729a7a1c1ce19c4fa1ba50fbed))
+ - [commitgraph] Add some doc comments. ([`6cf5cd8`](https://github.com/Byron/gitoxide/commit/6cf5cd8da54e9d5670e3a44de95253df1091b110))
+ - [commitgraph] Remove unused error variant. ([`66588f2`](https://github.com/Byron/gitoxide/commit/66588f227de8fd883a5f429821509e968c59b4fc))
+ - [commitgraph] Rename GraphFile -> File. ([`f451822`](https://github.com/Byron/gitoxide/commit/f451822ec912253b2e5a5b0a63e1abd76939f58d))
+ - [commitgraph] Rename CommitData -> Commit. ([`d8c2007`](https://github.com/Byron/gitoxide/commit/d8c20072fdce7cba249f4d9b5a0cba6136beb06f))
+ - [commitgraph] Don't re-export graph_file symbols at crate level. ([`7c405ab`](https://github.com/Byron/gitoxide/commit/7c405aba660537999a24b6824198b3afb6dde529))
+ - Merge from main. ([`b59bd5e`](https://github.com/Byron/gitoxide/commit/b59bd5e0b0895c7d1d585816cec8be4dea78c278))
+ - [commitgraph] Ditch pre-generated test repos. ([`1ce8468`](https://github.com/Byron/gitoxide/commit/1ce84689ee89eb0f9e4f57cdba3a5ccac4a1a12d))
+ - [commitgraph] Remove `Kind` enum. ([`3c92761`](https://github.com/Byron/gitoxide/commit/3c927610eb717645e7f83a257184e44f76918571))
+ - [commitgraph] Take `info` dir as arg, not `objects` dir. ([`36953e0`](https://github.com/Byron/gitoxide/commit/36953e0ec6119e1a01ae9b8e46e40bbd083e732c))
+ - Refactor ([`e4bcfe6`](https://github.com/Byron/gitoxide/commit/e4bcfe6406b14feffa63598c7cdcc8ecc73222bd))
+ - [commitgraph] implement basic, low-level read API ([`d1f0e9c`](https://github.com/Byron/gitoxide/commit/d1f0e9cbd259b460a7d12ae068fb95ede0000cb2))
+ - Reorganize git-commitgraph goals; add crate ([`21c9b75`](https://github.com/Byron/gitoxide/commit/21c9b7500cb144b3169a6537961ec2b9e865be81))
+</details>
+
+## 0.12.0 (2022-12-22)
+
+A maintenance release without user-facing changes.
+
+## 0.11.0 (2022-11-21)
+
+### New Features (BREAKING)
+
+ - <csr-id-3d8fa8fef9800b1576beab8a5bc39b821157a5ed/> upgrade edition to 2021 in most crates.
+ MSRV for this is 1.56, and we are now at 1.60 so should be compatible.
+ This isn't more than a patch release as it should break nobody
+ who is adhering to the MSRV, but let's be careful and mark it
+ breaking.
+
+ Note that `gix-features` and `gix-pack` are still on edition 2018
+ as they make use of a workaround to support (safe) mutable access
+ to non-overlapping entries in a slice which doesn't work anymore
+ in edition 2021.
+
+## 0.10.0 (2022-11-06)
+
+A maintenance release without user-facing changes.
+
+## 0.9.0 (2022-09-20)
+
+### Changed (BREAKING)
+
+ - <csr-id-99905bacace8aed42b16d43f0f04cae996cb971c/> upgrade `bstr` to `1.0.1`
+
+## 0.8.2 (2022-08-24)
+
+<csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/>
+
+### Chore
+
+ - <csr-id-f7f136dbe4f86e7dee1d54835c420ec07c96cd78/> uniformize deny attributes
+
+### New Features
+
+ - <csr-id-b1c40b0364ef092cd52d03b34f491b254816b18d/> use docsrs feature in code to show what is feature-gated automatically on docs.rs
+ - <csr-id-517677147f1c17304c62cf97a1dd09f232ebf5db/> pass --cfg docsrs when compiling for https://docs.rs
+
+## 0.8.1 (2022-08-17)
+
+A maintenance release without user-facing changes.
+
+## 0.8.0 (2022-07-22)
+
+A maintenance release without user-facing changes.
+
+## 0.7.0 (2022-04-03)
+
+A maintenance release, triggered by putting too many adjustments into a single commit.
+
+### Changed (BREAKING)
+
+ - <csr-id-2ef9a8424af51310db8c1e6df31dde9953ed3d21/> Change accessors named `hash_kind()` to `object_hash()` for consistency
+
+### New Features
+
+ - <csr-id-265b8ec07fd5357df629f0d29fb2412d0186a287/> Add support for hashes of different size
+ Even though right now, there is only Sha1, in future it's easy to
+ support other hash sizes.
+
+## v0.6.0 (2021-10-19)
+
+A maintenance release due to properly dealing with previously breaking changes in `gix-hash`.
+
+## v0.5.0 (2021-10-15)
+
+This is a maintenance release without functional changes.
+
+## v0.4.4 (2021-09-07)
+
+## v0.4.3 (2021-08-29)
+
+## v0.4.2 (2021-08-17)
+
+## v0.4.1 (2021-08-15)
+
+<csr-id-29bf8ca8399b6d4941aa242b9f08c74e59a179bb/>
+
+### Other
+
+ - <csr-id-29bf8ca8399b6d4941aa242b9f08c74e59a179bb/> try to disable GPG signing with environment variables…
+ …but it's not picked up at all even though it's definitely present.
+
+## v0.4.0 (2021-04-08)
+
+## v0.3.2 (2021-02-11)
+
+## v0.3.1 (2021-01-09)
+
+## v0.3.0 (2020-12-16)
+
+## v0.2.0 (2020-12-15)
+
+## v0.1.2 (2020-10-01)
+
+## v0.1.1 (2020-10-01)
+
+## v0.1.0 (2020-10-01)
+
+## v0.0.0 (2020-08-20)
+
diff --git a/vendor/gix-commitgraph/Cargo.toml b/vendor/gix-commitgraph/Cargo.toml
new file mode 100644
index 000000000..d8b2e1090
--- /dev/null
+++ b/vendor/gix-commitgraph/Cargo.toml
@@ -0,0 +1,80 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.64"
+name = "gix-commitgraph"
+version = "0.16.0"
+authors = [
+ "Conor Davis <gitoxide@conor.fastmail.fm>",
+ "Sebastian Thiel <sebastian.thiel@icloud.com>",
+]
+include = [
+ "src/**/*",
+ "LICENSE-*",
+ "CHANGELOG.md",
+]
+description = "Read-only access to the git commitgraph file format"
+documentation = "https://git-scm.com/docs/commit-graph#:~:text=The%20commit-graph%20file%20is%20a%20supplemental%20data%20structure,or%20in%20the%20info%20directory%20of%20an%20alternate."
+license = "MIT/Apache-2.0"
+repository = "https://github.com/Byron/gitoxide"
+
+[package.metadata.docs.rs]
+all-features = true
+features = ["document-features"]
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
+
+[lib]
+doctest = false
+
+[dependencies.bstr]
+version = "1.3.0"
+features = ["std"]
+default-features = false
+
+[dependencies.document-features]
+version = "0.2.0"
+optional = true
+
+[dependencies.gix-chunk]
+version = "^0.4.2"
+
+[dependencies.gix-features]
+version = "^0.30.0"
+features = ["rustsha1"]
+
+[dependencies.gix-hash]
+version = "^0.11.2"
+
+[dependencies.memmap2]
+version = "0.5.0"
+
+[dependencies.serde]
+version = "1.0.114"
+features = ["derive"]
+optional = true
+default-features = false
+
+[dependencies.thiserror]
+version = "1.0.26"
+
+[dev-dependencies]
+
+[features]
+serde = [
+ "dep:serde",
+ "gix-hash/serde",
+ "bstr/serde",
+]
diff --git a/vendor/gix-commitgraph/LICENSE-APACHE b/vendor/gix-commitgraph/LICENSE-APACHE
new file mode 100644
index 000000000..a51f59a06
--- /dev/null
+++ b/vendor/gix-commitgraph/LICENSE-APACHE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/gix-commitgraph/LICENSE-MIT b/vendor/gix-commitgraph/LICENSE-MIT
new file mode 100644
index 000000000..b58e818f1
--- /dev/null
+++ b/vendor/gix-commitgraph/LICENSE-MIT
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors).
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/gix-commitgraph/src/access.rs b/vendor/gix-commitgraph/src/access.rs
new file mode 100644
index 000000000..ce3688f78
--- /dev/null
+++ b/vendor/gix-commitgraph/src/access.rs
@@ -0,0 +1,97 @@
+use crate::{file, file::Commit, File, Graph, Position};
+
+/// Access
+impl Graph {
+ /// Returns the commit at the given position `pos`.
+ ///
+ /// # Panics
+ /// If `pos` is greater or equal to [`num_commits()`][Graph::num_commits()].
+ pub fn commit_at(&self, pos: Position) -> Commit<'_> {
+ let r = self.lookup_by_pos(pos);
+ r.file.commit_at(r.pos)
+ }
+
+ /// Returns the commit matching the given `id`.
+ pub fn commit_by_id(&self, id: impl AsRef<gix_hash::oid>) -> Option<Commit<'_>> {
+ let r = self.lookup_by_id(id.as_ref())?;
+ Some(r.file.commit_at(r.file_pos))
+ }
+
+ /// Returns the `hash` at the given position `pos`.
+ ///
+ /// # Panics
+ /// If `pos` is greater or equal to [`num_commits()`][Graph::num_commits()].
+ pub fn id_at(&self, pos: Position) -> &gix_hash::oid {
+ let r = self.lookup_by_pos(pos);
+ r.file.id_at(r.pos)
+ }
+
+ /// Iterate over commits in unsorted order.
+ pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
+ self.files.iter().flat_map(|file| file.iter_commits())
+ }
+
+ /// Iterate over commit IDs in unsorted order.
+ pub fn iter_ids(&self) -> impl Iterator<Item = &gix_hash::oid> {
+ self.files.iter().flat_map(|file| file.iter_ids())
+ }
+
+ /// Translate the given `id` to its position in the file.
+ pub fn lookup(&self, id: impl AsRef<gix_hash::oid>) -> Option<Position> {
+ Some(self.lookup_by_id(id.as_ref())?.graph_pos)
+ }
+
+ /// Returns the number of commits stored in this file.
+ pub fn num_commits(&self) -> u32 {
+ self.files.iter().map(|f| f.num_commits()).sum()
+ }
+}
+
+/// Access fundamentals
+impl Graph {
+ fn lookup_by_id(&self, id: &gix_hash::oid) -> Option<LookupByIdResult<'_>> {
+ let mut current_file_start = 0;
+ for file in &self.files {
+ if let Some(lex_pos) = file.lookup(id) {
+ return Some(LookupByIdResult {
+ file,
+ file_pos: lex_pos,
+ graph_pos: Position(current_file_start + lex_pos.0),
+ });
+ }
+ current_file_start += file.num_commits();
+ }
+ None
+ }
+
+ fn lookup_by_pos(&self, pos: Position) -> LookupByPositionResult<'_> {
+ let mut remaining = pos.0;
+ for (file_index, file) in self.files.iter().enumerate() {
+ match remaining.checked_sub(file.num_commits()) {
+ Some(v) => remaining = v,
+ None => {
+ return LookupByPositionResult {
+ file,
+ _file_index: file_index,
+ pos: file::Position(remaining),
+ }
+ }
+ }
+ }
+ panic!("graph position too large: {}", pos.0);
+ }
+}
+
+#[derive(Clone)]
+struct LookupByIdResult<'a> {
+ pub file: &'a File,
+ pub graph_pos: Position,
+ pub file_pos: file::Position,
+}
+
+#[derive(Clone)]
+struct LookupByPositionResult<'a> {
+ pub file: &'a File,
+ pub _file_index: usize,
+ pub pos: file::Position,
+}
diff --git a/vendor/gix-commitgraph/src/file/access.rs b/vendor/gix-commitgraph/src/file/access.rs
new file mode 100644
index 000000000..d3c32d8bb
--- /dev/null
+++ b/vendor/gix-commitgraph/src/file/access.rs
@@ -0,0 +1,138 @@
+use std::{
+ convert::TryInto,
+ fmt::{Debug, Formatter},
+ path::Path,
+};
+
+use crate::{
+ file::{self, commit::Commit, COMMIT_DATA_ENTRY_SIZE_SANS_HASH},
+ File,
+};
+
+/// Access
+impl File {
+ /// The number of base graphs that this file depends on.
+ pub fn base_graph_count(&self) -> u8 {
+ self.base_graph_count
+ }
+
+ /// Returns the commit data for the commit located at the given lexigraphical position.
+ ///
+ /// `pos` must range from 0 to `self.num_commits()`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `pos` is out of bounds.
+ pub fn commit_at(&self, pos: file::Position) -> Commit<'_> {
+ Commit::new(self, pos)
+ }
+
+ /// The kind of hash used in this File.
+ ///
+ /// Note that it is always conforming to the hash used in the owning repository.
+ pub fn object_hash(&self) -> gix_hash::Kind {
+ self.object_hash
+ }
+
+ /// Returns an object id at the given index in our list of (sorted) hashes.
+ /// The position ranges from 0 to `self.num_commits()`
+ // copied from gix-odb/src/pack/index/ext
+ pub fn id_at(&self, pos: file::Position) -> &gix_hash::oid {
+ assert!(
+ pos.0 < self.num_commits(),
+ "expected lexigraphical position less than {}, got {}",
+ self.num_commits(),
+ pos.0
+ );
+ let pos: usize = pos
+ .0
+ .try_into()
+ .expect("an architecture able to hold 32 bits of integer");
+ let start = self.oid_lookup_offset + (pos * self.hash_len);
+ gix_hash::oid::from_bytes_unchecked(&self.data[start..][..self.hash_len])
+ }
+
+ /// Return an iterator over all object hashes stored in the base graph.
+ pub fn iter_base_graph_ids(&self) -> impl Iterator<Item = &gix_hash::oid> {
+ let start = self.base_graphs_list_offset.unwrap_or(0);
+ let base_graphs_list = &self.data[start..][..self.hash_len * usize::from(self.base_graph_count)];
+ base_graphs_list
+ .chunks(self.hash_len)
+ .map(gix_hash::oid::from_bytes_unchecked)
+ }
+
+ /// return an iterator over all commits in this file.
+ pub fn iter_commits(&self) -> impl Iterator<Item = Commit<'_>> {
+ (0..self.num_commits()).map(move |i| self.commit_at(file::Position(i)))
+ }
+
+ /// Return an iterator over all object hashes stored in this file.
+ pub fn iter_ids(&self) -> impl Iterator<Item = &gix_hash::oid> {
+ (0..self.num_commits()).map(move |i| self.id_at(file::Position(i)))
+ }
+
+ /// Translate the given object hash to its position within this file, if present.
+ // copied from gix-odb/src/pack/index/ext
+ pub fn lookup(&self, id: impl AsRef<gix_hash::oid>) -> Option<file::Position> {
+ let id = id.as_ref();
+ let first_byte = usize::from(id.first_byte());
+ let mut upper_bound = self.fan[first_byte];
+ let mut lower_bound = if first_byte != 0 { self.fan[first_byte - 1] } else { 0 };
+
+ while lower_bound < upper_bound {
+ let mid = (lower_bound + upper_bound) / 2;
+ let mid_sha = self.id_at(file::Position(mid));
+
+ use std::cmp::Ordering::*;
+ match id.cmp(mid_sha) {
+ Less => upper_bound = mid,
+ Equal => return Some(file::Position(mid)),
+ Greater => lower_bound = mid + 1,
+ }
+ }
+ None
+ }
+
+ /// Returns the number of commits in this graph file.
+ ///
+ /// The maximum valid `file::Position` that can be used with this file is one less than
+ /// `num_commits()`.
+ pub fn num_commits(&self) -> u32 {
+ self.fan[255]
+ }
+
+ /// Returns the path to this file.
+ pub fn path(&self) -> &Path {
+ &self.path
+ }
+}
+
+impl File {
+ /// Returns the byte slice for the given commit in this file's Commit Data (CDAT) chunk.
+ pub(crate) fn commit_data_bytes(&self, pos: file::Position) -> &[u8] {
+ assert!(
+ pos.0 < self.num_commits(),
+ "expected lexigraphical position less than {}, got {}",
+ self.num_commits(),
+ pos.0
+ );
+ let pos: usize = pos
+ .0
+ .try_into()
+ .expect("an architecture able to hold 32 bits of integer");
+ let entry_size = self.hash_len + COMMIT_DATA_ENTRY_SIZE_SANS_HASH;
+ let start = self.commit_data_offset + (pos * entry_size);
+ &self.data[start..][..entry_size]
+ }
+
+ /// Returns the byte slice for this file's entire Extra Edge List (EDGE) chunk.
+ pub(crate) fn extra_edges_data(&self) -> Option<&[u8]> {
+ Some(&self.data[self.extra_edges_list_range.clone()?])
+ }
+}
+
+impl Debug for File {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, r#"File("{:?}")"#, self.path.display())
+ }
+}
diff --git a/vendor/gix-commitgraph/src/file/commit.rs b/vendor/gix-commitgraph/src/file/commit.rs
new file mode 100644
index 000000000..14fe15e84
--- /dev/null
+++ b/vendor/gix-commitgraph/src/file/commit.rs
@@ -0,0 +1,258 @@
+//! Low-level operations on individual commits.
+use std::{
+ convert::TryInto,
+ fmt::{Debug, Formatter},
+ slice::Chunks,
+};
+
+use crate::{
+ file::{self, EXTENDED_EDGES_MASK, LAST_EXTENDED_EDGE_MASK, NO_PARENT},
+ File, Position,
+};
+
+/// The error used in the [`file::commit`][self] module.
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error("commit {0}'s extra edges overflows the commit-graph file's extra edges list")]
+ ExtraEdgesListOverflow(gix_hash::ObjectId),
+ #[error("commit {0}'s first parent is an extra edge index, which is invalid")]
+ FirstParentIsExtraEdgeIndex(gix_hash::ObjectId),
+ #[error("commit {0} has extra edges, but commit-graph file has no extra edges list")]
+ MissingExtraEdgesList(gix_hash::ObjectId),
+ #[error("commit {0} has a second parent but not a first parent")]
+ SecondParentWithoutFirstParent(gix_hash::ObjectId),
+}
+
+/// A commit as stored in a [`File`].
+#[derive(Copy, Clone)]
+pub struct Commit<'a> {
+ file: &'a File,
+ pos: file::Position,
+ // We can parse the below fields lazily if needed.
+ commit_timestamp: u64,
+ generation: u32,
+ parent1: ParentEdge,
+ parent2: ParentEdge,
+ root_tree_id: &'a gix_hash::oid,
+}
+
+#[inline]
+fn read_u32(b: &[u8]) -> u32 {
+ u32::from_be_bytes(b.try_into().unwrap())
+}
+
+impl<'a> Commit<'a> {
+ pub(crate) fn new(file: &'a File, pos: file::Position) -> Self {
+ let bytes = file.commit_data_bytes(pos);
+ Commit {
+ file,
+ pos,
+ root_tree_id: gix_hash::oid::from_bytes_unchecked(&bytes[..file.hash_len]),
+ parent1: ParentEdge::from_raw(read_u32(&bytes[file.hash_len..][..4])),
+ parent2: ParentEdge::from_raw(read_u32(&bytes[file.hash_len + 4..][..4])),
+ // TODO: Add support for corrected commit date offset overflow.
+ // See https://github.com/git/git/commit/e8b63005c48696a26f976f5f9b0ccaf1983e439d and
+ // https://github.com/git/git/commit/f90fca638e99a031dce8e3aca72427b2f9b4bb38 for more details and hints at a test.
+ generation: read_u32(&bytes[file.hash_len + 8..][..4]) >> 2,
+ commit_timestamp: u64::from_be_bytes(bytes[file.hash_len + 8..][..8].try_into().unwrap())
+ & 0x0003_ffff_ffff,
+ }
+ }
+
+ /// Returns the committer timestamp of this commit.
+ ///
+ /// The value is the number of seconds since 1970-01-01 00:00:00 UTC.
+ pub fn committer_timestamp(&self) -> u64 {
+ self.commit_timestamp
+ }
+
+ /// Returns the generation number of this commit.
+ ///
+ /// Commits without parents have generation number 1. Commits with parents have a generation
+ /// number that is the max of their parents' generation numbers + 1.
+ pub fn generation(&self) -> u32 {
+ self.generation
+ }
+
+ /// Returns an iterator over the parent positions for lookup in the owning [Graph][crate::Graph].
+ pub fn iter_parents(self) -> Parents<'a> {
+ // I didn't find a combinator approach that a) was as strict as ParentIterator, b) supported
+ // fuse-after-first-error behavior, and b) was significantly shorter or more understandable
+ // than ParentIterator. So here we are.
+ Parents {
+ commit_data: self,
+ state: ParentIteratorState::First,
+ }
+ }
+
+ /// Returns the hash of this commit.
+ pub fn id(&self) -> &'a gix_hash::oid {
+ self.file.id_at(self.pos)
+ }
+
+ /// Returns the first parent of this commit.
+ pub fn parent1(&self) -> Result<Option<Position>, Error> {
+ self.iter_parents().next().transpose()
+ }
+
+ /// Returns the position at which this commit is stored in the parent [File].
+ pub fn position(&self) -> file::Position {
+ self.pos
+ }
+
+ /// Return the hash of the tree this commit points to.
+ pub fn root_tree_id(&self) -> &gix_hash::oid {
+ self.root_tree_id
+ }
+}
+
+impl<'a> Debug for Commit<'a> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "Commit {{ id: {}, lex_pos: {}, generation: {}, root_tree_id: {}, parent1: {:?}, parent2: {:?} }}",
+ self.id(),
+ self.pos,
+ self.generation(),
+ self.root_tree_id(),
+ self.parent1,
+ self.parent2,
+ )
+ }
+}
+
+impl<'a> Eq for Commit<'a> {}
+
+impl<'a> PartialEq for Commit<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ std::ptr::eq(self.file, other.file) && self.pos == other.pos
+ }
+}
+
+/// An iterator over parents of a [`Commit`].
+pub struct Parents<'a> {
+ commit_data: Commit<'a>,
+ state: ParentIteratorState<'a>,
+}
+
+impl<'a> Iterator for Parents<'a> {
+ type Item = Result<Position, Error>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let state = std::mem::replace(&mut self.state, ParentIteratorState::Exhausted);
+ match state {
+ ParentIteratorState::First => match self.commit_data.parent1 {
+ ParentEdge::None => match self.commit_data.parent2 {
+ ParentEdge::None => None,
+ _ => Some(Err(Error::SecondParentWithoutFirstParent(self.commit_data.id().into()))),
+ },
+ ParentEdge::GraphPosition(pos) => {
+ self.state = ParentIteratorState::Second;
+ Some(Ok(pos))
+ }
+ ParentEdge::ExtraEdgeIndex(_) => {
+ Some(Err(Error::FirstParentIsExtraEdgeIndex(self.commit_data.id().into())))
+ }
+ },
+ ParentIteratorState::Second => match self.commit_data.parent2 {
+ ParentEdge::None => None,
+ ParentEdge::GraphPosition(pos) => Some(Ok(pos)),
+ ParentEdge::ExtraEdgeIndex(extra_edge_index) => {
+ if let Some(extra_edges_list) = self.commit_data.file.extra_edges_data() {
+ let start_offset: usize = extra_edge_index
+ .try_into()
+ .expect("an architecture able to hold 32 bits of integer");
+ let start_offset = start_offset
+ .checked_mul(4)
+ .expect("an extended edge index small enough to fit in usize");
+ if let Some(tail) = extra_edges_list.get(start_offset..) {
+ self.state = ParentIteratorState::Extra(tail.chunks(4));
+ // This recursive call is what blocks me from replacing ParentIterator
+ // with a std::iter::from_fn closure.
+ self.next()
+ } else {
+ Some(Err(Error::ExtraEdgesListOverflow(self.commit_data.id().into())))
+ }
+ } else {
+ Some(Err(Error::MissingExtraEdgesList(self.commit_data.id().into())))
+ }
+ }
+ },
+ ParentIteratorState::Extra(mut chunks) => {
+ if let Some(chunk) = chunks.next() {
+ let extra_edge = read_u32(chunk);
+ match ExtraEdge::from_raw(extra_edge) {
+ ExtraEdge::Internal(pos) => {
+ self.state = ParentIteratorState::Extra(chunks);
+ Some(Ok(pos))
+ }
+ ExtraEdge::Last(pos) => Some(Ok(pos)),
+ }
+ } else {
+ Some(Err(Error::ExtraEdgesListOverflow(self.commit_data.id().into())))
+ }
+ }
+ ParentIteratorState::Exhausted => None,
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match (&self.state, self.commit_data.parent1, self.commit_data.parent2) {
+ (ParentIteratorState::First, ParentEdge::None, ParentEdge::None) => (0, Some(0)),
+ (ParentIteratorState::First, ParentEdge::None, _) => (1, Some(1)),
+ (ParentIteratorState::First, ParentEdge::GraphPosition(_), ParentEdge::None) => (1, Some(1)),
+ (ParentIteratorState::First, ParentEdge::GraphPosition(_), ParentEdge::GraphPosition(_)) => (2, Some(2)),
+ (ParentIteratorState::First, ParentEdge::GraphPosition(_), ParentEdge::ExtraEdgeIndex(_)) => (3, None),
+ (ParentIteratorState::First, ParentEdge::ExtraEdgeIndex(_), _) => (1, Some(1)),
+ (ParentIteratorState::Second, _, ParentEdge::None) => (0, Some(0)),
+ (ParentIteratorState::Second, _, ParentEdge::GraphPosition(_)) => (1, Some(1)),
+ (ParentIteratorState::Second, _, ParentEdge::ExtraEdgeIndex(_)) => (2, None),
+ (ParentIteratorState::Extra(_), _, _) => (1, None),
+ (ParentIteratorState::Exhausted, _, _) => (0, Some(0)),
+ }
+ }
+}
+
+#[derive(Debug)]
+enum ParentIteratorState<'a> {
+ First,
+ Second,
+ Extra(Chunks<'a, u8>),
+ Exhausted,
+}
+
+#[derive(Clone, Copy, Debug)]
+enum ParentEdge {
+ None,
+ GraphPosition(Position),
+ ExtraEdgeIndex(u32),
+}
+
+impl ParentEdge {
+ pub fn from_raw(raw: u32) -> ParentEdge {
+ if raw == NO_PARENT {
+ return ParentEdge::None;
+ }
+ if raw & EXTENDED_EDGES_MASK != 0 {
+ ParentEdge::ExtraEdgeIndex(raw & !EXTENDED_EDGES_MASK)
+ } else {
+ ParentEdge::GraphPosition(Position(raw))
+ }
+ }
+}
+
+enum ExtraEdge {
+ Internal(Position),
+ Last(Position),
+}
+
+impl ExtraEdge {
+ pub fn from_raw(raw: u32) -> Self {
+ if raw & LAST_EXTENDED_EDGE_MASK != 0 {
+ Self::Last(Position(raw & !LAST_EXTENDED_EDGE_MASK))
+ } else {
+ Self::Internal(Position(raw))
+ }
+ }
+}
diff --git a/vendor/gix-commitgraph/src/file/init.rs b/vendor/gix-commitgraph/src/file/init.rs
new file mode 100644
index 000000000..1d8f52e3f
--- /dev/null
+++ b/vendor/gix-commitgraph/src/file/init.rs
@@ -0,0 +1,257 @@
+use std::{
+ convert::{TryFrom, TryInto},
+ path::Path,
+};
+
+use bstr::ByteSlice;
+use memmap2::Mmap;
+
+use crate::{
+ file::{
+ ChunkId, BASE_GRAPHS_LIST_CHUNK_ID, COMMIT_DATA_CHUNK_ID, COMMIT_DATA_ENTRY_SIZE_SANS_HASH,
+ EXTENDED_EDGES_LIST_CHUNK_ID, FAN_LEN, HEADER_LEN, OID_FAN_CHUNK_ID, OID_LOOKUP_CHUNK_ID, SIGNATURE,
+ },
+ File,
+};
+
+/// The error used in [`File::at()`].
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error("Commit-graph {:?} chunk contains {from_chunk} base graphs, but commit-graph file header claims {from_header} base graphs", BASE_GRAPHS_LIST_CHUNK_ID.as_bstr())]
+ BaseGraphMismatch { from_header: u8, from_chunk: u32 },
+ #[error("Commit-graph {:?} chunk contains {chunk1_commits} commits, but {:?} chunk contains {chunk2_commits} commits", .chunk1_id.as_bstr(), .chunk2_id.as_bstr())]
+ CommitCountMismatch {
+ chunk1_id: ChunkId,
+ chunk1_commits: u32,
+ chunk2_id: ChunkId,
+ chunk2_commits: u32,
+ },
+ #[error("{0}")]
+ Corrupt(String),
+ // This error case is disabled, as git allows extra garbage in the extra edges list?
+ // #[error("The last entry in commit-graph's extended edges list does is not marked as being terminal")]
+ // ExtraEdgesOverflow,
+ #[error("Could not open commit-graph file at '{}'", .path.display())]
+ Io {
+ #[source]
+ err: std::io::Error,
+ path: std::path::PathBuf,
+ },
+ #[error("{0}")]
+ Trailer(String),
+ #[error("Commit-graph file uses unsupported hash version: {0}")]
+ UnsupportedHashVersion(u8),
+ #[error("Unsupported commit-graph file version: {0}")]
+ UnsupportedVersion(u8),
+ #[error(transparent)]
+ ChunkFileDecode(#[from] gix_chunk::file::decode::Error),
+ #[error(transparent)]
+ MissingChunk(#[from] gix_chunk::file::index::offset_by_kind::Error),
+ #[error("Commit-graph chunk {:?} has invalid size: {msg}", .id.as_bstr())]
+ InvalidChunkSize { id: ChunkId, msg: String },
+}
+
+const MIN_FILE_SIZE: usize = HEADER_LEN
+ + gix_chunk::file::Index::size_for_entries(3 /*OIDF, OIDL, CDAT*/)
+ + FAN_LEN * 4 /* FANOUT TABLE CHUNK OIDF */
+ + gix_hash::Kind::shortest().len_in_bytes();
+
+impl File {
+ /// Try to parse the commit graph file at `path`.
+ pub fn at(path: impl AsRef<Path>) -> Result<File, Error> {
+ Self::try_from(path.as_ref())
+ }
+}
+
+impl TryFrom<&Path> for File {
+ type Error = Error;
+
+ fn try_from(path: &Path) -> Result<Self, Self::Error> {
+ let data = std::fs::File::open(path)
+ .and_then(|file| {
+ // SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file.
+ #[allow(unsafe_code)]
+ unsafe {
+ Mmap::map(&file)
+ }
+ })
+ .map_err(|e| Error::Io {
+ err: e,
+ path: path.to_owned(),
+ })?;
+ let data_size = data.len();
+ if data_size < MIN_FILE_SIZE {
+ return Err(Error::Corrupt(
+ "Commit-graph file too small even for an empty graph".to_owned(),
+ ));
+ }
+
+ let mut ofs = 0;
+ if &data[ofs..ofs + SIGNATURE.len()] != SIGNATURE {
+ return Err(Error::Corrupt(
+ "Commit-graph file does not start with expected signature".to_owned(),
+ ));
+ }
+ ofs += SIGNATURE.len();
+
+ match data[ofs] {
+ 1 => (),
+ x => {
+ return Err(Error::UnsupportedVersion(x));
+ }
+ };
+ ofs += 1;
+
+ let object_hash = gix_hash::Kind::try_from(data[ofs]).map_err(Error::UnsupportedHashVersion)?;
+ ofs += 1;
+
+ let chunk_count = data[ofs];
+ // Can assert chunk_count >= MIN_CHUNKS here, but later OIDF+OIDL+CDAT presence checks make
+ // it redundant.
+ ofs += 1;
+
+ let base_graph_count = data[ofs];
+ ofs += 1;
+
+ let chunks = gix_chunk::file::Index::from_bytes(&data, ofs, chunk_count as u32)?;
+
+ let base_graphs_list_offset = chunks
+ .validated_usize_offset_by_id(BASE_GRAPHS_LIST_CHUNK_ID, |chunk_range| {
+ let chunk_size = chunk_range.len();
+ if chunk_size % object_hash.len_in_bytes() != 0 {
+ return Err(Error::InvalidChunkSize {
+ id: BASE_GRAPHS_LIST_CHUNK_ID,
+ msg: format!(
+ "chunk size {} is not a multiple of {}",
+ chunk_size,
+ object_hash.len_in_bytes()
+ ),
+ });
+ }
+ let chunk_base_graph_count: u32 = (chunk_size / object_hash.len_in_bytes())
+ .try_into()
+ .expect("base graph count to fit in 32-bits");
+ if chunk_base_graph_count != u32::from(base_graph_count) {
+ return Err(Error::BaseGraphMismatch {
+ from_chunk: chunk_base_graph_count,
+ from_header: base_graph_count,
+ });
+ }
+ Ok(chunk_range.start)
+ })
+ .ok()
+ .transpose()?;
+
+ let (commit_data_offset, commit_data_count) =
+ chunks.validated_usize_offset_by_id(COMMIT_DATA_CHUNK_ID, |chunk_range| {
+ let chunk_size = chunk_range.len();
+
+ let entry_size = object_hash.len_in_bytes() + COMMIT_DATA_ENTRY_SIZE_SANS_HASH;
+ if chunk_size % entry_size != 0 {
+ return Err(Error::InvalidChunkSize {
+ id: COMMIT_DATA_CHUNK_ID,
+ msg: format!("chunk size {chunk_size} is not a multiple of {entry_size}"),
+ });
+ }
+ Ok((
+ chunk_range.start,
+ (chunk_size / entry_size)
+ .try_into()
+ .expect("number of commits in CDAT chunk to fit in 32 bits"),
+ ))
+ })??;
+
+ let fan_offset = chunks.validated_usize_offset_by_id(OID_FAN_CHUNK_ID, |chunk_range| {
+ let chunk_size = chunk_range.len();
+
+ let expected_size = 4 * FAN_LEN;
+ if chunk_size != expected_size {
+ return Err(Error::InvalidChunkSize {
+ id: OID_FAN_CHUNK_ID,
+ msg: format!("expected chunk length {expected_size}, got {chunk_size}"),
+ });
+ }
+ Ok(chunk_range.start)
+ })??;
+
+ let (oid_lookup_offset, oid_lookup_count) =
+ chunks.validated_usize_offset_by_id(OID_LOOKUP_CHUNK_ID, |chunk_range| {
+ let chunk_size = chunk_range.len();
+
+ if chunk_size % object_hash.len_in_bytes() != 0 {
+ return Err(Error::InvalidChunkSize {
+ id: OID_LOOKUP_CHUNK_ID,
+ msg: format!(
+ "chunk size {} is not a multiple of {}",
+ chunk_size,
+ object_hash.len_in_bytes()
+ ),
+ });
+ }
+ Ok((
+ chunk_range.start,
+ (chunk_size / object_hash.len_in_bytes())
+ .try_into()
+ .expect("number of commits in OIDL chunk to fit in 32 bits"),
+ ))
+ })??;
+
+ let extra_edges_list_range = chunks.usize_offset_by_id(EXTENDED_EDGES_LIST_CHUNK_ID).ok();
+
+ let trailer = &data[chunks.highest_offset() as usize..];
+ if trailer.len() != object_hash.len_in_bytes() {
+ return Err(Error::Trailer(format!(
+ "Expected commit-graph trailer to contain {} bytes, got {}",
+ object_hash.len_in_bytes(),
+ trailer.len()
+ )));
+ }
+
+ if base_graph_count > 0 && base_graphs_list_offset.is_none() {
+ return Err(gix_chunk::file::index::offset_by_kind::Error {
+ kind: BASE_GRAPHS_LIST_CHUNK_ID,
+ }
+ .into());
+ }
+
+ let (fan, _) = read_fan(&data[fan_offset..]);
+ if oid_lookup_count != fan[255] {
+ return Err(Error::CommitCountMismatch {
+ chunk1_id: OID_FAN_CHUNK_ID,
+ chunk1_commits: fan[255],
+ chunk2_id: OID_LOOKUP_CHUNK_ID,
+ chunk2_commits: oid_lookup_count,
+ });
+ }
+ if commit_data_count != fan[255] {
+ return Err(Error::CommitCountMismatch {
+ chunk1_id: OID_FAN_CHUNK_ID,
+ chunk1_commits: fan[255],
+ chunk2_id: COMMIT_DATA_CHUNK_ID,
+ chunk2_commits: commit_data_count,
+ });
+ }
+ Ok(File {
+ base_graph_count,
+ base_graphs_list_offset,
+ commit_data_offset,
+ data,
+ extra_edges_list_range,
+ fan,
+ oid_lookup_offset,
+ path: path.to_owned(),
+ hash_len: object_hash.len_in_bytes(),
+ object_hash,
+ })
+ }
+}
+
+// Copied from gix-odb/pack/index/init.rs
+fn read_fan(d: &[u8]) -> ([u32; FAN_LEN], usize) {
+ let mut fan = [0; FAN_LEN];
+ for (c, f) in d.chunks(4).zip(fan.iter_mut()) {
+ *f = u32::from_be_bytes(c.try_into().unwrap());
+ }
+ (fan, FAN_LEN * 4)
+}
diff --git a/vendor/gix-commitgraph/src/file/mod.rs b/vendor/gix-commitgraph/src/file/mod.rs
new file mode 100644
index 000000000..528cd69fb
--- /dev/null
+++ b/vendor/gix-commitgraph/src/file/mod.rs
@@ -0,0 +1,46 @@
+//! Operations on a single commit-graph file.
+
+use std::fmt::{Display, Formatter};
+
+pub use self::{commit::Commit, init::Error};
+
+mod access;
+pub mod commit;
+mod init;
+pub mod verify;
+
+const COMMIT_DATA_ENTRY_SIZE_SANS_HASH: usize = 16;
+pub(crate) const FAN_LEN: usize = 256;
+const HEADER_LEN: usize = 8;
+
+const SIGNATURE: &[u8] = b"CGPH";
+
+type ChunkId = gix_chunk::Id;
+const BASE_GRAPHS_LIST_CHUNK_ID: ChunkId = *b"BASE";
+const COMMIT_DATA_CHUNK_ID: ChunkId = *b"CDAT";
+const EXTENDED_EDGES_LIST_CHUNK_ID: ChunkId = *b"EDGE";
+const OID_FAN_CHUNK_ID: ChunkId = *b"OIDF";
+const OID_LOOKUP_CHUNK_ID: ChunkId = *b"OIDL";
+
+// Note that git's commit-graph-format.txt as of v2.28.0 gives an incorrect value 0x0700_0000 for
+// NO_PARENT. Fixed in https://github.com/git/git/commit/4d515253afcef985e94400adbfed7044959f9121 .
+const NO_PARENT: u32 = 0x7000_0000;
+const EXTENDED_EDGES_MASK: u32 = 0x8000_0000;
+const LAST_EXTENDED_EDGE_MASK: u32 = 0x8000_0000;
+
+/// The position of a given commit within a graph file, starting at 0.
+///
+/// Commits within a graph file are sorted in lexicographical order by OID; a commit's lexicographical position
+/// is its position in this ordering. If a commit graph spans multiple files, each file's commits
+/// start at lexicographical position 0, so it is unique across a single file but is not unique across
+/// the whole commit graph. Each commit also has a graph position ([`Position`][crate::Position]),
+/// which is unique across the whole commit graph.
+/// In order to avoid accidentally mixing lexicographical positions with graph positions, distinct types are used for each.
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct Position(pub u32);
+
+impl Display for Position {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
diff --git a/vendor/gix-commitgraph/src/file/verify.rs b/vendor/gix-commitgraph/src/file/verify.rs
new file mode 100644
index 000000000..4f4f76829
--- /dev/null
+++ b/vendor/gix-commitgraph/src/file/verify.rs
@@ -0,0 +1,173 @@
+//! Auxiliary types used in commit graph file verification methods.
+use std::{
+ cmp::{max, min},
+ collections::HashMap,
+ path::Path,
+};
+
+use crate::{file, File, GENERATION_NUMBER_INFINITY, GENERATION_NUMBER_MAX};
+
+/// The error used in [`File::traverse()`].
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error<E: std::error::Error + 'static> {
+ #[error(transparent)]
+ Commit(#[from] file::commit::Error),
+ #[error("commit at file position {pos} has invalid ID {id}")]
+ CommitId {
+ id: gix_hash::ObjectId,
+ pos: file::Position,
+ },
+ #[error("commit at file position {pos} with ID {id} is out of order relative to its predecessor with ID {predecessor_id}")]
+ CommitsOutOfOrder {
+ id: gix_hash::ObjectId,
+ pos: file::Position,
+ predecessor_id: gix_hash::ObjectId,
+ },
+ #[error("commit-graph filename should be {0}")]
+ Filename(String),
+ #[error("commit {id} has invalid generation {generation}")]
+ Generation { generation: u32, id: gix_hash::ObjectId },
+ #[error("checksum mismatch: expected {expected}, got {actual}")]
+ Mismatch {
+ actual: gix_hash::ObjectId,
+ expected: gix_hash::ObjectId,
+ },
+ #[error("{0}")]
+ Processor(#[source] E),
+ #[error("commit {id} has invalid root tree ID {root_tree_id}")]
+ RootTreeId {
+ id: gix_hash::ObjectId,
+ root_tree_id: gix_hash::ObjectId,
+ },
+}
+
+/// The positive result of [`File::traverse()`] providing some statistical information.
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+pub struct Outcome {
+ /// The largest encountered [`file::Commit`] generation number.
+ pub max_generation: u32,
+ /// The smallest encountered [`file::Commit`] generation number.
+ pub min_generation: u32,
+ /// The largest number of parents in a single [`file::Commit`].
+ pub max_parents: u32,
+ /// The total number of [`commits`][file::Commit]s seen in the iteration.
+ pub num_commits: u32,
+ /// A mapping of `N -> number of commits with N parents`.
+ pub parent_counts: HashMap<u32, u32>,
+}
+
+/// Verification
+impl File {
+ /// Returns the trailing checksum over the entire content of this file.
+ pub fn checksum(&self) -> &gix_hash::oid {
+ gix_hash::oid::from_bytes_unchecked(&self.data[self.data.len() - self.hash_len..])
+ }
+
+ /// Traverse all [commits][file::Commit] stored in this file and call `processor(commit) -> Result<(), Error>` on it.
+ ///
+ /// If the `processor` fails, the iteration will be stopped and the entire call results in the respective error.
+ pub fn traverse<'a, E, Processor>(&'a self, mut processor: Processor) -> Result<Outcome, Error<E>>
+ where
+ E: std::error::Error + 'static,
+ Processor: FnMut(&file::Commit<'a>) -> Result<(), E>,
+ {
+ self.verify_checksum()
+ .map_err(|(actual, expected)| Error::Mismatch { actual, expected })?;
+ verify_split_chain_filename_hash(&self.path, self.checksum()).map_err(Error::Filename)?;
+
+ let null_id = self.object_hash().null_ref();
+
+ let mut stats = Outcome {
+ max_generation: 0,
+ max_parents: 0,
+ min_generation: GENERATION_NUMBER_INFINITY,
+ num_commits: self.num_commits(),
+ parent_counts: HashMap::new(),
+ };
+
+ // TODO: Verify self.fan values as we go.
+ let mut prev_id: &gix_hash::oid = null_id;
+ for commit in self.iter_commits() {
+ if commit.id() <= prev_id {
+ if commit.id() == null_id {
+ return Err(Error::CommitId {
+ pos: commit.position(),
+ id: commit.id().into(),
+ });
+ }
+ return Err(Error::CommitsOutOfOrder {
+ pos: commit.position(),
+ id: commit.id().into(),
+ predecessor_id: prev_id.into(),
+ });
+ }
+ if commit.root_tree_id() == null_id {
+ return Err(Error::RootTreeId {
+ id: commit.id().into(),
+ root_tree_id: commit.root_tree_id().into(),
+ });
+ }
+ if commit.generation() > GENERATION_NUMBER_MAX {
+ return Err(Error::Generation {
+ generation: commit.generation(),
+ id: commit.id().into(),
+ });
+ }
+
+ processor(&commit).map_err(Error::Processor)?;
+
+ stats.max_generation = max(stats.max_generation, commit.generation());
+ stats.min_generation = min(stats.min_generation, commit.generation());
+ let parent_count = commit
+ .iter_parents()
+ .try_fold(0u32, |acc, pos| pos.map(|_| acc + 1))
+ .map_err(Error::Commit)?;
+ *stats.parent_counts.entry(parent_count).or_insert(0) += 1;
+ prev_id = commit.id();
+ }
+
+ if stats.min_generation == GENERATION_NUMBER_INFINITY {
+ stats.min_generation = 0;
+ }
+
+ Ok(stats)
+ }
+
+ /// Assure the [`checksum`][File::checksum()] matches the actual checksum over all content of this file, excluding the trailing
+ /// checksum itself.
+ ///
+ /// Return the actual checksum on success or `(actual checksum, expected checksum)` if there is a mismatch.
+ pub fn verify_checksum(&self) -> Result<gix_hash::ObjectId, (gix_hash::ObjectId, gix_hash::ObjectId)> {
+ // Even though we could use gix_features::hash::bytes_of_file(…), this would require using our own
+ // Error type to support io::Error and Mismatch. As we only gain progress, there probably isn't much value
+ // as these files are usually small enough to process them in less than a second, even for the large ones.
+ // But it's possible, once a progress instance is passed.
+ let data_len_without_trailer = self.data.len() - self.hash_len;
+ let mut hasher = gix_features::hash::hasher(self.object_hash());
+ hasher.update(&self.data[..data_len_without_trailer]);
+ let actual = gix_hash::ObjectId::from(hasher.digest().as_ref());
+
+ let expected = self.checksum();
+ if actual == expected {
+ Ok(actual)
+ } else {
+ Err((actual, expected.into()))
+ }
+ }
+}
+
+/// If the given path's filename matches "graph-{hash}.graph", check that `hash` matches the
+/// expected hash.
+fn verify_split_chain_filename_hash(path: impl AsRef<Path>, expected: &gix_hash::oid) -> Result<(), String> {
+ let path = path.as_ref();
+ path.file_name()
+ .and_then(|filename| filename.to_str())
+ .and_then(|filename| filename.strip_suffix(".graph"))
+ .and_then(|stem| stem.strip_prefix("graph-"))
+ .map_or(Ok(()), |hex| match gix_hash::ObjectId::from_hex(hex.as_bytes()) {
+ Ok(actual) if actual == expected => Ok(()),
+ _ => Err(format!("graph-{}.graph", expected.to_hex())),
+ })
+}
diff --git a/vendor/gix-commitgraph/src/init.rs b/vendor/gix-commitgraph/src/init.rs
new file mode 100644
index 000000000..f964aade0
--- /dev/null
+++ b/vendor/gix-commitgraph/src/init.rs
@@ -0,0 +1,130 @@
+use std::{
+ convert::TryFrom,
+ io::{BufRead, BufReader},
+ path::{Path, PathBuf},
+};
+
+use crate::{file, File, Graph, MAX_COMMITS};
+
+/// The error returned by initializations functions like [`Graph::at()`].
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error {
+ #[error("{}", .path.display())]
+ File {
+ #[source]
+ err: file::Error,
+ path: PathBuf,
+ },
+ #[error("Commit-graph files mismatch: '{}' uses hash {hash1:?}, but '{}' uses hash {hash2:?}", .path1.display(), .path2.display())]
+ HashVersionMismatch {
+ path1: PathBuf,
+ hash1: gix_hash::Kind,
+ path2: PathBuf,
+ hash2: gix_hash::Kind,
+ },
+ #[error("Did not find any files that look like commit graphs at '{}'", .0.display())]
+ InvalidPath(PathBuf),
+ #[error("Could not open commit-graph file at '{}'", .path.display())]
+ Io {
+ #[source]
+ err: std::io::Error,
+ path: PathBuf,
+ },
+ #[error(
+ "Commit-graph files contain {0} commits altogether, but only {} commits are allowed",
+ MAX_COMMITS
+ )]
+ TooManyCommits(u64),
+}
+
+/// Instantiate a `Graph` from various sources.
+impl Graph {
+ /// Instantiate a commit graph from `path` which may be a directory containing graph files or the graph file itself.
+ pub fn at(path: impl AsRef<Path>) -> Result<Self, Error> {
+ Self::try_from(path.as_ref())
+ }
+
+ /// Instantiate a commit graph from the directory containing all of its files.
+ pub fn from_commit_graphs_dir(path: impl AsRef<Path>) -> Result<Self, Error> {
+ let commit_graphs_dir = path.as_ref();
+ let chain_file_path = commit_graphs_dir.join("commit-graph-chain");
+ let chain_file = std::fs::File::open(&chain_file_path).map_err(|e| Error::Io {
+ err: e,
+ path: chain_file_path.clone(),
+ })?;
+ let mut files = Vec::new();
+ for line in BufReader::new(chain_file).lines() {
+ let hash = line.map_err(|e| Error::Io {
+ err: e,
+ path: chain_file_path.clone(),
+ })?;
+ let graph_file_path = commit_graphs_dir.join(format!("graph-{hash}.graph"));
+ files.push(File::at(&graph_file_path).map_err(|e| Error::File {
+ err: e,
+ path: graph_file_path.clone(),
+ })?);
+ }
+ Self::new(files)
+ }
+
+ /// Instantiate a commit graph from a `.git/objects/info/commit-graph` or
+ /// `.git/objects/info/commit-graphs/graph-*.graph` file.
+ pub fn from_file(path: impl AsRef<Path>) -> Result<Self, Error> {
+ let path = path.as_ref();
+ let file = File::at(path).map_err(|e| Error::File {
+ err: e,
+ path: path.to_owned(),
+ })?;
+ Self::new(vec![file])
+ }
+
+ /// Instantiate a commit graph from an `.git/objects/info` directory.
+ pub fn from_info_dir(info_dir: impl AsRef<Path>) -> Result<Self, Error> {
+ Self::from_file(info_dir.as_ref().join("commit-graph"))
+ .or_else(|_| Self::from_commit_graphs_dir(info_dir.as_ref().join("commit-graphs")))
+ }
+
+ /// Create a new commit graph from a list of `files`.
+ pub fn new(files: Vec<File>) -> Result<Self, Error> {
+ let num_commits: u64 = files.iter().map(|f| u64::from(f.num_commits())).sum();
+ if num_commits > u64::from(MAX_COMMITS) {
+ return Err(Error::TooManyCommits(num_commits));
+ }
+
+ for window in files.windows(2) {
+ let f1 = &window[0];
+ let f2 = &window[1];
+ if f1.object_hash() != f2.object_hash() {
+ return Err(Error::HashVersionMismatch {
+ path1: f1.path().to_owned(),
+ hash1: f1.object_hash(),
+ path2: f2.path().to_owned(),
+ hash2: f2.object_hash(),
+ });
+ }
+ }
+
+ Ok(Self { files })
+ }
+}
+
+impl TryFrom<&Path> for Graph {
+ type Error = Error;
+
+ fn try_from(path: &Path) -> Result<Self, Self::Error> {
+ if path.is_file() {
+ // Assume we are looking at `.git/objects/info/commit-graph` or
+ // `.git/objects/info/commit-graphs/graph-*.graph`.
+ Self::from_file(path)
+ } else if path.is_dir() {
+ if path.join("commit-graph-chain").is_file() {
+ Self::from_commit_graphs_dir(path)
+ } else {
+ Self::from_info_dir(path)
+ }
+ } else {
+ Err(Error::InvalidPath(path.to_owned()))
+ }
+ }
+}
diff --git a/vendor/gix-commitgraph/src/lib.rs b/vendor/gix-commitgraph/src/lib.rs
new file mode 100644
index 000000000..231c11c6f
--- /dev/null
+++ b/vendor/gix-commitgraph/src/lib.rs
@@ -0,0 +1,77 @@
+//! Read, verify, and traverse git commit graphs.
+//!
+//! A [commit graph][Graph] is an index of commits in the git commit history.
+//! The [Graph] stores commit data in a way that accelerates lookups considerably compared to
+//! traversing the git history by usual means.
+//!
+//! As generating the full commit graph from scratch can take some time, git may write new commits
+//! to separate [files][File] instead of overwriting the original file.
+//! Eventually, git will merge these files together as the number of files grows.
+//! ## Feature Flags
+#![cfg_attr(
+ feature = "document-features",
+ cfg_attr(doc, doc = ::document_features::document_features!())
+)]
+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
+#![deny(missing_docs, rust_2018_idioms, unsafe_code)]
+
+use std::path::Path;
+
+/// A single commit-graph file.
+///
+/// All operations on a `File` are local to that graph file. Since a commit graph can span multiple
+/// files, all interesting graph operations belong on [`Graph`][crate::Graph].
+pub struct File {
+ base_graph_count: u8,
+ base_graphs_list_offset: Option<usize>,
+ commit_data_offset: usize,
+ data: memmap2::Mmap,
+ extra_edges_list_range: Option<std::ops::Range<usize>>,
+ fan: [u32; file::FAN_LEN],
+ oid_lookup_offset: usize,
+ path: std::path::PathBuf,
+ hash_len: usize,
+ object_hash: gix_hash::Kind,
+}
+
+/// A complete commit graph.
+///
+/// The data in the commit graph may come from a monolithic `objects/info/commit-graph` file, or it
+/// may come from one or more `objects/info/commit-graphs/graph-*.graph` files. These files are
+/// generated via `git commit-graph write ...` commands.
+pub struct Graph {
+ files: Vec<File>,
+}
+
+/// Instantiate a commit graph from an `.git/objects/info` directory, or one of the various commit-graph files.
+pub fn at(path: impl AsRef<Path>) -> Result<Graph, init::Error> {
+ Graph::at(path)
+}
+
+mod access;
+pub mod file;
+///
+pub mod init;
+pub mod verify;
+
+/// The number of generations that are considered 'infinite' commit history.
+pub const GENERATION_NUMBER_INFINITY: u32 = 0xffff_ffff;
+/// The largest valid generation number.
+///
+/// If a commit's real generation number is larger than this, the commit graph will cap the value to
+/// this number.
+/// The largest distinct generation number is `GENERATION_NUMBER_MAX - 1`.
+pub const GENERATION_NUMBER_MAX: u32 = 0x3fff_ffff;
+
+/// The maximum number of commits that can be stored in a commit graph.
+pub const MAX_COMMITS: u32 = (1 << 30) + (1 << 29) + (1 << 28) - 1;
+
+/// A generalized position for use in [`Graph`].
+#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
+pub struct Position(pub u32);
+
+impl std::fmt::Display for Position {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
diff --git a/vendor/gix-commitgraph/src/verify.rs b/vendor/gix-commitgraph/src/verify.rs
new file mode 100644
index 000000000..2d863e648
--- /dev/null
+++ b/vendor/gix-commitgraph/src/verify.rs
@@ -0,0 +1,205 @@
+//! Auxiliary types used by graph verification methods.
+use std::{
+ cmp::{max, min},
+ collections::BTreeMap,
+ convert::TryInto,
+ path::PathBuf,
+};
+
+use crate::{
+ file::{self, commit},
+ Graph, Position, GENERATION_NUMBER_MAX,
+};
+
+/// The error used in [`verify_integrity()`][Graph::verify_integrity].
+#[derive(thiserror::Error, Debug)]
+#[allow(missing_docs)]
+pub enum Error<E: std::error::Error + 'static> {
+ #[error("'{}' should have {expected} base graphs, but claims {actual} base graphs", .path.display())]
+ BaseGraphCount { actual: u8, expected: u8, path: PathBuf },
+ #[error("'{}' base graph at index {index} should have ID {expected} but is {actual}", .path.display())]
+ BaseGraphId {
+ actual: gix_hash::ObjectId,
+ expected: gix_hash::ObjectId,
+ index: u8,
+ path: PathBuf,
+ },
+ #[error(transparent)]
+ Commit(#[from] commit::Error),
+ #[error("{}: {err}", .path.display())]
+ File {
+ // Use zero-size error type. We will never return
+ // `graph::verify::Error::File(file::verify::Error::Processor(...))`, because we are the
+ // file's processor, and we convert`file::verify::Error::Processor<graph::verify::Error>`
+ // variants into direct `graph::verify::Error` values.
+ err: file::verify::Error<std::convert::Infallible>,
+ path: PathBuf,
+ },
+ #[error("Commit {id}'s generation should be {expected} but is {actual}")]
+ Generation {
+ actual: u32,
+ expected: u32,
+ id: gix_hash::ObjectId,
+ },
+ #[error(
+ "Commit {id} has parent position {parent_pos} that is out of range (should be in range 0-{max_valid_pos})"
+ )]
+ ParentOutOfRange {
+ id: gix_hash::ObjectId,
+ max_valid_pos: Position,
+ parent_pos: Position,
+ },
+ #[error("{0}")]
+ Processor(#[source] E),
+ #[error("Commit-graph should be composed of at most 256 files but actually contains {0} files")]
+ TooManyFiles(usize),
+}
+
+/// Statistics gathered while verifying the integrity of the graph as returned by [`Graph::verify_integrity()`].
+#[derive(Clone, Debug, Eq, PartialEq)]
+#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
+pub struct Outcome {
+ /// The length of the longest path between any two commits in this graph.
+ ///
+ /// For example, this will be `Some(9)` for a commit graph containing 10 linear commits.
+ /// This will be `Some(0)` for a commit graph containing 0 or 1 commits.
+ /// If the longest path length is too large to fit in a [u32], then this will be [None].
+ pub longest_path_length: Option<u32>,
+ /// The total number of commits traversed.
+ pub num_commits: u32,
+ /// A mapping of `N -> number of commits with N parents`.
+ pub parent_counts: BTreeMap<u32, u32>,
+}
+
+impl Graph {
+ /// Traverse all commits in the graph and call `processor(&commit) -> Result<(), E>` on it while verifying checksums.
+ ///
+ /// When `processor` returns an error, the entire verification is stopped and the error returned.
+ pub fn verify_integrity<E>(
+ &self,
+ mut processor: impl FnMut(&file::Commit<'_>) -> Result<(), E>,
+ ) -> Result<Outcome, Error<E>>
+ where
+ E: std::error::Error + 'static,
+ {
+ if self.files.len() > 256 {
+ // A file in a split chain can only have up to 255 base files.
+ return Err(Error::TooManyFiles(self.files.len()));
+ }
+
+ let mut stats = Outcome {
+ longest_path_length: None,
+ num_commits: 0,
+ parent_counts: BTreeMap::new(),
+ };
+ let mut max_generation = 0u32;
+
+ // TODO: Detect duplicate commit IDs across different files. Not sure how to do this without
+ // a separate loop, e.g. self.iter_sorted_ids().
+
+ let mut file_start_pos = Position(0);
+ for (file_index, file) in self.files.iter().enumerate() {
+ if usize::from(file.base_graph_count()) != file_index {
+ return Err(Error::BaseGraphCount {
+ actual: file.base_graph_count(),
+ expected: file_index
+ .try_into()
+ .expect("files.len() check to protect against this"),
+ path: file.path().to_owned(),
+ });
+ }
+
+ for (base_graph_index, (expected, actual)) in self.files[..file_index]
+ .iter()
+ .map(|base_file| base_file.checksum())
+ .zip(file.iter_base_graph_ids())
+ .enumerate()
+ {
+ if actual != expected {
+ return Err(Error::BaseGraphId {
+ actual: actual.into(),
+ expected: expected.into(),
+ index: base_graph_index
+ .try_into()
+ .expect("files.len() check to protect against this"),
+ path: file.path().to_owned(),
+ });
+ }
+ }
+
+ let next_file_start_pos = Position(file_start_pos.0 + file.num_commits());
+ let file_stats = file
+ .traverse(|commit| {
+ let mut max_parent_generation = 0u32;
+ for parent_pos in commit.iter_parents() {
+ let parent_pos = parent_pos.map_err(Error::Commit)?;
+ if parent_pos >= next_file_start_pos {
+ return Err(Error::ParentOutOfRange {
+ parent_pos,
+ id: commit.id().into(),
+ max_valid_pos: Position(next_file_start_pos.0 - 1),
+ });
+ }
+ let parent = self.commit_at(parent_pos);
+ max_parent_generation = max(max_parent_generation, parent.generation());
+ }
+
+ // If the max parent generation is GENERATION_NUMBER_MAX, then this commit's
+ // generation should be GENERATION_NUMBER_MAX too.
+ let expected_generation = min(max_parent_generation + 1, GENERATION_NUMBER_MAX);
+ if commit.generation() != expected_generation {
+ return Err(Error::Generation {
+ actual: commit.generation(),
+ expected: expected_generation,
+ id: commit.id().into(),
+ });
+ }
+
+ processor(commit).map_err(Error::Processor)?;
+
+ Ok(())
+ })
+ .map_err(|err| Error::File {
+ err: match err {
+ file::verify::Error::Processor(e) => return e,
+ file::verify::Error::RootTreeId { id, root_tree_id } => {
+ file::verify::Error::RootTreeId { id, root_tree_id }
+ }
+ file::verify::Error::Mismatch { actual, expected } => {
+ file::verify::Error::Mismatch { actual, expected }
+ }
+ file::verify::Error::Generation { generation, id } => {
+ file::verify::Error::Generation { generation, id }
+ }
+ file::verify::Error::Filename(expected) => file::verify::Error::Filename(expected),
+ file::verify::Error::Commit(err) => file::verify::Error::Commit(err),
+ file::verify::Error::CommitId { id, pos } => file::verify::Error::CommitId { id, pos },
+ file::verify::Error::CommitsOutOfOrder {
+ id,
+ pos,
+ predecessor_id,
+ } => file::verify::Error::CommitsOutOfOrder {
+ id,
+ pos,
+ predecessor_id,
+ },
+ },
+ path: file.path().to_owned(),
+ })?;
+
+ max_generation = max(max_generation, file_stats.max_generation);
+ stats.num_commits += file_stats.num_commits;
+ for (key, value) in file_stats.parent_counts.into_iter() {
+ *stats.parent_counts.entry(key).or_insert(0) += value;
+ }
+ file_start_pos = next_file_start_pos;
+ }
+
+ stats.longest_path_length = if max_generation < GENERATION_NUMBER_MAX {
+ Some(max_generation.saturating_sub(1))
+ } else {
+ None
+ };
+ Ok(stats)
+ }
+}