git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Jacob Keller <jacob.keller@gmail.com>
To: git@vger.kernel.org
Cc: Junio C Hamano <gitster@pobox.com>, Taylor Blau <me@ttaylorr.com>,
	Jacob Keller <jacob.e.keller@intel.com>,
	Pavel Rappo <pavel.rappo@gmail.com>
Subject: [PATCH v2 5/5] remote: handle negative refspecs in git remote show
Date: Thu, 16 Jun 2022 13:54:56 -0700	[thread overview]
Message-ID: <20220616205456.19081-6-jacob.e.keller@intel.com> (raw)
In-Reply-To: <20220616205456.19081-1-jacob.e.keller@intel.com>

By default, the git remote show command will query data from remotes to
show data about what might be done on a future git fetch. This process
currently does not handle negative refspecs. This can be confusing,
because the show command will list refs as if they would be fetched. For
example if the fetch refspec "^refs/heads/pr/*", it still displays the
following:

  * remote jdk19
    Fetch URL: git@github.com:openjdk/jdk19.git
    Push  URL: git@github.com:openjdk/jdk19.git
    HEAD branch: master
    Remote branches:
      master tracked
      pr/1   new (next fetch will store in remotes/jdk19)
      pr/2   new (next fetch will store in remotes/jdk19)
      pr/3   new (next fetch will store in remotes/jdk19)
    Local ref configured for 'git push':
      master pushes to master (fast-forwardable)

Fix this by adding an additional check inside of get_ref_states. Before
adding the ref name to the new_refs list, use omit_name_by_refspec to
see if the ref matches any negative refspecs. This change results in the
following output for git remote show:

  * remote jdk19
    Fetch URL: git@github.com:openjdk/jdk19.git
    Push  URL: git@github.com:openjdk/jdk19.git
    HEAD branch: master
    Remote branches:
      master tracked
      pr/1   skipped
      pr/2   skipped
      pr/3   skipped
    Local ref configured for 'git push':
      master pushes to master (fast-forwardable)

By showing the refs as skipped, it helps clarify that these references
won't actually be fetched. Alternatively, we could simply remove them
entirely.

Add a new test case to cover this functionality.

Reported-by: Pavel Rappo <pavel.rappo@gmail.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 builtin/remote.c  | 17 +++++++++++++----
 remote.c          |  2 +-
 remote.h          |  6 ++++++
 t/t5505-remote.sh | 22 ++++++++++++++++++++++
 4 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index d4b69fe77898..8d88c21e2e95 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -344,12 +344,13 @@ static void read_branches(void)
 
 struct ref_states {
 	struct remote *remote;
-	struct string_list new_refs, stale, tracked, heads, push;
+	struct string_list new_refs, skipped, stale, tracked, heads, push;
 	int queried;
 };
 
 #define REF_STATES_INIT { \
 	.new_refs = STRING_LIST_INIT_DUP, \
+	.skipped = STRING_LIST_INIT_DUP, \
 	.stale = STRING_LIST_INIT_DUP, \
 	.tracked = STRING_LIST_INIT_DUP, \
 	.heads = STRING_LIST_INIT_DUP, \
@@ -368,10 +369,13 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 				states->remote->fetch.raw[i]);
 
 	for (ref = fetch_map; ref; ref = ref->next) {
-		if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))
+		if (omit_name_by_refspec(ref->name, &states->remote->fetch)) {
+			string_list_append(&states->skipped, abbrev_branch(ref->name));
+		} else if (!ref->peer_ref || !ref_exists(ref->peer_ref->name)) {
 			string_list_append(&states->new_refs, abbrev_branch(ref->name));
-		else
+		} else {
 			string_list_append(&states->tracked, abbrev_branch(ref->name));
+		}
 	}
 	stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
 	for (ref = stale_refs; ref; ref = ref->next) {
@@ -383,6 +387,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 	free_refs(fetch_map);
 
 	string_list_sort(&states->new_refs);
+	string_list_sort(&states->skipped);
 	string_list_sort(&states->tracked);
 	string_list_sort(&states->stale);
 
@@ -941,6 +946,7 @@ static void clear_push_info(void *util, const char *string)
 static void free_remote_ref_states(struct ref_states *states)
 {
 	string_list_clear(&states->new_refs, 0);
+	string_list_clear(&states->skipped, 0);
 	string_list_clear(&states->stale, 1);
 	string_list_clear(&states->tracked, 0);
 	string_list_clear(&states->heads, 0);
@@ -1033,7 +1039,9 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data)
 		if (string_list_has_string(&states->new_refs, name)) {
 			fmt = _(" new (next fetch will store in remotes/%s)");
 			arg = states->remote->name;
-		} else if (string_list_has_string(&states->tracked, name))
+		} else if (string_list_has_string(&states->skipped, name))
+			arg = _(" skipped");
+		else if (string_list_has_string(&states->tracked, name))
 			arg = _(" tracked");
 		else if (string_list_has_string(&states->stale, name))
 			arg = _(" stale (use 'git remote prune' to remove)");
