Skip to content

Commit 51214b8

Browse files
committed
refs: loosen restriction on wildcard "*" refspecs
In commit cd377f45c9 (refs: loosen restriction on wildcard "*" refspecs, 2015-07-22) in git.git, the restrictions on wildcard "*" refspecs has been loosened. While wildcards were previously only allowed if the component is a single "*", this was changed to also accept other patterns as part of the component. We never adapted to that change and still reject any wildcard patterns that aren't a single "*" only. Update our tests to reflect the upstream change and adjust our own code accordingly.
1 parent 9d651e0 commit 51214b8

File tree

3 files changed

+38
-23
lines changed

3 files changed

+38
-23
lines changed

src/refs.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -897,14 +897,13 @@ static int is_valid_ref_char(char ch)
897897
case '\\':
898898
case '?':
899899
case '[':
900-
case '*':
901900
return 0;
902901
default:
903902
return 1;
904903
}
905904
}
906905

907-
static int ensure_segment_validity(const char *name)
906+
static int ensure_segment_validity(const char *name, char may_contain_glob)
908907
{
909908
const char *current = name;
910909
char prev = '\0';
@@ -927,6 +926,12 @@ static int ensure_segment_validity(const char *name)
927926
if (prev == '@' && *current == '{')
928927
return -1; /* Refname contains "@{" */
929928

929+
if (*current == '*') {
930+
if (!may_contain_glob)
931+
return -1;
932+
may_contain_glob = 0;
933+
}
934+
930935
prev = *current;
931936
}
932937

@@ -1005,19 +1010,20 @@ int git_reference__normalize_name(
10051010
}
10061011

10071012
while (true) {
1008-
segment_len = ensure_segment_validity(current);
1009-
if (segment_len < 0) {
1010-
if ((process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) &&
1011-
current[0] == '*' &&
1012-
(current[1] == '\0' || current[1] == '/')) {
1013-
/* Accept one wildcard as a full refname component. */
1014-
process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1015-
segment_len = 1;
1016-
} else
1017-
goto cleanup;
1018-
}
1013+
char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1014+
1015+
segment_len = ensure_segment_validity(current, may_contain_glob);
1016+
if (segment_len < 0)
1017+
goto cleanup;
10191018

10201019
if (segment_len > 0) {
1020+
/*
1021+
* There may only be one glob in a pattern, thus we reset
1022+
* the pattern-flag in case the current segment has one.
1023+
*/
1024+
if (memchr(current, '*', segment_len))
1025+
process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
1026+
10211027
if (normalize) {
10221028
size_t cur_len = git_buf_len(buf);
10231029

tests/network/refspecs.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,18 @@ void test_network_refspecs__parsing(void)
7070
assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/delete me", false);
7171
assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD to me", false);
7272

73-
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
74-
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
73+
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
74+
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
7575

76-
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
77-
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
76+
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
77+
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
7878

7979
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
8080
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
8181

82+
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
83+
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
84+
8285
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
8386
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
8487

@@ -111,6 +114,12 @@ void test_network_refspecs__transform_mid_star(void)
111114
assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
112115
}
113116

117+
void test_network_refspecs__transform_loosened_star(void)
118+
{
119+
assert_valid_transform("refs/heads/branch-*:refs/remotes/origin/branch-*", "refs/heads/branch-a", "refs/remotes/origin/branch-a");
120+
assert_valid_transform("refs/heads/branch-*/head:refs/remotes/origin/branch-*/head", "refs/heads/branch-a/head", "refs/remotes/origin/branch-a/head");
121+
}
122+
114123
void test_network_refspecs__no_dst(void)
115124
{
116125
assert_valid_transform("refs/heads/master:", "refs/heads/master", "");

tests/refs/normalize.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,12 +352,12 @@ void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_ver
352352

353353
void test_refs_normalize__refspec_pattern(void)
354354
{
355-
ensure_refname_invalid(
356-
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar");
357-
ensure_refname_invalid(
358-
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar");
359-
ensure_refname_invalid(
360-
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar");
355+
ensure_refname_normalized(
356+
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar", "heads/*foo/bar");
357+
ensure_refname_normalized(
358+
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar", "heads/foo*/bar");
359+
ensure_refname_normalized(
360+
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar", "heads/f*o/bar");
361361

362362
ensure_refname_invalid(
363363
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo");

0 commit comments

Comments
 (0)