diff --git a/gitoxide-core/src/repository/mod.rs b/gitoxide-core/src/repository/mod.rs index 8158f7cf0b6..bf3f5fe0e6d 100644 --- a/gitoxide-core/src/repository/mod.rs +++ b/gitoxide-core/src/repository/mod.rs @@ -44,6 +44,7 @@ pub mod remote; pub mod revision; pub mod status; pub mod submodule; +pub mod tag; pub mod tree; pub mod verify; pub mod worktree; diff --git a/gitoxide-core/src/repository/tag.rs b/gitoxide-core/src/repository/tag.rs new file mode 100644 index 00000000000..4d51aed3c9e --- /dev/null +++ b/gitoxide-core/src/repository/tag.rs @@ -0,0 +1,31 @@ +pub fn list(repo: gix::Repository, out: &mut dyn std::io::Write) -> anyhow::Result<()> { + let platform = repo.references()?; + + for mut reference in (platform.tags()?).flatten() { + let tag = reference.peel_to_tag(); + let tag_ref = tag.as_ref().map(gix::Tag::decode); + + // `name` is the name of the file in `refs/tags/`. This applies to both lightweight as well + // as annotated tags. + let name = reference.name().shorten(); + + match tag_ref { + Ok(Ok(tag_ref)) => { + // `tag_name` is the name provided by the user via `git tag -a/-s/-u`. It is only + // present for annotated tags. + let tag_name = tag_ref.name; + + if name == tag_name { + writeln!(out, "{name} *")?; + } else { + writeln!(out, "{name} [tag name: {}]", tag_ref.name)?; + } + } + _ => { + writeln!(out, "{name}")?; + } + } + } + + Ok(()) +} diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 3a81447d701..00aea889375 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -17,7 +17,7 @@ use crate::{ plumbing::{ options::{ attributes, commit, commitgraph, config, credential, exclude, free, fsck, index, mailmap, merge, odb, - revision, tree, Args, Subcommands, + revision, tag, tree, Args, Subcommands, }, show_progress, }, @@ -1304,6 +1304,17 @@ pub fn main() -> Result<()> { }, ), }, + Subcommands::Tag(cmd) => match cmd { + tag::Subcommands::List => prepare_and_run( + "tag-list", + trace, + auto_verbose, + progress, + progress_keep_open, + None, + move |_progress, out, _err| core::repository::tag::list(repository(Mode::Lenient)?, out), + ), + }, Subcommands::Tree(cmd) => match cmd { tree::Subcommands::Entries { treeish, diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index ae1ea443551..5b982599d81 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -100,6 +100,9 @@ pub enum Subcommands { /// Interact with commit objects. #[clap(subcommand)] Commit(commit::Subcommands), + /// Interact with tag objects. + #[clap(subcommand)] + Tag(tag::Subcommands), /// Verify the integrity of the entire repository Verify { #[clap(flatten)] @@ -928,6 +931,14 @@ pub mod commit { } } +pub mod tag { + #[derive(Debug, clap::Subcommand)] + pub enum Subcommands { + /// List all tags. + List, + } +} + pub mod credential { #[derive(Debug, clap::Subcommand)] pub enum Subcommands {