Merge branch 'jk/refspecs-negative'

"git fetch" and "git push" support negative refspecs.

* jk/refspecs-negative:
  refspec: add support for negative refspecs
This commit is contained in:
Junio C Hamano
2020-10-05 14:01:54 -07:00
7 changed files with 367 additions and 13 deletions

View File

@ -8,6 +8,7 @@ static struct refspec_item s_tag_refspec = {
1,
0,
0,
0,
"refs/tags/*",
"refs/tags/*"
};
@ -32,10 +33,17 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
if (*lhs == '+') {
item->force = 1;
lhs++;
} else if (*lhs == '^') {
item->negative = 1;
lhs++;
}
rhs = strrchr(lhs, ':');
/* negative refspecs only have one side */
if (item->negative && rhs)
return 0;
/*
* Before going on, special case ":" (or "+:") as a refspec
* for pushing matching refs.
@ -55,7 +63,7 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
if (1 <= llen && memchr(lhs, '*', llen)) {
if ((rhs && !is_glob) || (!rhs && fetch))
if ((rhs && !is_glob) || (!rhs && !item->negative && fetch))
return 0;
is_glob = 1;
} else if (rhs && is_glob) {
@ -66,6 +74,28 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
item->src = xstrndup(lhs, llen);
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
if (item->negative) {
struct object_id unused;
/*
* Negative refspecs only have a LHS, which indicates a ref
* (or pattern of refs) to exclude from other matches. This
* can either be a simple ref, or a glob pattern. Exact sha1
* match is not currently supported.
*/
if (!*item->src)
return 0; /* negative refspecs must not be empty */
else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
return 0; /* negative refpsecs cannot be exact sha1 */
else if (!check_refname_format(item->src, flags))
; /* valid looking ref is ok */
else
return 0;
/* the other rules below do not apply to negative refspecs */
return 1;
}
if (fetch) {
struct object_id unused;
@ -223,7 +253,7 @@ void refspec_ref_prefixes(const struct refspec *rs,
const struct refspec_item *item = &rs->items[i];
const char *prefix = NULL;
if (item->exact_sha1)
if (item->exact_sha1 || item->negative)
continue;
if (rs->fetch == REFSPEC_FETCH)
prefix = item->src;