diff --git a/gitoxide-core/src/repository/branch.rs b/gitoxide-core/src/repository/branch.rs new file mode 100644 index 00000000000..a9fe9b2afa0 --- /dev/null +++ b/gitoxide-core/src/repository/branch.rs @@ -0,0 +1,60 @@ +use crate::OutputFormat; + +pub mod list { + pub enum Kind { + Local, + All, + } + + pub struct Options { + pub kind: Kind, + } +} + +pub fn list( + repo: gix::Repository, + out: &mut dyn std::io::Write, + format: OutputFormat, + options: list::Options, +) -> anyhow::Result<()> { + if format != OutputFormat::Human { + anyhow::bail!("JSON output isn't supported"); + } + + let platform = repo.references()?; + + let (show_local, show_remotes) = match options.kind { + list::Kind::Local => (true, false), + list::Kind::All => (true, true), + }; + + if show_local { + let mut branch_names: Vec = platform + .local_branches()? + .flatten() + .map(|branch| branch.name().shorten().to_string()) + .collect(); + + branch_names.sort(); + + for branch_name in branch_names { + writeln!(out, "{branch_name}")?; + } + } + + if show_remotes { + let mut branch_names: Vec = platform + .remote_branches()? + .flatten() + .map(|branch| branch.name().shorten().to_string()) + .collect(); + + branch_names.sort(); + + for branch_name in branch_names { + writeln!(out, "{branch_name}")?; + } + } + + Ok(()) +} diff --git a/gitoxide-core/src/repository/mod.rs b/gitoxide-core/src/repository/mod.rs index bf3f5fe0e6d..53161d5696c 100644 --- a/gitoxide-core/src/repository/mod.rs +++ b/gitoxide-core/src/repository/mod.rs @@ -6,6 +6,7 @@ use gix::bstr::BString; #[cfg(feature = "archive")] pub mod archive; +pub mod branch; pub mod cat; pub use cat::function::cat; pub mod blame; diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 24148035056..1d0bb96343c 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -16,8 +16,8 @@ use gix::bstr::{io::BufReadExt, BString}; use crate::{ plumbing::{ options::{ - attributes, commit, commitgraph, config, credential, exclude, free, fsck, index, mailmap, merge, odb, - revision, tag, tree, Args, Subcommands, + attributes, branch, commit, commitgraph, config, credential, exclude, free, fsck, index, mailmap, merge, + odb, revision, tag, tree, Args, Subcommands, }, show_progress, }, @@ -509,6 +509,26 @@ pub fn main() -> Result<()> { ) }, ), + Subcommands::Branch(platform) => match platform.cmd { + branch::Subcommands::List { all } => { + use core::repository::branch::list; + + let kind = if all { list::Kind::All } else { list::Kind::Local }; + let options = list::Options { kind }; + + prepare_and_run( + "branch-list", + trace, + auto_verbose, + progress, + progress_keep_open, + None, + move |_progress, out, _err| { + core::repository::branch::list(repository(Mode::Lenient)?, out, format, options) + }, + ) + } + }, #[cfg(feature = "gitoxide-core-tools-corpus")] Subcommands::Corpus(crate::plumbing::options::corpus::Platform { db, path, cmd }) => { let reverse_trace_lines = progress; diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 33f636b323b..597c7b7aaea 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -83,6 +83,9 @@ pub enum Subcommands { /// Subcommands for creating worktree archives. #[cfg(feature = "gitoxide-core-tools-archive")] Archive(archive::Platform), + /// Interact with branches. + #[clap(visible_alias = "branches")] + Branch(branch::Platform), /// Remove untracked files from the working tree. #[cfg(feature = "gitoxide-core-tools-clean")] Clean(clean::Command), @@ -236,6 +239,24 @@ pub mod archive { } } +pub mod branch { + #[derive(Debug, clap::Parser)] + pub struct Platform { + #[clap(subcommand)] + pub cmd: Subcommands, + } + + #[derive(Debug, clap::Subcommand)] + pub enum Subcommands { + /// List branches. + List { + /// List remote-tracking as well as local branches. + #[clap(long, short = 'a')] + all: bool, + }, + } +} + pub mod status { use gix::bstr::BString; diff --git a/tests/it/src/commands/blame_copy_royal.rs b/tests/it/src/commands/blame_copy_royal.rs index 75a31bd90e2..6eaa2e51e09 100644 --- a/tests/it/src/commands/blame_copy_royal.rs +++ b/tests/it/src/commands/blame_copy_royal.rs @@ -217,7 +217,7 @@ git commit -m {commit_id} // history’s root being the last element. We reverse the order in place so that all // methods can rely on the assumption that the root comes first, followed by its // descendants. That way, we can use a simple `for` loop to iterate through - // `self.blame_path` below. + // `self.blame_infos` below. self.blame_infos.reverse(); for blame_path_entry in self.blame_infos.clone() {