From e973dfeaf17ca63385496202e9fdcdd912e20f42 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 31 Oct 2022 16:56:41 +0100 Subject: [PATCH] feat: `gix remote ref-map --show-unmapped-remote-refs`. (#450) That way it's more obvious to see what was filtered out by ref-specs. It's also great to validate that server-side filtering via ref-prefix will not send refs that are referred to by symbolic refs that are not filtered out. That should be fine as it's all about objects, it's just something to deal with as we may have to deal with symbolic refs that aren't in the set of refs the server sent to us. --- gitoxide-core/src/repository/fetch.rs | 10 ++++++- gitoxide-core/src/repository/remote.rs | 41 ++++++++++++++++++++++---- src/plumbing/main.rs | 10 +++++-- src/plumbing/options/mod.rs | 3 ++ 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/gitoxide-core/src/repository/fetch.rs b/gitoxide-core/src/repository/fetch.rs index c9ff1f1ce8b..9775e3bd945 100644 --- a/gitoxide-core/src/repository/fetch.rs +++ b/gitoxide-core/src/repository/fetch.rs @@ -61,7 +61,15 @@ pub(crate) mod function { let ref_specs = remote.refspecs(git::remote::Direction::Fetch); match res.status { Status::NoChange => { - crate::repository::remote::refs::print_refmap(&repo, ref_specs, res.ref_map, &mut out, err) + let show_unmapped = false; + crate::repository::remote::refs::print_refmap( + &repo, + ref_specs, + res.ref_map, + show_unmapped, + &mut out, + err, + ) } Status::DryRun { update_refs } => print_updates(&repo, update_refs, ref_specs, res.ref_map, &mut out, err), Status::Change { diff --git a/gitoxide-core/src/repository/remote.rs b/gitoxide-core/src/repository/remote.rs index 2543b6103e7..7f11a0808c0 100644 --- a/gitoxide-core/src/repository/remote.rs +++ b/gitoxide-core/src/repository/remote.rs @@ -2,6 +2,7 @@ mod refs_impl { use anyhow::bail; use git_repository as git; + use git_repository::remote::fetch::Source; use git_repository::{ protocol::fetch, refspec::{match_group::validate::Fix, RefSpec}, @@ -19,7 +20,10 @@ mod refs_impl { pub enum Kind { Remote, - Tracking { ref_specs: Vec }, + Tracking { + ref_specs: Vec, + show_unmapped_remote_refs: bool, + }, } pub struct Options { @@ -46,14 +50,21 @@ mod refs_impl { ) -> anyhow::Result<()> { use anyhow::Context; let mut remote = by_name_or_url(&repo, name_or_url.as_deref())?; - if let refs::Kind::Tracking { ref_specs, .. } = &kind { + let show_unmapped = if let refs::Kind::Tracking { + ref_specs, + show_unmapped_remote_refs, + } = &kind + { if format != OutputFormat::Human { bail!("JSON output isn't yet supported for listing ref-mappings."); } if !ref_specs.is_empty() { remote.replace_refspecs(ref_specs.iter(), git::remote::Direction::Fetch)?; } - } + *show_unmapped_remote_refs + } else { + false + }; progress.info(format!( "Connecting to {:?}", remote @@ -75,9 +86,14 @@ mod refs_impl { writeln!(out, "\t{:?}", map.handshake)?; } match kind { - refs::Kind::Tracking { .. } => { - print_refmap(&repo, remote.refspecs(git::remote::Direction::Fetch), map, out, err) - } + refs::Kind::Tracking { .. } => print_refmap( + &repo, + remote.refspecs(git::remote::Direction::Fetch), + map, + show_unmapped, + out, + err, + ), refs::Kind::Remote => { match format { OutputFormat::Human => drop(print(out, &map.remote_refs)), @@ -96,6 +112,7 @@ mod refs_impl { repo: &git::Repository, refspecs: &[RefSpec], mut map: git::remote::fetch::RefMap, + show_unmapped_remotes: bool, mut out: impl std::io::Write, mut err: impl std::io::Write, ) -> anyhow::Result<()> { @@ -169,6 +186,18 @@ mod refs_impl { map.remote_refs.len() - map.mappings.len(), refspecs.len() )?; + if show_unmapped_remotes { + writeln!(&mut out, "\nFiltered: ")?; + for remote_ref in map.remote_refs.iter().filter(|r| { + !map.mappings.iter().any(|m| match &m.remote { + Source::Ref(other) => other == *r, + Source::ObjectId(_) => false, + }) + }) { + print_ref(&mut out, remote_ref)?; + writeln!(&mut out)?; + } + } } if refspecs.is_empty() { bail!("Without ref-specs there is nothing to show here. Add ref-specs as arguments or configure them in git-config.") diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 13a6ded3b3f..24633d306c2 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -178,9 +178,13 @@ pub fn main() -> Result<()> { remote::Subcommands::Refs | remote::Subcommands::RefMap { .. } => { let kind = match cmd { remote::Subcommands::Refs => core::repository::remote::refs::Kind::Remote, - remote::Subcommands::RefMap { ref_spec } => { - core::repository::remote::refs::Kind::Tracking { ref_specs: ref_spec } - } + remote::Subcommands::RefMap { + ref_spec, + show_unmapped_remote_refs, + } => core::repository::remote::refs::Kind::Tracking { + ref_specs: ref_spec, + show_unmapped_remote_refs, + }, }; let context = core::repository::remote::refs::Options { name_or_url: name, diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 40193ff9198..a0971cc40eb 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -195,6 +195,9 @@ pub mod remote { Refs, /// Print all references available on the remote as filtered through ref-specs. RefMap { + /// Also display remote references that were sent by the server, but filtered by the refspec locally. + #[clap(long, short = 'u')] + show_unmapped_remote_refs: bool, /// Override the built-in and configured ref-specs with one or more of the given ones. #[clap(parse(try_from_os_str = git::env::os_str_to_bstring))] ref_spec: Vec,