Skip to content

Commit

Permalink
Make gix::Repository extension available in oxidize.
Browse files Browse the repository at this point in the history
It has minimal dependencies and can be used everywhere.
  • Loading branch information
Byron committed Dec 6, 2024
1 parent 398b2aa commit 85bf792
Show file tree
Hide file tree
Showing 16 changed files with 160 additions and 150 deletions.
4 changes: 2 additions & 2 deletions crates/gitbutler-branch-actions/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use anyhow::{anyhow, bail, Context, Result};
use gitbutler_branch::GITBUTLER_WORKSPACE_REFERENCE;
use gitbutler_command_context::CommandContext;
use gitbutler_error::error::Marker;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
use gitbutler_project::FetchResult;
use gitbutler_reference::{Refname, RemoteRefname};
use gitbutler_repo::{GixRepositoryExt, LogUntil, RepositoryExt};
use gitbutler_repo::{LogUntil, RepositoryExt};
use gitbutler_repo_actions::RepoActionsExt;
use gitbutler_stack::{BranchOwnershipClaims, Stack, Target, VirtualBranchesHandle};
use serde::Serialize;
Expand Down
4 changes: 2 additions & 2 deletions crates/gitbutler-branch-actions/src/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use gitbutler_branch::BranchIdentity;
use gitbutler_branch::ReferenceExtGix;
use gitbutler_command_context::CommandContext;
use gitbutler_diff::DiffByPathMap;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
use gitbutler_project::access::WorktreeReadPermission;
use gitbutler_reference::normalize_branch_name;
use gitbutler_reference::RemoteRefname;
use gitbutler_repo::{GixRepositoryExt, RepositoryExt as _};
use gitbutler_repo::RepositoryExt as _;
use gitbutler_serde::BStringForFrontend;
use gitbutler_stack::{Stack as GitButlerBranch, StackId, Target};
use gix::object::tree::diff::Action;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
use super::BranchManager;
use crate::r#virtual as vbranch;
use crate::{
conflicts::RepoConflictsExt, hunk::VirtualBranchHunk, integration::update_workspace_commit,
VirtualBranchesExt,
};
use anyhow::{anyhow, bail, Context, Result};
use gitbutler_branch::BranchCreateRequest;
use gitbutler_branch::{self, dedup};
use gitbutler_cherry_pick::RepositoryExt as _;
use gitbutler_commit::{commit_ext::CommitExt, commit_headers::HasCommitHeaders};
use gitbutler_error::error::Marker;
use gitbutler_oplog::SnapshotExt;
use gitbutler_oxidize::GixRepositoryExt;
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_reference::{Refname, RemoteRefname};
use gitbutler_repo::GixRepositoryExt;
use gitbutler_repo::{
rebase::{cherry_rebase_group, gitbutler_merge_commits},
LogUntil, RepositoryExt,
Expand All @@ -19,12 +24,6 @@ use gitbutler_time::time::now_since_unix_epoch_ms;
use gitbutler_workspace::checkout_branch_trees;
use tracing::instrument;

use super::BranchManager;
use crate::{
conflicts::RepoConflictsExt, hunk::VirtualBranchHunk, integration::update_workspace_commit,
VirtualBranchesExt,
};

impl BranchManager<'_> {
#[instrument(level = tracing::Level::DEBUG, skip(self, perm), err(Debug))]
pub fn create_virtual_branch(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ use git2::Commit;
use gitbutler_branch::BranchExt;
use gitbutler_commit::commit_headers::CommitHeadersV2;
use gitbutler_oplog::SnapshotExt;
use gitbutler_oxidize::git2_to_gix_object_id;
use gitbutler_oxidize::gix_to_git2_oid;
use gitbutler_oxidize::{git2_to_gix_object_id, GixRepositoryExt};
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_reference::{normalize_branch_name, ReferenceName, Refname};
use gitbutler_repo::GixRepositoryExt;
use gitbutler_repo::RepositoryExt;
use gitbutler_repo::SignaturePurpose;
use gitbutler_repo_actions::RepoActionsExt;
Expand Down
4 changes: 2 additions & 2 deletions crates/gitbutler-branch-actions/src/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt;
use gitbutler_error::error::Marker;
use gitbutler_operating_modes::OPEN_WORKSPACE_REFS;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_repo::{GixRepositoryExt, SignaturePurpose};
use gitbutler_repo::SignaturePurpose;
use gitbutler_repo::{LogUntil, RepositoryExt};
use gitbutler_stack::{Stack, VirtualBranchesHandle};
use tracing::instrument;
Expand Down
4 changes: 2 additions & 2 deletions crates/gitbutler-branch-actions/src/upstream_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use anyhow::{anyhow, bail, Result};
use gitbutler_cherry_pick::RepositoryExt;
use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt as _;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_repo::RepositoryExt as _;
use gitbutler_repo::{
rebase::{cherry_rebase_group, gitbutler_merge_commits},
GixRepositoryExt, LogUntil,
LogUntil,
};
use gitbutler_repo_actions::RepoActionsExt as _;
use gitbutler_stack::stack_context::StackContext;
Expand Down
6 changes: 4 additions & 2 deletions crates/gitbutler-branch-actions/src/virtual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ use gitbutler_commit::{commit_ext::CommitExt, commit_headers::HasCommitHeaders};
use gitbutler_diff::{trees, GitHunk, Hunk};
use gitbutler_error::error::Code;
use gitbutler_operating_modes::assure_open_workspace_mode;
use gitbutler_oxidize::{git2_signature_to_gix_signature, git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{
git2_signature_to_gix_signature, git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt,
};
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_reference::{normalize_branch_name, Refname, RemoteRefname};
use gitbutler_repo::{
rebase::{cherry_rebase, cherry_rebase_group},
GixRepositoryExt, LogUntil, RepositoryExt,
LogUntil, RepositoryExt,
};
use gitbutler_repo_actions::RepoActionsExt;
use gitbutler_stack::{
Expand Down
11 changes: 3 additions & 8 deletions crates/gitbutler-cherry-pick/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,13 @@ impl GixRepositoryExt for gix::Repository {
ConflictedTreeKey::Theirs,
)?;

use gitbutler_oxidize::GixRepositoryExt;
self.merge_trees(
base,
ours,
theirs,
gix::merge::blob::builtin_driver::text::Labels {
ancestor: Some("base".into()),
current: Some("ours".into()),
other: Some("theirs".into()),
},
self.tree_merge_options()?
.with_tree_favor(Some(gix::merge::tree::TreeFavor::Ours))
.with_file_favor(Some(gix::merge::tree::FileFavor::Ours)),
self.default_merge_labels(),
self.merge_options_force_ours()?,
)
.context("failed to merge trees for cherry pick")
}
Expand Down
6 changes: 4 additions & 2 deletions crates/gitbutler-oplog/src/oplog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ use anyhow::{anyhow, bail, Context, Result};
use git2::FileMode;
use gitbutler_command_context::RepositoryExtLite;
use gitbutler_diff::{hunks_by_filepath, FileDiff};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_time_to_git2, gix_to_git2_oid};
use gitbutler_oxidize::{
git2_to_gix_object_id, gix_time_to_git2, gix_to_git2_oid, GixRepositoryExt,
};
use gitbutler_project::{
access::{WorktreeReadPermission, WorktreeWritePermission},
Project,
};
use gitbutler_repo::RepositoryExt;
use gitbutler_repo::SignaturePurpose;
use gitbutler_repo::{GixRepositoryExt, RepositoryExt};
use gitbutler_stack::{Stack, VirtualBranchesHandle, VirtualBranchesState};
use gix::bstr::ByteSlice;
use gix::object::tree::diff::Change;
Expand Down
123 changes: 123 additions & 0 deletions crates/gitbutler-oxidize/src/ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use crate::git2_to_gix_object_id;
use anyhow::{Context, Result};
use gix::merge::tree::{Options, TreatAsUnresolved};

pub trait GixRepositoryExt: Sized {
/// Configure the repository for diff operations between trees.
/// This means it needs an object cache relative to the amount of files in the repository.
fn for_tree_diffing(self) -> Result<Self>;

/// Returns `true` if the merge between `our_tree` and `their_tree` is free of conflicts.
/// Conflicts entail content merges with conflict markers, or anything else that doesn't merge cleanly in the tree.
///
/// # Important
///
/// Make sure the repository is configured [`with_object_memory()`](gix::Repository::with_object_memory()).
fn merges_cleanly_compat(
&self,
ancestor_tree: git2::Oid,
our_tree: git2::Oid,
their_tree: git2::Oid,
) -> Result<bool>;

/// Just like the above, but with `gix` types.
fn merges_cleanly(
&self,
ancestor_tree: gix::ObjectId,
our_tree: gix::ObjectId,
their_tree: gix::ObjectId,
) -> Result<bool>;

/// Return default label names when merging trees.
///
/// Note that these should probably rather be branch names, but that's for another day.
fn default_merge_labels(&self) -> gix::merge::blob::builtin_driver::text::Labels<'static> {
gix::merge::blob::builtin_driver::text::Labels {
ancestor: Some("base".into()),
current: Some("ours".into()),
other: Some("theirs".into()),
}
}

/// Tree merge options that enforce undecidable conflicts to be forcefully resolved
/// to favor ours, both when dealing with content merges and with tree merges.
fn merge_options_force_ours(&self) -> Result<gix::merge::tree::Options>;

/// Return options suitable for merging so that the merge stops immediately after the first conflict.
/// It also returns the conflict kind to use when checking for unresolved conflicts.
fn merge_options_fail_fast(
&self,
) -> Result<(
gix::merge::tree::Options,
gix::merge::tree::TreatAsUnresolved,
)>;

/// Just like [`Self::merge_options_fail_fast()`], but additionally don't perform rename tracking.
/// This is useful if the merge result isn't going to be used, and we are only interested in knowing
/// if a merge would succeed.
fn merge_options_no_rewrites_fail_fast(
&self,
) -> Result<(gix::merge::tree::Options, TreatAsUnresolved)>;
}

impl GixRepositoryExt for gix::Repository {
fn for_tree_diffing(mut self) -> anyhow::Result<Self> {
let bytes = self.compute_object_cache_size_for_tree_diffs(&***self.index_or_empty()?);
self.object_cache_size_if_unset(bytes);
Ok(self)
}

fn merges_cleanly_compat(
&self,
ancestor_tree: git2::Oid,
our_tree: git2::Oid,
their_tree: git2::Oid,
) -> Result<bool> {
self.merges_cleanly(
git2_to_gix_object_id(ancestor_tree),
git2_to_gix_object_id(our_tree),
git2_to_gix_object_id(their_tree),
)
}

fn merges_cleanly(
&self,
ancestor_tree: gix::ObjectId,
our_tree: gix::ObjectId,
their_tree: gix::ObjectId,
) -> Result<bool> {
let (options, conflict_kind) = self.merge_options_no_rewrites_fail_fast()?;
let merge_outcome = self
.merge_trees(
ancestor_tree,
our_tree,
their_tree,
Default::default(),
options,
)
.context("failed to merge trees")?;
Ok(!merge_outcome.has_unresolved_conflicts(conflict_kind))
}

fn merge_options_force_ours(&self) -> Result<Options> {
Ok(self
.tree_merge_options()?
.with_tree_favor(Some(gix::merge::tree::TreeFavor::Ours))
.with_file_favor(Some(gix::merge::tree::FileFavor::Ours)))
}

fn merge_options_fail_fast(&self) -> Result<(gix::merge::tree::Options, TreatAsUnresolved)> {
let conflict_kind = TreatAsUnresolved::forced_resolution();
let options = self
.tree_merge_options()?
.with_fail_on_conflict(Some(conflict_kind));
Ok((options, conflict_kind))
}

fn merge_options_no_rewrites_fail_fast(
&self,
) -> Result<(gix::merge::tree::Options, TreatAsUnresolved)> {
let (options, conflict_kind) = self.merge_options_fail_fast()?;
Ok((options.with_rewrites(None), conflict_kind))
}
}
3 changes: 3 additions & 0 deletions crates/gitbutler-oxidize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use anyhow::Context;
use gix::bstr::ByteSlice;
use std::borrow::Borrow;

mod ext;
pub use ext::GixRepositoryExt;

pub fn gix_time_to_git2(time: gix::date::Time) -> git2::Time {
git2::Time::new(time.seconds, time.offset)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/gitbutler-repo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub use commands::{FileInfo, RepoCommands};
pub use remote::GitRemote;

mod repository_ext;
pub use repository_ext::{GixRepositoryExt, LogUntil, RepositoryExt};
pub use repository_ext::{LogUntil, RepositoryExt};

pub mod credentials;

Expand Down
13 changes: 3 additions & 10 deletions crates/gitbutler-repo/src/rebase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use gitbutler_commit::{
commit_ext::CommitExt,
commit_headers::{CommitHeadersV2, HasCommitHeaders},
};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid};
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt as _};
use serde::{Deserialize, Serialize};

/// cherry-pick based rebase, which handles empty commits
Expand Down Expand Up @@ -325,15 +325,8 @@ pub fn gitbutler_merge_commits<'repository>(
git2_to_gix_object_id(base_tree.id()),
git2_to_gix_object_id(incoming_merge_tree.id()),
git2_to_gix_object_id(target_merge_tree.id()),
gix::merge::blob::builtin_driver::text::Labels {
ancestor: Some("base".into()),
current: Some("ours".into()),
other: Some("theirs".into()),
},
gix_repo
.tree_merge_options()?
.with_tree_favor(Some(gix::merge::tree::TreeFavor::Ours))
.with_file_favor(Some(gix::merge::tree::FileFavor::Ours)),
gix_repo.default_merge_labels(),
gix_repo.merge_options_force_ours()?,
)?;
let merged_tree_id = merge_result.tree.write()?;

Expand Down
Loading

0 comments on commit 85bf792

Please sign in to comment.