Skip to content

Commit 8cea69a

Browse files
committed
feat: gix merge-base for the CLI
For now it only supports the standard merge-base, but more derivatives can be added easily on demand.
1 parent 15b938a commit 8cea69a

File tree

5 files changed

+61
-6
lines changed

5 files changed

+61
-6
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use crate::OutputFormat;
2+
use anyhow::bail;
3+
4+
pub fn merge_base(
5+
mut repo: gix::Repository,
6+
first: String,
7+
others: Vec<String>,
8+
mut out: impl std::io::Write,
9+
format: OutputFormat,
10+
) -> anyhow::Result<()> {
11+
if format != OutputFormat::Human {
12+
bail!("Only 'human' format is currently supported");
13+
}
14+
repo.object_cache_size_if_unset(50 * 1024 * 1024);
15+
let first_id = repo.rev_parse_single(first.as_str())?;
16+
let other_ids: Vec<_> = others
17+
.iter()
18+
.cloned()
19+
.map(|other| repo.rev_parse_single(other.as_str()).map(gix::Id::detach))
20+
.collect::<Result<_, _>>()?;
21+
22+
let cache = repo.commit_graph_if_enabled()?;
23+
let bases = repo.merge_bases_many_with_cache(first_id, &other_ids, cache.as_ref())?;
24+
if bases.is_empty() {
25+
bail!("No base found for {first} and {others}", others = others.join(", "))
26+
}
27+
for id in bases {
28+
writeln!(&mut out, "{id}")?;
29+
}
30+
Ok(())
31+
}

gitoxide-core/src/repository/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ mod fsck;
4444
pub use fsck::function as fsck;
4545
pub mod index;
4646
pub mod mailmap;
47+
mod merge_base;
48+
pub use merge_base::merge_base;
4749
pub mod odb;
4850
pub mod remote;
4951
pub mod revision;

gix/src/repository/revision.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ impl crate::Repository {
5151
let two = two.into();
5252
let cache = self.commit_graph_if_enabled()?;
5353
let mut graph = self.revision_graph(cache.as_ref());
54-
let bases =
55-
gix_revision::merge_base(one, &vec![two], &mut graph)?.ok_or(super::merge_base::Error::NotFound {
56-
first: one,
57-
second: two,
58-
})?;
54+
let bases = gix_revision::merge_base(one, &[two], &mut graph)?.ok_or(super::merge_base::Error::NotFound {
55+
first: one,
56+
second: two,
57+
})?;
5958
Ok(bases[0].attach(self))
6059
}
6160

@@ -74,7 +73,7 @@ impl crate::Repository {
7473
let one = one.into();
7574
let two = two.into();
7675
let mut graph = self.revision_graph(cache);
77-
let bases = gix_revision::merge_base(one, &vec![two], &mut graph)?.ok_or(
76+
let bases = gix_revision::merge_base(one, &[two], &mut graph)?.ok_or(
7877
super::merge_base_with_cache::Error::NotFound {
7978
first: one,
8079
second: two,

src/plumbing/main.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ pub fn main() -> Result<()> {
141141
}
142142

143143
match cmd {
144+
Subcommands::MergeBase(crate::plumbing::options::merge_base::Command { first, others }) => prepare_and_run(
145+
"merge-base",
146+
trace,
147+
verbose,
148+
progress,
149+
progress_keep_open,
150+
None,
151+
move |_progress, out, _err| {
152+
core::repository::merge_base(repository(Mode::Lenient)?, first, others, out, format)
153+
},
154+
),
144155
Subcommands::Worktree(crate::plumbing::options::worktree::Platform { cmd }) => match cmd {
145156
crate::plumbing::options::worktree::SubCommands::List => prepare_and_run(
146157
"worktree-list",

src/plumbing/options/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ pub enum Subcommands {
138138
Config(config::Platform),
139139
#[cfg(feature = "gitoxide-core-tools-corpus")]
140140
Corpus(corpus::Platform),
141+
MergeBase(merge_base::Command),
141142
Worktree(worktree::Platform),
142143
/// Subcommands that need no git repository to run.
143144
#[clap(subcommand)]
@@ -268,6 +269,17 @@ pub mod status {
268269
}
269270
}
270271

272+
pub mod merge_base {
273+
#[derive(Debug, clap::Parser)]
274+
#[command(about = "A command for calculating all merge-bases")]
275+
pub struct Command {
276+
/// A revspec for the first commit.
277+
pub first: String,
278+
/// Revspecs for the other commits to compute the merge-base with.
279+
pub others: Vec<String>,
280+
}
281+
}
282+
271283
pub mod worktree {
272284
#[derive(Debug, clap::Parser)]
273285
#[command(about = "Commands for handling worktrees")]

0 commit comments

Comments
 (0)