@@ -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)
@@ -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;
@@ -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.
@@ -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
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(-)