From 37d3bf24ac1a79302f3e97b97372e4ad381c45e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BC=C3=9Fler?= Date: Wed, 2 Jul 2025 13:57:44 +0200 Subject: [PATCH 1/3] feat: add first debug version of `gix tag list` --- gitoxide-core/src/repository/mod.rs | 1 + gitoxide-core/src/repository/tag.rs | 17 +++++++++++++++++ src/plumbing/main.rs | 13 ++++++++++++- src/plumbing/options/mod.rs | 11 +++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 gitoxide-core/src/repository/tag.rs 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..7dc9e3d93d6 --- /dev/null +++ b/gitoxide-core/src/repository/tag.rs @@ -0,0 +1,17 @@ +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); + + let name = match tag_ref { + Ok(Ok(tag)) => tag.name.to_string(), + _ => reference.name().shorten().to_string(), + }; + + 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 { From a845a4b5b0579cd65f1e2f5c18a751329ff9504f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20R=C3=BC=C3=9Fler?= Date: Fri, 4 Jul 2025 12:15:55 +0200 Subject: [PATCH 2/3] Make output more verbose --- gitoxide-core/src/repository/tag.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/gitoxide-core/src/repository/tag.rs b/gitoxide-core/src/repository/tag.rs index 7dc9e3d93d6..4d51aed3c9e 100644 --- a/gitoxide-core/src/repository/tag.rs +++ b/gitoxide-core/src/repository/tag.rs @@ -5,12 +5,26 @@ pub fn list(repo: gix::Repository, out: &mut dyn std::io::Write) -> anyhow::Resu let tag = reference.peel_to_tag(); let tag_ref = tag.as_ref().map(gix::Tag::decode); - let name = match tag_ref { - Ok(Ok(tag)) => tag.name.to_string(), - _ => reference.name().shorten().to_string(), - }; + // `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(); - writeln!(out, "{name}")?; + 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(()) From 750ae9bc3cf72c1d9a358307e423523324eb25fb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 6 Jul 2025 15:54:53 +0200 Subject: [PATCH 3/3] refactor - add alias - support `tags` as alias, invoked without explicit `list` - always put annotated tag information into `[]`, despite being more noisy. --- gitoxide-core/src/repository/tag.rs | 26 ++++++++++++++------------ src/plumbing/main.rs | 4 ++-- src/plumbing/options/mod.rs | 10 ++++++++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/gitoxide-core/src/repository/tag.rs b/gitoxide-core/src/repository/tag.rs index 4d51aed3c9e..2bc109020e5 100644 --- a/gitoxide-core/src/repository/tag.rs +++ b/gitoxide-core/src/repository/tag.rs @@ -1,25 +1,27 @@ 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() { + 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. + // `name` is the name of the file in `refs/tags/`. + // This applies to both lightweight and annotated tags. let name = reference.name().shorten(); - + let mut fields = Vec::new(); 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)?; + // `tag_name` is the name provided by the user via `git tag -a/-s/-u`. + // It is only present for annotated tags. + fields.push(format!( + "tag name: {}", + if name == tag_ref.name { "*".into() } else { tag_ref.name } + )); + if tag_ref.pgp_signature.is_some() { + fields.push("signed".into()); } + + writeln!(out, "{name} [{fields}]", fields = fields.join(", "))?; } _ => { writeln!(out, "{name}")?; diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 00aea889375..12f2e5e7733 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -1304,8 +1304,8 @@ pub fn main() -> Result<()> { }, ), }, - Subcommands::Tag(cmd) => match cmd { - tag::Subcommands::List => prepare_and_run( + Subcommands::Tag(platform) => match platform.cmds { + Some(tag::Subcommands::List) | None => prepare_and_run( "tag-list", trace, auto_verbose, diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 5b982599d81..33f636b323b 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -101,8 +101,8 @@ pub enum Subcommands { #[clap(subcommand)] Commit(commit::Subcommands), /// Interact with tag objects. - #[clap(subcommand)] - Tag(tag::Subcommands), + #[clap(visible_alias = "tags")] + Tag(tag::Platform), /// Verify the integrity of the entire repository Verify { #[clap(flatten)] @@ -932,6 +932,12 @@ pub mod commit { } pub mod tag { + #[derive(Debug, clap::Parser)] + pub struct Platform { + #[clap(subcommand)] + pub cmds: Option, + } + #[derive(Debug, clap::Subcommand)] pub enum Subcommands { /// List all tags.