Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 54 additions & 45 deletions crates/but-core/src/repo_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ pub trait RepositoryExt: Sized {
/// This means it needs an object cache relative to the amount of files in the repository.
fn for_tree_diffing(self) -> anyhow::Result<Self>;

/// Return a repository configured for commit shortening,
/// i.e. with an object database configured to *not* check for new packs.
fn for_commit_shortening(self) -> Self;

Comment thread
Byron marked this conversation as resolved.
/// Just like the above, but with `gix` types.
fn merges_cleanly(
&self,
Expand Down Expand Up @@ -97,40 +101,16 @@ pub trait RepositoryExt: Sized {
}

impl RepositoryExt for gix::Repository {
fn cherry_pick_commits_to_tree(
&self,
new_base_commit_id: gix::ObjectId,
to_rebase_commit_id: gix::ObjectId,
merge_options: gix::merge::tree::Options,
) -> anyhow::Result<gix::merge::tree::Outcome<'_>> {
// TODO: more tests for the handling of conlicting commits in particular
let to_rebase_commit = crate::Commit::from_id(to_rebase_commit_id.attach(self))?;
// If the commit we are picking is conflicted then we want to use the
// original base that was used when it was first cherry-picked.
//
// If it is not conflicted, then we use the first parent as the base.
let base = if to_rebase_commit.is_conflicted() {
match to_rebase_commit.inner.parents.first() {
None => gix::ObjectId::empty_tree(self.object_hash()),
Some(parent_commit) => crate::Commit::from_id(parent_commit.attach(self))?
.tree_id_or_auto_resolution()?
.detach(),
}
} else {
to_rebase_commit.tree_id_or_kind(TreeKind::Base)?.detach()
};
let ours = crate::Commit::from_id(new_base_commit_id.attach(self))?
.tree_id_or_auto_resolution()?;
let theirs = to_rebase_commit.tree_id_or_kind(TreeKind::Theirs)?;
fn git_settings(&self) -> anyhow::Result<GitConfigSettings> {
GitConfigSettings::try_from_snapshot(&self.config_snapshot())
}

self.merge_trees(
base, /* the tree of the parent of the commit to cherry-pick */
ours, /* the new base to cherry-pick onto */
theirs, /* the tree of the commit to cherry-pick */
self.default_merge_labels(),
merge_options,
)
.context("failed to merge trees for cherry pick")
fn gitbutler_storage_path(&self) -> anyhow::Result<PathBuf> {
but_project_handle::gitbutler_storage_path(self)
}

fn set_git_settings(&self, settings: &GitConfigSettings) -> anyhow::Result<()> {
settings.persist_to_local_config(self)
}

fn commit_signatures(&self) -> anyhow::Result<(gix::actor::Signature, gix::actor::Signature)> {
Expand All @@ -156,18 +136,6 @@ impl RepositoryExt for gix::Repository {
Ok((author.into(), committer))
}

fn git_settings(&self) -> anyhow::Result<GitConfigSettings> {
GitConfigSettings::try_from_snapshot(&self.config_snapshot())
}

fn gitbutler_storage_path(&self) -> anyhow::Result<PathBuf> {
but_project_handle::gitbutler_storage_path(self)
}

fn set_git_settings(&self, settings: &GitConfigSettings) -> anyhow::Result<()> {
settings.persist_to_local_config(self)
}

fn local_common_config_for_editing(&self) -> anyhow::Result<gix::config::File<'static>> {
let local_config_path = self.common_dir().join("config");
let config = gix::config::File::from_path_no_includes(
Expand Down Expand Up @@ -199,12 +167,53 @@ impl RepositoryExt for gix::Repository {
Ok(())
}

fn cherry_pick_commits_to_tree(
&self,
new_base_commit_id: gix::ObjectId,
to_rebase_commit_id: gix::ObjectId,
merge_options: gix::merge::tree::Options,
) -> anyhow::Result<gix::merge::tree::Outcome<'_>> {
// TODO: more tests for the handling of conlicting commits in particular
let to_rebase_commit = crate::Commit::from_id(to_rebase_commit_id.attach(self))?;
// If the commit we are picking is conflicted then we want to use the
// original base that was used when it was first cherry-picked.
//
// If it is not conflicted, then we use the first parent as the base.
let base = if to_rebase_commit.is_conflicted() {
match to_rebase_commit.inner.parents.first() {
None => gix::ObjectId::empty_tree(self.object_hash()),
Some(parent_commit) => crate::Commit::from_id(parent_commit.attach(self))?
.tree_id_or_auto_resolution()?
.detach(),
}
} else {
to_rebase_commit.tree_id_or_kind(TreeKind::Base)?.detach()
};
let ours = crate::Commit::from_id(new_base_commit_id.attach(self))?
.tree_id_or_auto_resolution()?;
let theirs = to_rebase_commit.tree_id_or_kind(TreeKind::Theirs)?;

self.merge_trees(
base, /* the tree of the parent of the commit to cherry-pick */
ours, /* the new base to cherry-pick onto */
theirs, /* the tree of the commit to cherry-pick */
self.default_merge_labels(),
merge_options,
)
.context("failed to merge trees for cherry pick")
}

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 for_commit_shortening(mut self) -> Self {
self.objects.refresh = gix::odb::store::RefreshMode::Never;
self
}

fn merges_cleanly(
&self,
ancestor_tree: gix::ObjectId,
Expand Down
12 changes: 8 additions & 4 deletions crates/but/src/command/legacy/absorb.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::Path;

use but_core::sync::RepoExclusiveGuard;
use but_core::{RepositoryExt, sync::RepoExclusiveGuard};
use but_ctx::Context;
use but_hunk_assignment::{
AbsorptionTarget, CommitAbsorption, HunkAssignment, JsonAbsorbOutput, JsonCommitAbsorption,
Expand All @@ -16,7 +16,7 @@ use itertools::Itertools;
use crate::{
CliId, IdMap,
id::{UncommittedCliId, parser::parse_sources},
utils::OutputChannel,
utils::{OutputChannel, shorten_object_id},
};
/// Amends changes into the appropriate commits where they belong.
///
Expand Down Expand Up @@ -79,7 +79,10 @@ pub(crate) fn handle(
// Display the plan (in JSON mode for non-dry-run, collect without writing — we'll
// combine it with the result in absorb_assignments to avoid a double-write that
// would overwrite the plan in the JSON buffer).
let plan_json = display_absorption_plan(&absorption_plan, out, new, dry_run)?;
let plan_json = {
let repo = ctx.repo.get()?.clone().for_commit_shortening();
display_absorption_plan(&absorption_plan, &repo, out, new, dry_run)?
};

if dry_run {
// Nothing more to do
Expand Down Expand Up @@ -206,6 +209,7 @@ fn get_hunk_ranges(assignment: &HunkAssignment) -> Vec<String> {
/// in a single JSON write — avoiding a double-write that would overwrite the buffer.
fn display_absorption_plan(
commit_absorptions: &[CommitAbsorption],
repo: &gix::Repository,
out: &mut OutputChannel,
new: bool,
write_json: bool,
Expand Down Expand Up @@ -277,7 +281,7 @@ fn display_absorption_plan(
writeln!(out)?;

for absorption in commit_absorptions {
let short_hash = &absorption.commit_id.to_hex().to_string()[..7];
let short_hash = shorten_object_id(repo, absorption.commit_id);
let verb = if new {
"Created on top of commit"
} else {
Expand Down
24 changes: 14 additions & 10 deletions crates/but/src/command/legacy/branch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use colored::Colorize;
use crate::{
CliId, IdMap,
args::branch,
utils::{Confirm, ConfirmDefault, OutputChannel},
utils::{Confirm, ConfirmDefault, OutputChannel, shorten_object_id},
};

pub mod apply;
Expand Down Expand Up @@ -117,15 +117,19 @@ pub fn handle(
None
};

let anchor_display = anchor.as_ref().map(|anchor_ref| match anchor_ref {
but_api::legacy::stack::create_reference::Anchor::AtReference {
short_name,
..
} => short_name.clone(),
but_api::legacy::stack::create_reference::Anchor::AtCommit {
commit_id, ..
} => commit_id.to_string()[..7].to_string(),
});
let anchor_display = {
let repo = ctx.repo.get()?;
anchor.as_ref().map(|anchor_ref| match anchor_ref {
but_api::legacy::stack::create_reference::Anchor::AtReference {
short_name,
..
} => short_name.clone(),
but_api::legacy::stack::create_reference::Anchor::AtCommit {
commit_id,
..
} => shorten_object_id(&repo, commit_id.0),
})
};

but_api::legacy::stack::create_reference(
ctx,
Expand Down
10 changes: 5 additions & 5 deletions crates/but/src/command/legacy/branch/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use but_oxidize::{ObjectIdExt, OidExt};
use colored::Colorize;
use tracing::instrument;

use crate::utils::OutputChannel;
use crate::utils::{OutputChannel, shorten_object_id};

#[allow(clippy::too_many_arguments)]
pub fn show(
Expand Down Expand Up @@ -238,15 +238,15 @@ fn get_merge_conflict_paths(

fn find_commits_modifying_file(
git2_repo: &git2::Repository,
gix_repo: &gix::Repository,
repo: &gix::Repository,
path: &str,
from_commit: gix::ObjectId,
to_commit: gix::ObjectId,
) -> Result<Vec<CommitRef>, anyhow::Error> {
use gix::prelude::ObjectIdExt as _;

let traversal = to_commit
.attach(gix_repo)
.attach(repo)
.ancestors()
.with_hidden(Some(from_commit))
.all()?;
Expand Down Expand Up @@ -289,7 +289,7 @@ fn find_commits_modifying_file(
let author = commit.author();
commits.push(CommitRef {
sha: oid.to_string(),
short_sha: oid.to_string()[..7].to_string(),
short_sha: shorten_object_id(repo, info.id),
message: commit
.message()
.unwrap_or("(no message)")
Expand Down Expand Up @@ -430,7 +430,7 @@ fn get_commits_ahead(

commits.push(CommitInfo {
sha: oid.to_string(),
short_sha: oid.to_string()[..7].to_string(),
short_sha: shorten_object_id(&gix_repo, info.id),
message: commit
.message()
.unwrap_or("(no message)")
Expand Down
12 changes: 6 additions & 6 deletions crates/but/src/command/legacy/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
CliId, IdMap,
command::legacy::status::assignment::{CLIHunkAssignment, FileAssignment},
tui,
utils::{InputOutputChannel, OutputChannel},
utils::{InputOutputChannel, OutputChannel, shorten_object_id},
};

pub(crate) fn insert_blank_commit(
Expand Down Expand Up @@ -54,16 +54,16 @@ pub(crate) fn insert_blank_commit(
// Determine target commit ID and use provided insert_side
let success_message = match cli_id {
CliId::Commit { commit_id: oid, .. } => {
let short_oid = {
let repo = ctx.repo.get()?;
shorten_object_id(&repo, *oid)
};
commit_insert_blank(
ctx,
but_api::commit::ui::RelativeTo::Commit(*oid),
insert_side,
)?;
format!(
"Created blank commit {} commit {}",
position_desc,
&oid.to_string()[..7]
)
format!("Created blank commit {position_desc} commit {short_oid}")
}
CliId::Branch { name, .. } => {
let reference = {
Expand Down
9 changes: 6 additions & 3 deletions crates/but/src/command/legacy/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use anyhow::bail;
use but_ctx::Context;
use colored::Colorize;

use crate::{CliId, IdMap, utils::OutputChannel};
use crate::{
CliId, IdMap,
utils::{OutputChannel, shorten_object_id},
};

pub async fn handle(
ctx: &mut Context,
Expand Down Expand Up @@ -70,9 +73,9 @@ pub async fn handle(
progress,
"Merging {} ({}) into {} ({})",
branch_name.bright_cyan(),
merge_in_branch_head_oid.to_string()[..7].bright_black(),
shorten_object_id(&repo, merge_in_branch_head_oid).bright_black(),
local_branch_name.bright_cyan(),
local_branch_head_oid.to_string()[..7].bright_black()
shorten_object_id(&repo, local_branch_head_oid).bright_black()
)?;

// do the merge
Expand Down
Loading
Loading