add crate to keep gitoxide conversions to prevent duplication

This commit is contained in:
Sebastian Thiel 2024-09-24 15:38:13 +02:00
parent d16656816d
commit fe7d5d92e7
No known key found for this signature in database
GPG Key ID: 9CB5EE7895E8268B
11 changed files with 118 additions and 102 deletions

78
Cargo.lock generated
View File

@ -160,9 +160,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.86" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@ -328,9 +328,9 @@ dependencies = [
[[package]] [[package]]
name = "async-signal" name = "async-signal"
version = "0.2.10" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32"
dependencies = [ dependencies = [
"async-io 2.3.4", "async-io 2.3.4",
"async-lock 3.4.0", "async-lock 3.4.0",
@ -341,7 +341,7 @@ dependencies = [
"rustix 0.38.34", "rustix 0.38.34",
"signal-hook-registry", "signal-hook-registry",
"slab", "slab",
"windows-sys 0.59.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -404,7 +404,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -689,9 +689,9 @@ dependencies = [
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.17.0" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31" checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@ -750,7 +750,7 @@ checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -1971,7 +1971,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -1988,7 +1988,7 @@ dependencies = [
"libc", "libc",
"pango-sys", "pango-sys",
"pkg-config", "pkg-config",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -2002,7 +2002,7 @@ dependencies = [
"gobject-sys", "gobject-sys",
"libc", "libc",
"pkg-config", "pkg-config",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -2014,7 +2014,7 @@ dependencies = [
"gdk-sys", "gdk-sys",
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
"x11", "x11",
] ]
@ -2105,7 +2105,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
"winapi", "winapi",
] ]
@ -2147,6 +2147,7 @@ dependencies = [
"gitbutler-error", "gitbutler-error",
"gitbutler-fs", "gitbutler-fs",
"gitbutler-id", "gitbutler-id",
"gitbutler-oxidize",
"gitbutler-reference", "gitbutler-reference",
"gitbutler-serde", "gitbutler-serde",
"gix", "gix",
@ -2180,6 +2181,7 @@ dependencies = [
"gitbutler-id", "gitbutler-id",
"gitbutler-operating-modes", "gitbutler-operating-modes",
"gitbutler-oplog", "gitbutler-oplog",
"gitbutler-oxidize",
"gitbutler-project", "gitbutler-project",
"gitbutler-reference", "gitbutler-reference",
"gitbutler-repo", "gitbutler-repo",
@ -2423,6 +2425,15 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "gitbutler-oxidize"
version = "0.0.0"
dependencies = [
"anyhow",
"git2",
"gix",
]
[[package]] [[package]]
name = "gitbutler-project" name = "gitbutler-project"
version = "0.0.0" version = "0.0.0"
@ -2473,6 +2484,7 @@ dependencies = [
"gitbutler-error", "gitbutler-error",
"gitbutler-git", "gitbutler-git",
"gitbutler-id", "gitbutler-id",
"gitbutler-oxidize",
"gitbutler-project", "gitbutler-project",
"gitbutler-reference", "gitbutler-reference",
"gitbutler-testsupport", "gitbutler-testsupport",
@ -3877,7 +3889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4" checksum = "ef4b192f8e65e9cf76cbf4ea71fa8e3be4a0e18ffe3d68b8da6836974cc5bad4"
dependencies = [ dependencies = [
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -3907,7 +3919,7 @@ checksum = "0d57ce44246becd17153bd035ab4d32cfee096a657fc01f2231c9278378d1e0a"
dependencies = [ dependencies = [
"glib-sys", "glib-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -3948,7 +3960,7 @@ dependencies = [
"gobject-sys", "gobject-sys",
"libc", "libc",
"pango-sys", "pango-sys",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -5489,7 +5501,7 @@ dependencies = [
"glib-sys", "glib-sys",
"gobject-sys", "gobject-sys",
"libc", "libc",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -7251,15 +7263,15 @@ dependencies = [
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "6.2.2" version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
dependencies = [ dependencies = [
"cfg-expr 0.15.8", "cfg-expr 0.15.8",
"heck 0.5.0", "heck 0.4.1",
"pkg-config", "pkg-config",
"toml 0.8.19", "toml 0.8.19",
"version-compare 0.2.0", "version-compare 0.1.1",
] ]
[[package]] [[package]]
@ -7311,13 +7323,13 @@ dependencies = [
[[package]] [[package]]
name = "tao-macros" name = "tao-macros"
version = "0.1.3" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" checksum = "ec114582505d158b669b136e6851f85840c109819d77c42bb7c0709f727d18c2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 1.0.109",
] ]
[[package]] [[package]]
@ -8192,9 +8204,9 @@ checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.2.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]] [[package]]
name = "version_check" name = "version_check"
@ -8402,7 +8414,7 @@ dependencies = [
"pango-sys", "pango-sys",
"pkg-config", "pkg-config",
"soup2-sys", "soup2-sys",
"system-deps 6.2.2", "system-deps 6.2.0",
] ]
[[package]] [[package]]
@ -8745,9 +8757,9 @@ checksum = "f838de2fe15fe6bac988e74b798f26499a8b21a9d97edec321e79b28d1d7f597"
[[package]] [[package]]
name = "windows-version" name = "windows-version"
version = "0.1.1" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4"
dependencies = [ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@ -9021,12 +9033,12 @@ dependencies = [
[[package]] [[package]]
name = "xdg-home" name = "xdg-home"
version = "1.3.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.59.0", "winapi",
] ]
[[package]] [[package]]

View File

@ -31,6 +31,7 @@ members = [
"crates/gitbutler-operating-modes", "crates/gitbutler-operating-modes",
"crates/gitbutler-edit-mode", "crates/gitbutler-edit-mode",
"crates/gitbutler-cherry-pick", "crates/gitbutler-cherry-pick",
"crates/gitbutler-oxidize",
] ]
resolver = "2" resolver = "2"
@ -83,6 +84,7 @@ gitbutler-diff = { path = "crates/gitbutler-diff" }
gitbutler-operating-modes = { path = "crates/gitbutler-operating-modes" } gitbutler-operating-modes = { path = "crates/gitbutler-operating-modes" }
gitbutler-edit-mode = { path = "crates/gitbutler-edit-mode" } gitbutler-edit-mode = { path = "crates/gitbutler-edit-mode" }
gitbutler-cherry-pick = { path = "crates/gitbutler-cherry-pick" } gitbutler-cherry-pick = { path = "crates/gitbutler-cherry-pick" }
gitbutler-oxidize = { path = "crates/gitbutler-oxidize" }
[profile.release] [profile.release]
codegen-units = 1 # Compile crates one after another so the compiler can optimize better codegen-units = 1 # Compile crates one after another so the compiler can optimize better

View File

@ -26,6 +26,7 @@ gitbutler-fs.workspace = true
gitbutler-diff.workspace = true gitbutler-diff.workspace = true
gitbutler-operating-modes.workspace = true gitbutler-operating-modes.workspace = true
gitbutler-cherry-pick.workspace = true gitbutler-cherry-pick.workspace = true
gitbutler-oxidize.workspace = true
serde = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["std"] }
bstr.workspace = true bstr.workspace = true
diffy = "0.4.0" diffy = "0.4.0"

View File

@ -7,6 +7,7 @@ use gitbutler_branch::{
}; };
use gitbutler_command_context::CommandContext; use gitbutler_command_context::CommandContext;
use gitbutler_diff::DiffByPathMap; use gitbutler_diff::DiffByPathMap;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_project::access::WorktreeReadPermission; use gitbutler_project::access::WorktreeReadPermission;
use gitbutler_reference::normalize_branch_name; use gitbutler_reference::normalize_branch_name;
use gitbutler_repo::{GixRepositoryExt, RepositoryExt as _}; use gitbutler_repo::{GixRepositoryExt, RepositoryExt as _};
@ -290,14 +291,6 @@ fn branch_group_to_branch(
})) }))
} }
fn gix_to_git2_oid(id: impl Into<gix::ObjectId>) -> git2::Oid {
git2::Oid::from_bytes(id.into().as_bytes()).expect("always valid")
}
fn git2_to_gix_object_id(id: git2::Oid) -> gix::ObjectId {
gix::ObjectId::try_from(id.as_bytes()).expect("git2 oid is always valid")
}
/// A sum type of branch that can be a plain git branch or a virtual branch /// A sum type of branch that can be a plain git branch or a virtual branch
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
enum GroupBranch<'a> { enum GroupBranch<'a> {

View File

@ -21,6 +21,7 @@ use gitbutler_commit::{commit_ext::CommitExt, commit_headers::HasCommitHeaders};
use gitbutler_diff::{trees, GitHunk, Hunk}; use gitbutler_diff::{trees, GitHunk, Hunk};
use gitbutler_error::error::{Code, Marker}; use gitbutler_error::error::{Code, Marker};
use gitbutler_operating_modes::assure_open_workspace_mode; use gitbutler_operating_modes::assure_open_workspace_mode;
use gitbutler_oxidize::git2_signature_to_gix_signature;
use gitbutler_project::access::WorktreeWritePermission; use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_reference::{normalize_branch_name, Refname, RemoteRefname}; use gitbutler_reference::{normalize_branch_name, Refname, RemoteRefname};
use gitbutler_repo::{ use gitbutler_repo::{
@ -454,18 +455,6 @@ impl TryFrom<&git2::Commit<'_>> for CommitData {
} }
} }
fn git2_signature_to_gix_signature(input: git2::Signature<'_>) -> gix::actor::Signature {
gix::actor::Signature {
name: input.name_bytes().into(),
email: input.email_bytes().into(),
time: gix::date::Time {
seconds: input.when().seconds(),
offset: input.when().offset_minutes() * 60,
sign: input.when().offset_minutes().into(),
},
}
}
fn branches_with_large_files_abridged(mut branches: Vec<VirtualBranch>) -> Vec<VirtualBranch> { fn branches_with_large_files_abridged(mut branches: Vec<VirtualBranch>) -> Vec<VirtualBranch> {
for branch in &mut branches { for branch in &mut branches {
for file in &mut branch.files { for file in &mut branch.files {

View File

@ -15,6 +15,7 @@ gitbutler-id.workspace = true
gitbutler-error.workspace = true gitbutler-error.workspace = true
gitbutler-fs.workspace = true gitbutler-fs.workspace = true
gitbutler-diff.workspace = true gitbutler-diff.workspace = true
gitbutler-oxidize.workspace = true
itertools = "0.13" itertools = "0.13"
toml.workspace = true toml.workspace = true
serde = { workspace = true, features = ["std"] } serde = { workspace = true, features = ["std"] }

View File

@ -1,8 +1,6 @@
mod branch; mod branch;
use anyhow::Context;
pub use branch::{Branch, BranchCreateRequest, BranchId, BranchIdentity, BranchUpdateRequest}; pub use branch::{Branch, BranchCreateRequest, BranchId, BranchIdentity, BranchUpdateRequest};
use bstr::ByteSlice;
mod branch_ext; mod branch_ext;
pub use branch_ext::BranchExt; pub use branch_ext::BranchExt;
mod reference_ext; mod reference_ext;
@ -20,6 +18,7 @@ mod reference;
pub use reference::ChangeReference; pub use reference::ChangeReference;
mod state; mod state;
use gitbutler_oxidize::gix_to_git2_signature;
use lazy_static::lazy_static; use lazy_static::lazy_static;
pub use state::{VirtualBranches as VirtualBranchesState, VirtualBranchesHandle}; pub use state::{VirtualBranches as VirtualBranchesState, VirtualBranchesHandle};
lazy_static! { lazy_static! {
@ -49,26 +48,6 @@ pub fn signature(purpose: SignaturePurpose) -> anyhow::Result<git2::Signature<'s
gix_to_git2_signature(signature) gix_to_git2_signature(signature)
} }
/// Convert `actor` to a `git2` representation or fail if that's not possible.
/// Note that the current time as provided by `gix` is also used as it.
pub fn gix_to_git2_signature(
actor: gix::actor::SignatureRef<'_>,
) -> anyhow::Result<git2::Signature<'static>> {
let offset_in_minutes = actor.time.offset / 60;
let time = git2::Time::new(actor.time.seconds, offset_in_minutes);
Ok(git2::Signature::new(
actor
.name
.to_str()
.with_context(|| format!("Could not process actor name: {}", actor.name))?,
actor
.email
.to_str()
.with_context(|| format!("Could not process actor email: {}", actor.email))?,
&time,
)?)
}
/// Return the time of a commit as `now` unless the `overriding_variable_name` contains a parseable date, /// Return the time of a commit as `now` unless the `overriding_variable_name` contains a parseable date,
/// which is used instead. /// which is used instead.
fn commit_time(overriding_variable_name: &str) -> gix::date::Time { fn commit_time(overriding_variable_name: &str) -> gix::date::Time {

View File

@ -0,0 +1,11 @@
[package]
name = "gitbutler-oxidize"
version = "0.0.0"
edition = "2021"
authors = ["GitButler <gitbutler@gitbutler.com>"]
publish = false
[dependencies]
anyhow.workspace = true
gix.workspace = true
git2.workspace = true

View File

@ -0,0 +1,48 @@
//! A crate with various utilities to make the migration to `gitoxide` less cumbersome and repetitive.
use anyhow::Context;
use gix::bstr::ByteSlice;
use std::borrow::Borrow;
pub fn git2_to_gix_object_id(id: git2::Oid) -> gix::ObjectId {
gix::ObjectId::try_from(id.as_bytes()).expect("git2 oid is always valid")
}
pub fn gix_to_git2_oid(id: impl Into<gix::ObjectId>) -> git2::Oid {
git2::Oid::from_bytes(id.into().as_bytes()).expect("always valid")
}
pub fn git2_signature_to_gix_signature<'a>(
input: impl Borrow<git2::Signature<'a>>,
) -> gix::actor::Signature {
let input = input.borrow();
gix::actor::Signature {
name: input.name_bytes().into(),
email: input.email_bytes().into(),
time: gix::date::Time {
seconds: input.when().seconds(),
offset: input.when().offset_minutes() * 60,
sign: input.when().offset_minutes().into(),
},
}
}
/// Convert `actor` to a `git2` representation or fail if that's not possible.
/// Note that the current time as provided by `gix` is also used as it.
pub fn gix_to_git2_signature(
actor: gix::actor::SignatureRef<'_>,
) -> anyhow::Result<git2::Signature<'static>> {
let offset_in_minutes = actor.time.offset / 60;
let time = git2::Time::new(actor.time.seconds, offset_in_minutes);
Ok(git2::Signature::new(
actor
.name
.to_str()
.with_context(|| format!("Could not process actor name: {}", actor.name))?,
actor
.email
.to_str()
.with_context(|| format!("Could not process actor email: {}", actor.email))?,
&time,
)?)
}

View File

@ -35,6 +35,7 @@ gitbutler-time.workspace = true
gitbutler-commit.workspace = true gitbutler-commit.workspace = true
gitbutler-url.workspace = true gitbutler-url.workspace = true
gitbutler-cherry-pick.workspace = true gitbutler-cherry-pick.workspace = true
gitbutler-oxidize.workspace = true
uuid.workspace = true uuid.workspace = true
itertools = "0.13" itertools = "0.13"

View File

@ -4,20 +4,22 @@ use std::os::unix::fs::PermissionsExt;
use std::os::windows::process::CommandExt; use std::os::windows::process::CommandExt;
use std::{io::Write, path::Path, process::Stdio, str}; use std::{io::Write, path::Path, process::Stdio, str};
use crate::{Config, LogUntil};
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use bstr::{BString, ByteSlice}; use bstr::{BString, ByteSlice};
use git2::{BlameOptions, Tree}; use git2::{BlameOptions, Tree};
use gitbutler_branch::{gix_to_git2_signature, SignaturePurpose}; use gitbutler_branch::SignaturePurpose;
use gitbutler_commit::commit_headers::CommitHeadersV2; use gitbutler_commit::commit_headers::CommitHeadersV2;
use gitbutler_config::git::{GbConfig, GitConfig}; use gitbutler_config::git::{GbConfig, GitConfig};
use gitbutler_error::error::Code; use gitbutler_error::error::Code;
use gitbutler_oxidize::{
git2_signature_to_gix_signature, git2_to_gix_object_id, gix_to_git2_oid, gix_to_git2_signature,
};
use gitbutler_reference::{Refname, RemoteRefname}; use gitbutler_reference::{Refname, RemoteRefname};
use gix::objs::WriteTo; use gix::objs::WriteTo;
use gix::status::plumbing::index_as_worktree::{Change, EntryStatus}; use gix::status::plumbing::index_as_worktree::{Change, EntryStatus};
use tracing::instrument; use tracing::instrument;
use crate::{Config, LogUntil};
/// Extension trait for `git2::Repository`. /// Extension trait for `git2::Repository`.
/// ///
/// For now, it collects useful methods from `gitbutler-core::git::Repository` /// For now, it collects useful methods from `gitbutler-core::git::Repository`
@ -536,7 +538,7 @@ impl RepositoryExt for git2::Repository {
let author = repo let author = repo
.author() .author()
.transpose()? .transpose()?
.map(gitbutler_branch::gix_to_git2_signature) .map(gix_to_git2_signature)
.transpose()? .transpose()?
.context("No author is configured in Git") .context("No author is configured in Git")
.context(Code::AuthorMissing)?; .context(Code::AuthorMissing)?;
@ -619,7 +621,6 @@ impl CheckoutIndexBuilder<'_> {
} }
} }
// TODO(ST): put this into `gix`, the logic seems good, add unit-test for number generation.
pub trait GixRepositoryExt: Sized { pub trait GixRepositoryExt: Sized {
/// Configure the repository for diff operations between trees. /// Configure the repository for diff operations between trees.
/// This means it needs an object cache relative to the amount of files in the repository. /// This means it needs an object cache relative to the amount of files in the repository.
@ -633,25 +634,3 @@ impl GixRepositoryExt for gix::Repository {
Ok(self) Ok(self)
} }
} }
// TODO: expose in separate crate to deduplicate
fn git2_to_gix_object_id(id: git2::Oid) -> gix::ObjectId {
gix::ObjectId::try_from(id.as_bytes()).expect("git2 oid is always valid")
}
// TODO: expose in separate crate to deduplicate
fn git2_signature_to_gix_signature(input: &git2::Signature<'_>) -> gix::actor::Signature {
gix::actor::Signature {
name: input.name_bytes().into(),
email: input.email_bytes().into(),
time: gix::date::Time {
seconds: input.when().seconds(),
offset: input.when().offset_minutes() * 60,
sign: input.when().offset_minutes().into(),
},
}
}
fn gix_to_git2_oid(id: impl Into<gix::ObjectId>) -> git2::Oid {
git2::Oid::from_bytes(id.into().as_bytes()).expect("always valid")
}