@@ -1308,6 +1316,7 @@ static int show(int argc, const char **argv)
 		/* remote branch info */
 		info.width = 0;
 		for_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info);
+		for_each_string_list(&info.states.skipped, add_remote_to_show_info, &info);
 		for_each_string_list(&info.states.tracked, add_remote_to_show_info, &info);
 		for_each_string_list(&info.states.stale, add_remote_to_show_info, &info);
 		if (info.list.nr)
diff --git a/remote.c b/remote.c
index 404e1e0a0ddb..7d68b5632bb5 100644
--- a/remote.c
+++ b/remote.c
@@ -804,7 +804,7 @@ static int refspec_match(const struct refspec_item *refspec,
 	return !strcmp(refspec->src, name);
 }
 
-static int omit_name_by_refspec(const char *name, struct refspec *rs)
+int omit_name_by_refspec(const char *name, struct refspec *rs)
 {
 	int i;
 
diff --git a/remote.h b/remote.h
index dd4402436f1f..448675e11259 100644
--- a/remote.h
+++ b/remote.h
@@ -247,6 +247,12 @@ int resolve_remote_symref(struct ref *ref, struct ref *list);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
+/*
+ * Check whether a name matches any negative refspec in rs. Returns 1 if the
+ * name matches at least one negative refspec, and 0 otherwise.
+ */
+int omit_name_by_refspec(const char *name, struct refspec *rs);
+
 /*
  * Remove all entries in the input list which match any negative refspec in
  * the refspec list.
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index ac5198141e79..06e5cef325c2 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -263,6 +263,28 @@ test_expect_success 'show' '
 	test_cmp expect output
 '
 
+cat >expect <<EOF
+* remote origin
+  Fetch URL: $(pwd)/one
+  Push  URL: $(pwd)/one
+  HEAD branch: main
+  Remote branches:
+    main skipped
+    side tracked
+  Local branches configured for 'git pull':
+    ahead merges with remote main
+    main  merges with remote main
+  Local refs configured for 'git push':
+    main pushes to main     (local out of date)
+    main pushes to upstream (create)
+EOF
+
+test_expect_success 'show with negative refspecs' '
+	test_config -C test --add remote.origin.fetch ^refs/heads/main &&
+	git -C test remote show origin >output &&
+	test_cmp expect output
+'
+
 cat >expect <<EOF
 * remote origin
   Fetch URL: $(pwd)/one
-- 
2.36.1


  parent reply	other threads:[~2022-06-16 20:55 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-16 20:54 [PATCH v2 0/5] support negative refspecs in git remote show Jacob Keller
2022-06-16 20:54 ` [PATCH v2 1/5] t5505: remove sub shell use in favor of git -C Jacob Keller
2022-06-16 21:09   ` Junio C Hamano
2022-06-16 21:10     ` Jacob Keller
2022-06-16 20:54 ` [PATCH v2 2/5] tests: handle --global directly in test_config/test_unconfig Jacob Keller
2022-06-16 21:34   ` Junio C Hamano
2022-06-16 22:08     ` Jacob Keller
2022-06-16 20:54 ` [PATCH v2 3/5] tests: only automatically unset matching values from test_config Jacob Keller
2022-06-16 21:18   ` Junio C Hamano
2022-06-16 22:07     ` Jacob Keller
2022-06-16 20:54 ` [PATCH v2 4/5] t5505: use test_config where appropriate Jacob Keller
2022-06-16 20:54 ` Jacob Keller [this message]
2022-06-16 21:31 ` [PATCH v2 0/5] support negative refspecs in git remote show Junio C Hamano
2022-06-16 22:08   ` Jacob Keller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220616205456.19081-6-jacob.e.keller@intel.com \
    --to=jacob.keller@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=jacob.e.keller@intel.com \
    --cc=me@ttaylorr.com \
    --cc=pavel.rappo@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).