summaryrefslogtreecommitdiff
path: root/remote.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-10-05 21:01:54 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-10-05 21:01:54 (GMT)
commit8e3ec76a20d6abf5dd8ceb3f5f2c157000e4c13e (patch)
tree816c5dc42c7dc8cac732c804b8e99775806bb5dc /remote.c
parentf6b06b459092520bd90e5a191589e2d4371ef7d1 (diff)
parentc0192df6306d4d9ad77f6015a053925b13155834 (diff)
downloadgit-8e3ec76a20d6abf5dd8ceb3f5f2c157000e4c13e.zip
git-8e3ec76a20d6abf5dd8ceb3f5f2c157000e4c13e.tar.gz
git-8e3ec76a20d6abf5dd8ceb3f5f2c157000e4c13e.tar.bz2
Merge branch 'jk/refspecs-negative'
"git fetch" and "git push" support negative refspecs. * jk/refspecs-negative: refspec: add support for negative refspecs
Diffstat (limited to 'remote.c')
-rw-r--r--remote.c108
1 files changed, 104 insertions, 4 deletions
diff --git a/remote.c b/remote.c
index eafc14c..8be67f0 100644
--- a/remote.c
+++ b/remote.c
@@ -682,6 +682,91 @@ static int match_name_with_pattern(const char *key, const char *name,
return ret;
}
+static int refspec_match(const struct refspec_item *refspec,
+ const char *name)
+{
+ if (refspec->pattern)
+ return match_name_with_pattern(refspec->src, name, NULL, NULL);
+
+ return !strcmp(refspec->src, name);
+}
+
+static int omit_name_by_refspec(const char *name, struct refspec *rs)
+{
+ int i;
+
+ for (i = 0; i < rs->nr; i++) {
+ if (rs->items[i].negative && refspec_match(&rs->items[i], name))
+ return 1;
+ }
+ return 0;
+}
+
+struct ref *apply_negative_refspecs(struct ref *ref_map, struct refspec *rs)
+{
+ struct ref **tail;
+
+ for (tail = &ref_map; *tail; ) {
+ struct ref *ref = *tail;
+
+ if (omit_name_by_refspec(ref->name, rs)) {
+ *tail = ref->next;
+ free(ref->peer_ref);
+ free(ref);
+ } else
+ tail = &ref->next;
+ }
+
+ return ref_map;
+}
+
+static int query_matches_negative_refspec(struct refspec *rs, struct refspec_item *query)
+{
+ int i, matched_negative = 0;
+ int find_src = !query->src;
+ struct string_list reversed = STRING_LIST_INIT_NODUP;
+ const char *needle = find_src ? query->dst : query->src;
+
+ /*
+ * Check whether the queried ref matches any negative refpsec. If so,
+ * then we should ultimately treat this as not matching the query at
+ * all.
+ *
+ * Note that negative refspecs always match the source, but the query
+ * item uses the destination. To handle this, we apply pattern
+ * refspecs in reverse to figure out if the query source matches any
+ * of the negative refspecs.
+ */
+ for (i = 0; i < rs->nr; i++) {
+ struct refspec_item *refspec = &rs->items[i];
+ char *expn_name;
+
+ if (refspec->negative)
+ continue;
+
+ /* Note the reversal of src and dst */
+ if (refspec->pattern) {
+ const char *key = refspec->dst ? refspec->dst : refspec->src;
+ const char *value = refspec->src;
+
+ if (match_name_with_pattern(key, needle, value, &expn_name))
+ string_list_append_nodup(&reversed, expn_name);
+ } else {
+ if (!strcmp(needle, refspec->src))
+ string_list_append(&reversed, refspec->src);
+ }
+ }
+
+ for (i = 0; !matched_negative && i < reversed.nr; i++) {
+ if (omit_name_by_refspec(reversed.items[i].string, rs))
+ matched_negative = 1;
+ }
+
+ string_list_clear(&reversed, 0);
+
+ return matched_negative;
+}
+
static void query_refspecs_multiple(struct refspec *rs,
struct refspec_item *query,
struct string_list *results)
@@ -692,6 +777,9 @@ static void query_refspecs_multiple(struct refspec *rs,
if (find_src && !query->dst)
BUG("query_refspecs_multiple: need either src or dst");
+ if (query_matches_negative_refspec(rs, query))
+ return;
+
for (i = 0; i < rs->nr; i++) {
struct refspec_item *refspec = &rs->items[i];
const char *key = find_src ? refspec->dst : refspec->src;
@@ -699,7 +787,7 @@ static void query_refspecs_multiple(struct refspec *rs,
const char *needle = find_src ? query->dst : query->src;
char **result = find_src ? &query->src : &query->dst;
- if (!refspec->dst)
+ if (!refspec->dst || refspec->negative)
continue;
if (refspec->pattern) {
if (match_name_with_pattern(key, needle, value, result))
@@ -720,12 +808,15 @@ int query_refspecs(struct refspec *rs, struct refspec_item *query)
if (find_src && !query->dst)
BUG("query_refspecs: need either src or dst");
+ if (query_matches_negative_refspec(rs, query))
+ return -1;
+
for (i = 0; i < rs->nr; i++) {
struct refspec_item *refspec = &rs->items[i];
const char *key = find_src ? refspec->dst : refspec->src;
const char *value = find_src ? refspec->src : refspec->dst;
- if (!refspec->dst)
+ if (!refspec->dst || refspec->negative)
continue;
if (refspec->pattern) {
if (match_name_with_pattern(key, needle, value, result)) {
@@ -1054,7 +1145,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
const char *dst_value = rs->dst;
char *dst_guess;
- if (rs->pattern || rs->matching)
+ if (rs->pattern || rs->matching || rs->negative)
return 0;
matched_src = matched_dst = NULL;
@@ -1130,6 +1221,10 @@ static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
int matching_refs = -1;
for (i = 0; i < rs->nr; i++) {
const struct refspec_item *item = &rs->items[i];
+
+ if (item->negative)
+ continue;
+
if (item->matching &&
(matching_refs == -1 || item->force)) {
matching_refs = i;
@@ -1335,7 +1430,7 @@ int check_push_refs(struct ref *src, struct refspec *rs)
for (i = 0; i < rs->nr; i++) {
struct refspec_item *item = &rs->items[i];
- if (item->pattern || item->matching)
+ if (item->pattern || item->matching || item->negative)
continue;
ret |= match_explicit_lhs(src, item, NULL, NULL);
@@ -1437,6 +1532,8 @@ int match_push_refs(struct ref *src, struct ref **dst,
string_list_clear(&src_ref_index, 0);
}
+ *dst = apply_negative_refspecs(*dst, rs);
+
if (errs)
return -1;
return 0;
@@ -1806,6 +1903,9 @@ int get_fetch_map(const struct ref *remote_refs,
{
struct ref *ref_map, **rmp;
+ if (refspec->negative)
+ return 0;
+
if (refspec->pattern) {
ref_map = get_expanded_map(remote_refs, refspec);
} else {