diff options
author | Junio C Hamano <gitster@pobox.com> | 2018-05-30 21:51:26 +0900 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2018-05-30 21:51:26 +0900 |
commit | e12cbeaa624b82bc00d585bb24c8034fbf5f9de2 (patch) | |
tree | 6eed9588af71c6ba9776f592c3573d88929d1bab | |
parent | Merge branch 'sb/grep-die-on-unreadable-index' (diff) | |
parent | fetch: generate ref-prefixes when using a configured refspec (diff) | |
download | tgif-e12cbeaa624b82bc00d585bb24c8034fbf5f9de2.tar.xz |
Merge branch 'bw/ref-prefix-for-configured-refspec'
"git fetch $there $refspec" that talks over protocol v2 can take
advantage of server-side ref filtering; the code has been extended
so that this mechanism triggers also when fetching with configured
refspec.
* bw/ref-prefix-for-configured-refspec: (38 commits)
fetch: generate ref-prefixes when using a configured refspec
refspec: consolidate ref-prefix generation logic
submodule: convert push_unpushed_submodules to take a struct refspec
remote: convert check_push_refs to take a struct refspec
remote: convert match_push_refs to take a struct refspec
http-push: store refspecs in a struct refspec
transport: remove transport_verify_remote_names
send-pack: store refspecs in a struct refspec
transport: convert transport_push to take a struct refspec
push: convert to use struct refspec
push: check for errors earlier
remote: convert match_explicit_refs to take a struct refspec
remote: convert get_ref_match to take a struct refspec
remote: convert query_refspecs to take a struct refspec
remote: convert apply_refspecs to take a struct refspec
remote: convert get_stale_heads to take a struct refspec
fetch: convert prune_refs to take a struct refspec
fetch: convert get_ref_map to take a struct refspec
fetch: convert do_fetch to take a struct refspec
refspec: remove the deprecated functions
...
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | branch.c | 7 | ||||
-rw-r--r-- | builtin/clone.c | 13 | ||||
-rw-r--r-- | builtin/fast-export.c | 22 | ||||
-rw-r--r-- | builtin/fetch.c | 139 | ||||
-rw-r--r-- | builtin/merge.c | 1 | ||||
-rw-r--r-- | builtin/pull.c | 9 | ||||
-rw-r--r-- | builtin/push.c | 80 | ||||
-rw-r--r-- | builtin/remote.c | 37 | ||||
-rw-r--r-- | builtin/send-pack.c | 24 | ||||
-rw-r--r-- | builtin/submodule--helper.c | 14 | ||||
-rw-r--r-- | checkout.c | 5 | ||||
-rw-r--r-- | http-push.c | 18 | ||||
-rw-r--r-- | refspec.c | 223 | ||||
-rw-r--r-- | refspec.h | 48 | ||||
-rw-r--r-- | remote.c | 353 | ||||
-rw-r--r-- | remote.h | 50 | ||||
-rw-r--r-- | submodule.c | 19 | ||||
-rw-r--r-- | submodule.h | 3 | ||||
-rwxr-xr-x | t/t5702-protocol-v2.sh | 14 | ||||
-rw-r--r-- | transport-helper.c | 39 | ||||
-rw-r--r-- | transport.c | 60 | ||||
-rw-r--r-- | transport.h | 4 |
23 files changed, 570 insertions, 613 deletions
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o LIB_OBJS += refs/iterator.o LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/ref-cache.o +LIB_OBJS += refspec.o LIB_OBJS += ref-filter.o LIB_OBJS += remote.o LIB_OBJS += replace-object.o @@ -3,12 +3,13 @@ #include "config.h" #include "branch.h" #include "refs.h" +#include "refspec.h" #include "remote.h" #include "commit.h" #include "worktree.h" struct tracking { - struct refspec spec; + struct refspec_item spec; char *src; const char *remote; int matches; @@ -218,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force) static int check_tracking_branch(struct remote *remote, void *cb_data) { char *tracking_branch = cb_data; - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.dst = tracking_branch; return !remote_find_tracking(remote, &query); } diff --git a/builtin/clone.c b/builtin/clone.c index ecd8495dab..99e73dae85 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -14,6 +14,7 @@ #include "parse-options.h" #include "fetch-pack.h" #include "refs.h" +#include "refspec.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" @@ -546,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch } static struct ref *wanted_peer_refs(const struct ref *refs, - struct refspec *refspec) + struct refspec_item *refspec) { struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD")); struct ref *local_refs = head; @@ -894,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) int err = 0, complete_refs_before_fetch = 1; int submodule_progress; - struct refspec *refspec; - const char *fetch_pattern; + struct refspec_item refspec; fetch_if_missing = 0; @@ -1077,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); - fetch_pattern = value.buf; - refspec = parse_fetch_refspec(1, &fetch_pattern); + refspec_item_init(&refspec, value.buf, REFSPEC_FETCH); strbuf_reset(&value); @@ -1138,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) refs = transport_get_remote_refs(transport, NULL); if (refs) { - mapped_refs = wanted_peer_refs(refs, refspec); + mapped_refs = wanted_peer_refs(refs, &refspec); /* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list @@ -1232,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) strbuf_release(&value); junk_mode = JUNK_LEAVE_ALL; - free(refspec); + refspec_item_clear(&refspec); return err; } diff --git a/builtin/fast-export.c b/builtin/fast-export.c index f9568ddba0..6c9768742f 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -7,6 +7,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "object.h" #include "tag.h" @@ -35,8 +36,7 @@ static int use_done_feature; static int no_data; static int full_tree; static struct string_list extra_refs = STRING_LIST_INIT_NODUP; -static struct refspec *refspecs; -static int refspecs_nr; +static struct refspec refspecs = REFSPEC_INIT_FETCH; static int anonymize; static int parse_opt_signed_tag_mode(const struct option *opt, @@ -828,9 +828,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info) if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1) continue; - if (refspecs) { + if (refspecs.nr) { char *private; - private = apply_refspecs(refspecs, refspecs_nr, full_name); + private = apply_refspecs(&refspecs, full_name); if (private) { free(full_name); full_name = private; @@ -976,8 +976,8 @@ static void import_marks(char *input_file) static void handle_deletes(void) { int i; - for (i = 0; i < refspecs_nr; i++) { - struct refspec *refspec = &refspecs[i]; + for (i = 0; i < refspecs.nr; i++) { + struct refspec_item *refspec = &refspecs.items[i]; if (*refspec->src) continue; @@ -1038,18 +1038,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) usage_with_options (fast_export_usage, options); if (refspecs_list.nr) { - const char **refspecs_str; int i; - ALLOC_ARRAY(refspecs_str, refspecs_list.nr); for (i = 0; i < refspecs_list.nr; i++) - refspecs_str[i] = refspecs_list.items[i].string; - - refspecs_nr = refspecs_list.nr; - refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str); + refspec_append(&refspecs, refspecs_list.items[i].string); string_list_clear(&refspecs_list, 1); - free(refspecs_str); } if (use_done_feature) @@ -1088,7 +1082,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) if (use_done_feature) printf("done\n"); - free_refspec(refspecs_nr, refspecs); + refspec_clear(&refspecs); return 0; } diff --git a/builtin/fetch.c b/builtin/fetch.c index 1f037e8e4b..c0d8ad1fe2 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -5,6 +5,7 @@ #include "config.h" #include "repository.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "builtin.h" #include "string-list.h" @@ -59,8 +60,7 @@ static const char *submodule_prefix = ""; static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; static int shown_url = 0; -static int refmap_alloc, refmap_nr; -static const char **refmap_array; +static struct refspec refmap = REFSPEC_INIT_FETCH; static struct list_objects_filter_options filter_options; static struct string_list server_options = STRING_LIST_INIT_DUP; @@ -108,14 +108,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb) static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) { - ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc); - /* * "git fetch --refmap='' origin foo" * can be used to tell the command not to store anywhere */ - if (*arg) - refmap_array[refmap_nr++] = arg; + refspec_append(&refmap, arg); + return 0; } @@ -204,7 +202,7 @@ static void add_merge_config(struct ref **head, for (i = 0; i < branch->merge_nr; i++) { struct ref *rm, **old_tail = *tail; - struct refspec refspec; + struct refspec_item refspec; for (rm = *head; rm; rm = rm->next) { if (branch_merge_matches(branch, i, rm->name)) { @@ -341,7 +339,7 @@ static void find_non_local_tags(struct transport *transport, } static struct ref *get_ref_map(struct transport *transport, - struct refspec *refspecs, int refspec_count, + struct refspec *rs, int tags, int *autotags) { int i; @@ -355,29 +353,26 @@ static struct ref *get_ref_map(struct transport *transport, const struct ref *remote_refs; - for (i = 0; i < refspec_count; i++) { - if (!refspecs[i].exact_sha1) { - const char *glob = strchr(refspecs[i].src, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - refspecs[i].src), - refspecs[i].src); - else - expand_ref_prefix(&ref_prefixes, refspecs[i].src); - } + if (rs->nr) + refspec_ref_prefixes(rs, &ref_prefixes); + else if (transport->remote && transport->remote->fetch.nr) + refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes); + + if (ref_prefixes.argc && + (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) { + argv_array_push(&ref_prefixes, "refs/tags/"); } remote_refs = transport_get_remote_refs(transport, &ref_prefixes); argv_array_clear(&ref_prefixes); - if (refspec_count) { + if (rs->nr) { struct refspec *fetch_refspec; - int fetch_refspec_nr; - for (i = 0; i < refspec_count; i++) { - get_fetch_map(remote_refs, &refspecs[i], &tail, 0); - if (refspecs[i].dst && refspecs[i].dst[0]) + for (i = 0; i < rs->nr; i++) { + get_fetch_map(remote_refs, &rs->items[i], &tail, 0); + if (rs->items[i].dst && rs->items[i].dst[0]) *autotags = 1; } /* Merge everything on the command line (but not --tags) */ @@ -404,17 +399,14 @@ static struct ref *get_ref_map(struct transport *transport, * by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ - if (refmap_array) { - fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array); - fetch_refspec_nr = refmap_nr; - } else { - fetch_refspec = transport->remote->fetch; - fetch_refspec_nr = transport->remote->fetch_refspec_nr; - } + if (refmap.nr) + fetch_refspec = &refmap; + else + fetch_refspec = &transport->remote->fetch; - for (i = 0; i < fetch_refspec_nr; i++) - get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1); - } else if (refmap_array) { + for (i = 0; i < fetch_refspec->nr; i++) + get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1); + } else if (refmap.nr) { die("--refmap option is only meaningful with command-line refspec(s)."); } else { /* Use the defaults */ @@ -422,16 +414,16 @@ static struct ref *get_ref_map(struct transport *transport, struct branch *branch = branch_get(NULL); int has_merge = branch_has_merge_config(branch); if (remote && - (remote->fetch_refspec_nr || + (remote->fetch.nr || /* Note: has_merge implies non-NULL branch->remote_name */ (has_merge && !strcmp(branch->remote_name, remote->name)))) { - for (i = 0; i < remote->fetch_refspec_nr; i++) { - get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0); - if (remote->fetch[i].dst && - remote->fetch[i].dst[0]) + for (i = 0; i < remote->fetch.nr; i++) { + get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0); + if (remote->fetch.items[i].dst && + remote->fetch.items[i].dst[0]) *autotags = 1; if (!i && !has_merge && ref_map && - !remote->fetch[0].pattern) + !remote->fetch.items[0].pattern) ref_map->fetch_head_status = FETCH_HEAD_MERGE; } /* @@ -966,11 +958,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) return ret; } -static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map, - const char *raw_url) +static int prune_refs(struct refspec *rs, struct ref *ref_map, + const char *raw_url) { int url_len, i, result = 0; - struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map); + struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map); char *url; int summary_width = transport_summary_width(stale_refs); const char *dangling_msg = dry_run @@ -1116,7 +1108,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) } static int do_fetch(struct transport *transport, - struct refspec *refs, int ref_count) + struct refspec *rs) { struct string_list existing_refs = STRING_LIST_INIT_DUP; struct ref *ref_map; @@ -1140,7 +1132,7 @@ static int do_fetch(struct transport *transport, goto cleanup; } - ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags); + ref_map = get_ref_map(transport, rs, tags, &autotags); if (!update_head_ok) check_not_current_branch(ref_map); @@ -1164,11 +1156,10 @@ static int do_fetch(struct transport *transport, * explicitly (via command line or configuration); we * don't care whether --tags was specified. */ - if (ref_count) { - prune_refs(refs, ref_count, ref_map, transport->url); + if (rs->nr) { + prune_refs(rs, ref_map, transport->url); } else { - prune_refs(transport->remote->fetch, - transport->remote->fetch_refspec_nr, + prune_refs(&transport->remote->fetch, ref_map, transport->url); } @@ -1357,10 +1348,8 @@ static inline void fetch_one_setup_partial(struct remote *remote) static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok) { - static const char **refs = NULL; - struct refspec *refspec; - int ref_nr = 0; - int j = 0; + struct refspec rs = REFSPEC_INIT_FETCH; + int i; int exit_code; int maybe_prune_tags; int remote_via_config = remote_is_configured(remote, 0); @@ -1393,29 +1382,24 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru maybe_prune_tags = prune_tags_ok && prune_tags; if (maybe_prune_tags && remote_via_config) - add_prune_tags_to_fetch_refspec(remote); - - if (argc > 0 || (maybe_prune_tags && !remote_via_config)) { - size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1); - refs = xcalloc(nr_alloc, sizeof(const char *)); - if (maybe_prune_tags) { - refs[j++] = xstrdup("refs/tags/*:refs/tags/*"); - ref_nr++; - } - } - - if (argc > 0) { - int i; - for (i = 0; i < argc; i++) { - if (!strcmp(argv[i], "tag")) { - i++; - if (i >= argc) - die(_("You need to specify a tag name.")); - refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s", - argv[i], argv[i]); - } else - refs[j++] = argv[i]; - ref_nr++; + refspec_append(&remote->fetch, TAG_REFSPEC); + + if (maybe_prune_tags && (argc || !remote_via_config)) + refspec_append(&rs, TAG_REFSPEC); + + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i], "tag")) { + char *tag; + i++; + if (i >= argc) + die(_("You need to specify a tag name.")); + + tag = xstrfmt("refs/tags/%s:refs/tags/%s", + argv[i], argv[i]); + refspec_append(&rs, tag); + free(tag); + } else { + refspec_append(&rs, argv[i]); } } @@ -1424,9 +1408,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); - refspec = parse_fetch_refspec(ref_nr, refs); - exit_code = do_fetch(gtransport, refspec, ref_nr); - free_refspec(ref_nr, refspec); + exit_code = do_fetch(gtransport, &rs); + refspec_clear(&rs); transport_disconnect(gtransport); gtransport = NULL; return exit_code; diff --git a/builtin/merge.c b/builtin/merge.c index fba0a7fc79..d85f99b781 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -14,6 +14,7 @@ #include "run-command.h" #include "diff.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diffcore.h" #include "revision.h" diff --git a/builtin/pull.c b/builtin/pull.c index 25f7db5b3a..1f2ecf3a88 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -15,6 +15,7 @@ #include "remote.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "revision.h" #include "submodule.h" #include "submodule-config.h" @@ -679,12 +680,12 @@ static const char *get_upstream_branch(const char *remote) */ static const char *get_tracking_branch(const char *remote, const char *refspec) { - struct refspec *spec; + struct refspec_item spec; const char *spec_src; const char *merge_branch; - spec = parse_fetch_refspec(1, &refspec); - spec_src = spec->src; + refspec_item_init(&spec, refspec, REFSPEC_FETCH); + spec_src = spec.src; if (!*spec_src || !strcmp(spec_src, "HEAD")) spec_src = "HEAD"; else if (skip_prefix(spec_src, "heads/", &spec_src)) @@ -704,7 +705,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec) } else merge_branch = NULL; - free_refspec(1, spec); + refspec_item_clear(&spec); return merge_branch; } diff --git a/builtin/push.c b/builtin/push.c index ac3705370e..9cd8e8cd56 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -4,6 +4,7 @@ #include "cache.h" #include "config.h" #include "refs.h" +#include "refspec.h" #include "run-command.h" #include "builtin.h" #include "remote.h" @@ -56,19 +57,10 @@ static enum transport_family family; static struct push_cas_option cas; -static const char **refspec; -static int refspec_nr; -static int refspec_alloc; +static struct refspec rs = REFSPEC_INIT_PUSH; static struct string_list push_options_config = STRING_LIST_INIT_DUP; -static void add_refspec(const char *ref) -{ - refspec_nr++; - ALLOC_GROW(refspec, refspec_nr, refspec_alloc); - refspec[refspec_nr-1] = ref; -} - static const char *map_refspec(const char *ref, struct remote *remote, struct ref *local_refs) { @@ -78,12 +70,11 @@ static const char *map_refspec(const char *ref, if (count_refspec_match(ref, local_refs, &matched) != 1) return ref; - if (remote->push) { - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + if (remote->push.nr) { + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.src = matched->name; - if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) && - query.dst) { + if (!query_refspecs(&remote->push, &query) && query.dst) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%s%s:%s", query.force ? "+" : "", @@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo) } ref = map_refspec(ref, remote, local_refs); } - add_refspec(ref); + refspec_append(&rs, ref); } } @@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch, } strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src); - add_refspec(refspec.buf); + refspec_append(&rs, refspec.buf); } static void setup_push_current(struct remote *remote, struct branch *branch) @@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch) if (!branch) die(_(message_detached_head_die), remote->name); strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname); - add_refspec(refspec.buf); + refspec_append(&rs, refspec.buf); } static int is_workflow_triangular(struct remote *remote) @@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote) switch (push_default) { default: case PUSH_DEFAULT_MATCHING: - add_refspec(":"); + refspec_append(&rs, ":"); break; case PUSH_DEFAULT_UNSPECIFIED: @@ -341,7 +332,8 @@ static void advise_ref_needs_force(void) advise(_(message_advice_ref_needs_force)); } -static int push_with_options(struct transport *transport, int flags) +static int push_with_options(struct transport *transport, struct refspec *rs, + int flags) { int err; unsigned int reject_reasons; @@ -363,8 +355,7 @@ static int push_with_options(struct transport *transport, int flags) if (verbosity > 0) fprintf(stderr, _("Pushing to %s\n"), transport->url); - err = transport_push(transport, refspec_nr, refspec, flags, - &reject_reasons); + err = transport_push(transport, rs, flags, &reject_reasons); if (err != 0) { fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR)); error(_("failed to push some refs to '%s'"), transport->url); @@ -397,6 +388,7 @@ static int do_push(const char *repo, int flags, struct remote *remote = pushremote_get(repo); const char **url; int url_nr; + struct refspec *push_refspec = &rs; if (!remote) { if (repo) @@ -417,27 +409,9 @@ static int do_push(const char *repo, int flags, if (push_options->nr) flags |= TRANSPORT_PUSH_OPTIONS; - if ((flags & TRANSPORT_PUSH_ALL) && refspec) { - if (!strcmp(*refspec, "refs/tags/*")) - return error(_("--all and --tags are incompatible")); - return error(_("--all can't be combined with refspecs")); - } - - if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) { - if (!strcmp(*refspec, "refs/tags/*")) - return error(_("--mirror and --tags are incompatible")); - return error(_("--mirror can't be combined with refspecs")); - } - - if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) == - (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) { - return error(_("--all and --mirror are incompatible")); - } - - if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) { - if (remote->push_refspec_nr) { - refspec = remote->push_refspec; - refspec_nr = remote->push_refspec_nr; + if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) { + if (remote->push.nr) { + push_refspec = &remote->push; } else if (!(flags & TRANSPORT_PUSH_MIRROR)) setup_default_push_refspecs(remote); } @@ -449,7 +423,7 @@ static int do_push(const char *repo, int flags, transport_get(remote, url[i]); if (flags & TRANSPORT_PUSH_OPTIONS) transport->push_options = push_options; - if (push_with_options(transport, flags)) + if (push_with_options(transport, push_refspec, flags)) errs++; } } else { @@ -457,7 +431,7 @@ static int do_push(const char *repo, int flags, transport_get(remote, NULL); if (flags & TRANSPORT_PUSH_OPTIONS) transport->push_options = push_options; - if (push_with_options(transport, flags)) + if (push_with_options(transport, push_refspec, flags)) errs++; } return !!errs; @@ -625,6 +599,20 @@ int cmd_push(int argc, const char **argv, const char *prefix) die(_("--delete is incompatible with --all, --mirror and --tags")); if (deleterefs && argc < 2) die(_("--delete doesn't make sense without any refs")); + if (flags & TRANSPORT_PUSH_ALL) { + if (tags) + die(_("--all and --tags are incompatible")); + if (argc >= 2) + die(_("--all can't be combined with refspecs")); + } + if (flags & TRANSPORT_PUSH_MIRROR) { + if (tags) + die(_("--mirror and --tags are incompatible")); + if (argc >= 2) + die(_("--mirror can't be combined with refspecs")); + } + if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR)) + die(_("--all and --mirror are incompatible")); if (recurse_submodules == RECURSE_SUBMODULES_CHECK) flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK; @@ -634,7 +622,7 @@ int cmd_push(int argc, const char **argv, const char *prefix) flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY; if (tags) - add_refspec("refs/tags/*"); + refspec_append(&rs, "refs/tags/*"); if (argc > 0) { repo = argv[0]; diff --git a/builtin/remote.c b/builtin/remote.c index 0bbf9f4c9e..1a82d850a2 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -7,6 +7,7 @@ #include "strbuf.h" #include "run-command.h" #include "refs.h" +#include "refspec.h" #include "argv-array.h" static const char * const builtin_remote_usage[] = { @@ -336,10 +337,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat struct ref *ref, *stale_refs; int i; - for (i = 0; i < states->remote->fetch_refspec_nr; i++) - if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1)) + for (i = 0; i < states->remote->fetch.nr; i++) + if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1)) die(_("Could not get fetch map for refspec %s"), - states->remote->fetch_refspec[i]); + states->remote->fetch.raw[i]); states->new_refs.strdup_strings = 1; states->tracked.strdup_strings = 1; @@ -350,8 +351,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat else string_list_append(&states->tracked, abbrev_branch(ref->name)); } - stale_refs = get_stale_heads(states->remote->fetch, - states->remote->fetch_refspec_nr, fetch_map); + stale_refs = get_stale_heads(&states->remote->fetch, fetch_map); for (ref = stale_refs; ref; ref = ref->next) { struct string_list_item *item = string_list_append(&states->stale, abbrev_branch(ref->name)); @@ -391,8 +391,7 @@ static int get_push_ref_states(const struct ref *remote_refs, local_refs = get_local_heads(); push_map = copy_ref_list(remote_refs); - match_push_refs(local_refs, &push_map, remote->push_refspec_nr, - remote->push_refspec, MATCH_REFS_NONE); + match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE); states->push.strdup_strings = 1; for (ref = push_map; ref; ref = ref->next) { @@ -438,14 +437,14 @@ static int get_push_ref_states_noquery(struct ref_states *states) return 0; states->push.strdup_strings = 1; - if (!remote->push_refspec_nr) { + if (!remote->push.nr) { item = string_list_append(&states->push, _("(matching)")); info = item->util = xcalloc(1, sizeof(struct push_info)); info->status = PUSH_STATUS_NOTQUERIED; info->dest = xstrdup(item->string); } - for (i = 0; i < remote->push_refspec_nr; i++) { - struct refspec *spec = remote->push + i; + for (i = 0; i < remote->push.nr; i++) { + const struct refspec_item *spec = &remote->push.items[i]; if (spec->matching) item = string_list_append(&states->push, _("(matching)")); else if (strlen(spec->src)) @@ -465,7 +464,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat { struct ref *ref, *matches; struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; - struct refspec refspec; + struct refspec_item refspec; refspec.force = 0; refspec.pattern = 1; @@ -518,7 +517,7 @@ static int add_branch_for_removal(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct branches_for_remote *branches = cb_data; - struct refspec refspec; + struct refspec_item refspec; struct known_remote *kr; memset(&refspec, 0, sizeof(refspec)); @@ -589,12 +588,12 @@ static int migrate_file(struct remote *remote) git_config_set_multivar(buf.buf, remote->url[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); - for (i = 0; i < remote->push_refspec_nr; i++) - git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0); + for (i = 0; i < remote->push.raw_nr; i++) + git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); - for (i = 0; i < remote->fetch_refspec_nr; i++) - git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0); + for (i = 0; i < remote->fetch.raw_nr; i++) + git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0); if (remote->origin == REMOTE_REMOTES) unlink_or_warn(git_path("remotes/%s", remote->name)); else if (remote->origin == REMOTE_BRANCHES) @@ -649,11 +648,11 @@ static int mv(int argc, const char **argv) strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); git_config_set_multivar(buf.buf, NULL, NULL, 1); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); - for (i = 0; i < oldremote->fetch_refspec_nr; i++) { + for (i = 0; i < oldremote->fetch.raw_nr; i++) { char *ptr; strbuf_reset(&buf2); - strbuf_addstr(&buf2, oldremote->fetch_refspec[i]); + strbuf_addstr(&buf2, oldremote->fetch.raw[i]); ptr = strstr(buf2.buf, old_remote_context.buf); if (ptr) { refspec_updated = 1; @@ -837,7 +836,7 @@ static int append_ref_to_tracked_list(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct ref_states *states = cb_data; - struct refspec refspec; + struct refspec_item refspec; if (flags & REF_ISSYMREF) return 0; diff --git a/builtin/send-pack.c b/builtin/send-pack.c index b5427f75e3..4923b1058c 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb) int cmd_send_pack(int argc, const char **argv, const char *prefix) { - int i, nr_refspecs = 0; - const char **refspecs = NULL; + struct refspec rs = REFSPEC_INIT_PUSH; const char *remote_name = NULL; struct remote *remote = NULL; const char *dest = NULL; @@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0); if (argc > 0) { dest = argv[0]; - refspecs = (const char **)(argv + 1); - nr_refspecs = argc - 1; + refspec_appendn(&rs, argv + 1, argc - 1); } if (!dest) @@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) args.push_options = push_options.nr ? &push_options : NULL; if (from_stdin) { - struct argv_array all_refspecs = ARGV_ARRAY_INIT; - - for (i = 0; i < nr_refspecs; i++) - argv_array_push(&all_refspecs, refspecs[i]); - if (args.stateless_rpc) { const char *buf; while ((buf = packet_read_line(0, NULL))) - argv_array_push(&all_refspecs, buf); + refspec_append(&rs, buf); } else { struct strbuf line = STRBUF_INIT; while (strbuf_getline(&line, stdin) != EOF) - argv_array_push(&all_refspecs, line.buf); + refspec_append(&rs, line.buf); strbuf_release(&line); } - - refspecs = all_refspecs.argv; - nr_refspecs = all_refspecs.argc; } /* * --all and --mirror are incompatible; neither makes sense * with any refspecs. */ - if ((nr_refspecs > 0 && (send_all || args.send_mirror)) || + if ((rs.nr > 0 && (send_all || args.send_mirror)) || (send_all && args.send_mirror)) usage_with_options(send_pack_usage, options); @@ -275,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) BUG("unknown protocol version"); } - transport_verify_remote_names(nr_refspecs, refspecs); - local_refs = get_local_heads(); flags = MATCH_REFS_NONE; @@ -287,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) flags |= MATCH_REFS_MIRROR; /* match them up */ - if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags)) + if (match_push_refs(local_refs, &remote_refs, &rs, flags)) return -1; if (!is_empty_cas(&cas)) diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 7c3cd9dbeb..bd250ca216 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -12,6 +12,7 @@ #include "run-command.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "connect.h" #include "revision.h" #include "diffcore.h" @@ -1753,13 +1754,14 @@ static int push_check(int argc, const char **argv, const char *prefix) /* Check the refspec */ if (argc > 2) { - int i, refspec_nr = argc - 2; + int i; struct ref *local_refs = get_local_heads(); - struct refspec *refspec = parse_push_refspec(refspec_nr, - argv + 2); + struct refspec refspec = REFSPEC_INIT_PUSH; - for (i = 0; i < refspec_nr; i++) { - struct refspec *rs = refspec + i; + refspec_appendn(&refspec, argv + 2, argc - 2); + + for (i = 0; i < refspec.nr; i++) { + const struct refspec_item *rs = &refspec.items[i]; if (rs->pattern || rs->matching) continue; @@ -1786,7 +1788,7 @@ static int push_check(int argc, const char **argv, const char *prefix) rs->src); } } - free_refspec(refspec_nr, refspec); + refspec_clear(&refspec); } free(head); diff --git a/checkout.c b/checkout.c index ac42630f74..bdefc888ba 100644 --- a/checkout.c +++ b/checkout.c @@ -1,5 +1,6 @@ #include "cache.h" #include "remote.h" +#include "refspec.h" #include "checkout.h" struct tracking_name_data { @@ -12,8 +13,8 @@ struct tracking_name_data { static int check_tracking_name(struct remote *remote, void *cb_data) { struct tracking_name_data *cb = cb_data; - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.src = cb->src_ref; if (remote_find_tracking(remote, &query) || get_oid(query.dst, cb->dst_oid)) { diff --git a/http-push.c b/http-push.c index 2669f4bfa1..7e38522098 100644 --- a/http-push.c +++ b/http-push.c @@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv) { struct transfer_request *request; struct transfer_request *next_request; - int nr_refspec = 0; - const char **refspec = NULL; + struct refspec rs = REFSPEC_INIT_PUSH; struct remote_lock *ref_lock = NULL; struct remote_lock *info_ref_lock = NULL; struct rev_info revs; @@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv) } continue; } - refspec = argv; - nr_refspec = argc - i; + refspec_appendn(&rs, argv, argc - i); break; } @@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv) if (!repo->url) usage(http_push_usage); - if (delete_branch && nr_refspec != 1) + if (delete_branch && rs.nr != 1) die("You must specify only one branch name when deleting a remote branch"); setup_git_directory(); @@ -1814,18 +1812,18 @@ int cmd_main(int argc, const char **argv) /* Remove a remote branch if -d or -D was specified */ if (delete_branch) { - if (delete_remote_branch(refspec[0], force_delete) == -1) { + const char *branch = rs.items[i].src; + if (delete_remote_branch(branch, force_delete) == -1) { fprintf(stderr, "Unable to delete remote branch %s\n", - refspec[0]); + branch); if (helper_status) - printf("error %s cannot remove\n", refspec[0]); + printf("error %s cannot remove\n", branch); } goto cleanup; } /* match them up */ - if (match_push_refs(local_refs, &remote_refs, - nr_refspec, (const char **) refspec, push_all)) { + if (match_push_refs(local_refs, &remote_refs, &rs, push_all)) { rc = -1; goto cleanup; } diff --git a/refspec.c b/refspec.c new file mode 100644 index 0000000000..c59a4ccf1e --- /dev/null +++ b/refspec.c @@ -0,0 +1,223 @@ +#include "cache.h" +#include "argv-array.h" +#include "refs.h" +#include "refspec.h" + +static struct refspec_item s_tag_refspec = { + 0, + 1, + 0, + 0, + "refs/tags/*", + "refs/tags/*" +}; + +/* See TAG_REFSPEC for the string version */ +const struct refspec_item *tag_refspec = &s_tag_refspec; + +/* + * Parses the provided refspec 'refspec' and populates the refspec_item 'item'. + * Returns 1 if successful and 0 if the refspec is invalid. + */ +static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch) +{ + size_t llen; + int is_glob; + const char *lhs, *rhs; + int flags; + + is_glob = 0; + + lhs = refspec; + if (*lhs == '+') { + item->force = 1; + lhs++; + } + + rhs = strrchr(lhs, ':'); + + /* + * Before going on, special case ":" (or "+:") as a refspec + * for pushing matching refs. + */ + if (!fetch && rhs == lhs && rhs[1] == '\0') { + item->matching = 1; + return 1; + } + + if (rhs) { + size_t rlen = strlen(++rhs); + is_glob = (1 <= rlen && strchr(rhs, '*')); + item->dst = xstrndup(rhs, rlen); + } + + llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); + if (1 <= llen && memchr(lhs, '*', llen)) { + if ((rhs && !is_glob) || (!rhs && fetch)) + return 0; + is_glob = 1; + } else if (rhs && is_glob) { + return 0; + } + + item->pattern = is_glob; + item->src = xstrndup(lhs, llen); + flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); + + if (fetch) { + struct object_id unused; + + /* LHS */ + if (!*item->src) + ; /* empty is ok; it means "HEAD" */ + else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused)) + item->exact_sha1 = 1; /* ok */ + else if (!check_refname_format(item->src, flags)) + ; /* valid looking ref is ok */ + else + return 0; + /* RHS */ + if (!item->dst) + ; /* missing is ok; it is the same as empty */ + else if (!*item->dst) + ; /* empty is ok; it means "do not store" */ + else if (!check_refname_format(item->dst, flags)) + ; /* valid looking ref is ok */ + else + return 0; + } else { + /* + * LHS + * - empty is allowed; it means delete. + * - when wildcarded, it must be a valid looking ref. + * - otherwise, it must be an extended SHA-1, but + * there is no existing way to validate this. + */ + if (!*item->src) + ; /* empty is ok */ + else if (is_glob) { + if (check_refname_format(item->src, flags)) + return 0; + } + else + ; /* anything goes, for now */ + /* + * RHS + * - missing is allowed, but LHS then must be a + * valid looking ref. + * - empty is not allowed. + * - otherwise it must be a valid looking ref. + */ + if (!item->dst) { + if (check_refname_format(item->src, flags)) + return 0; + } else if (!*item->dst) { + return 0; + } else { + if (check_refname_format(item->dst, flags)) + return 0; + } + } + + return 1; +} + +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch) +{ + memset(item, 0, sizeof(*item)); + + if (!parse_refspec(item, refspec, fetch)) + die("Invalid refspec '%s'", refspec); +} + +void refspec_item_clear(struct refspec_item *item) +{ + FREE_AND_NULL(item->src); + FREE_AND_NULL(item->dst); + item->force = 0; + item->pattern = 0; + item->matching = 0; + item->exact_sha1 = 0; +} + +void refspec_init(struct refspec *rs, int fetch) +{ + memset(rs, 0, sizeof(*rs)); + rs->fetch = fetch; +} + +void refspec_append(struct refspec *rs, const char *refspec) +{ + struct refspec_item item; + + refspec_item_init(&item, refspec, rs->fetch); + + ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc); + rs->items[rs->nr++] = item; + + ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc); + rs->raw[rs->raw_nr++] = xstrdup(refspec); +} + +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr) +{ + int i; + for (i = 0; i < nr; i++) + refspec_append(rs, refspecs[i]); +} + +void refspec_clear(struct refspec *rs) +{ + int i; + + for (i = 0; i < rs->nr; i++) + refspec_item_clear(&rs->items[i]); + + FREE_AND_NULL(rs->items); + rs->alloc = 0; + rs->nr = 0; + + for (i = 0; i < rs->raw_nr; i++) + free((char *)rs->raw[i]); + FREE_AND_NULL(rs->raw); + rs->raw_alloc = 0; + rs->raw_nr = 0; + + rs->fetch = 0; +} + +int valid_fetch_refspec(const char *fetch_refspec_str) +{ + struct refspec_item refspec; + int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH); + refspec_item_clear(&refspec); + return ret; +} + +void refspec_ref_prefixes(const struct refspec *rs, + struct argv_array *ref_prefixes) +{ + int i; + for (i = 0; i < rs->nr; i++) { + const struct refspec_item *item = &rs->items[i]; + const char *prefix = NULL; + + if (rs->fetch == REFSPEC_FETCH) + prefix = item->src; + else if (item->dst) + prefix = item->dst; + else if (item->src && !item->exact_sha1) + prefix = item->src; + + if (prefix) { + if (item->pattern) { + const char *glob = strchr(prefix, '*'); + argv_array_pushf(ref_prefixes, "%.*s", + (int)(glob - prefix), + prefix); + } else { + expand_ref_prefix(ref_prefixes, prefix); + } + } + } +} diff --git a/refspec.h b/refspec.h new file mode 100644 index 0000000000..01b700e094 --- /dev/null +++ b/refspec.h @@ -0,0 +1,48 @@ +#ifndef REFSPEC_H +#define REFSPEC_H + +#define TAG_REFSPEC "refs/tags/*:refs/tags/*" +extern const struct refspec_item *tag_refspec; + +struct refspec_item { + unsigned force : 1; + unsigned pattern : 1; + unsigned matching : 1; + unsigned exact_sha1 : 1; + + char *src; + char *dst; +}; + +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0 + +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { + struct refspec_item *items; + int alloc; + int nr; + + const char **raw; + int raw_alloc; + int raw_nr; + + int fetch; +}; + +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch); +void refspec_item_clear(struct refspec_item *item); +void refspec_init(struct refspec *rs, int fetch); +void refspec_append(struct refspec *rs, const char *refspec); +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr); +void refspec_clear(struct refspec *rs); + +int valid_fetch_refspec(const char *refspec); + +struct argv_array; +void refspec_ref_prefixes(const struct refspec *rs, + struct argv_array *ref_prefixes); + +#endif /* REFSPEC_H */ @@ -2,6 +2,7 @@ #include "config.h" #include "remote.h" #include "refs.h" +#include "refspec.h" #include "commit.h" #include "diff.h" #include "revision.h" @@ -13,18 +14,6 @@ enum map_direction { FROM_SRC, FROM_DST }; -static struct refspec s_tag_refspec = { - 0, - 1, - 0, - 0, - "refs/tags/*", - "refs/tags/*" -}; - -/* See TAG_REFSPEC for the string version */ -const struct refspec *tag_refspec = &s_tag_refspec; - struct counted_string { size_t len; const char *s; @@ -88,33 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r) return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } -static void add_push_refspec(struct remote *remote, const char *ref) -{ - ALLOC_GROW(remote->push_refspec, - remote->push_refspec_nr + 1, - remote->push_refspec_alloc); - remote->push_refspec[remote->push_refspec_nr++] = ref; -} - -static void add_fetch_refspec(struct remote *remote, const char *ref) -{ - ALLOC_GROW(remote->fetch_refspec, - remote->fetch_refspec_nr + 1, - remote->fetch_refspec_alloc); - remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; -} - -void add_prune_tags_to_fetch_refspec(struct remote *remote) -{ - int nr = remote->fetch_refspec_nr; - int bufsize = nr + 1; - int size = sizeof(struct refspec); - - remote->fetch = xrealloc(remote->fetch, size * bufsize); - memcpy(&remote->fetch[nr], tag_refspec, size); - add_fetch_refspec(remote, xstrdup(TAG_REFSPEC)); -} - static void add_url(struct remote *remote, const char *url) { ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); @@ -186,9 +148,12 @@ static struct remote *make_remote(const char *name, int len) ret = xcalloc(1, sizeof(struct remote)); ret->prune = -1; /* unspecified */ ret->prune_tags = -1; /* unspecified */ + ret->name = xstrndup(name, len); + refspec_init(&ret->push, REFSPEC_PUSH); + refspec_init(&ret->fetch, REFSPEC_FETCH); + ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); remotes[remotes_nr++] = ret; - ret->name = xstrndup(name, len); hashmap_entry_init(ret, lookup_entry.hash); replaced = hashmap_put(&remotes_hash, ret); @@ -286,9 +251,9 @@ static void read_remotes_file(struct remote *remote) if (skip_prefix(buf.buf, "URL:", &v)) add_url_alias(remote, xstrdup(skip_spaces(v))); else if (skip_prefix(buf.buf, "Push:", &v)) - add_push_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->push, skip_spaces(v)); else if (skip_prefix(buf.buf, "Pull:", &v)) - add_fetch_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->fetch, skip_spaces(v)); } strbuf_release(&buf); fclose(f); @@ -327,15 +292,19 @@ static void read_branches_file(struct remote *remote) frag = "master"; add_url_alias(remote, strbuf_detach(&buf, NULL)); - add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s", - frag, remote->name)); + strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s", + frag, remote->name); + refspec_append(&remote->fetch, buf.buf); /* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ - add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag)); + strbuf_reset(&buf); + strbuf_addf(&buf, "HEAD:refs/heads/%s", frag); + refspec_append(&remote->push, buf.buf); remote->fetch_tags = 1; /* always auto-follow */ + strbuf_release(&buf); } static int handle_config(const char *key, const char *value, void *cb) @@ -420,12 +389,14 @@ static int handle_config(const char *key, const char *value, void *cb) const char *v; if (git_config_string(&v, key, value)) return -1; - add_push_refspec(remote, v); + refspec_append(&remote->push, v); + free((char *)v); } else if (!strcmp(subkey, "fetch")) { const char *v; if (git_config_string(&v, key, value)) return -1; - add_fetch_refspec(remote, v); + refspec_append(&remote->fetch, v); + free((char *)v); } else if (!strcmp(subkey, "receivepack")) { const char *v; if (git_config_string(&v, key, value)) @@ -499,158 +470,6 @@ static void read_config(void) alias_all_urls(); } -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) -{ - int i; - struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs)); - - for (i = 0; i < nr_refspec; i++) { - size_t llen; - int is_glob; - const char *lhs, *rhs; - int flags; - - is_glob = 0; - - lhs = refspec[i]; - if (*lhs == '+') { - rs[i].force = 1; - lhs++; - } - - rhs = strrchr(lhs, ':'); - - /* - * Before going on, special case ":" (or "+:") as a refspec - * for pushing matching refs. - */ - if (!fetch && rhs == lhs && rhs[1] == '\0') { - rs[i].matching = 1; - continue; - } - - if (rhs) { - size_t rlen = strlen(++rhs); - is_glob = (1 <= rlen && strchr(rhs, '*')); - rs[i].dst = xstrndup(rhs, rlen); - } - - llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); - if (1 <= llen && memchr(lhs, '*', llen)) { - if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob = 1; - } else if (rhs && is_glob) { - goto invalid; - } - - rs[i].pattern = is_glob; - rs[i].src = xstrndup(lhs, llen); - flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); - - if (fetch) { - struct object_id unused; - - /* LHS */ - if (!*rs[i].src) - ; /* empty is ok; it means "HEAD" */ - else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused)) - rs[i].exact_sha1 = 1; /* ok */ - else if (!check_refname_format(rs[i].src, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - /* RHS */ - if (!rs[i].dst) - ; /* missing is ok; it is the same as empty */ - else if (!*rs[i].dst) - ; /* empty is ok; it means "do not store" */ - else if (!check_refname_format(rs[i].dst, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - } else { - /* - * LHS - * - empty is allowed; it means delete. - * - when wildcarded, it must be a valid looking ref. - * - otherwise, it must be an extended SHA-1, but - * there is no existing way to validate this. - */ - if (!*rs[i].src) - ; /* empty is ok */ - else if (is_glob) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } - else - ; /* anything goes, for now */ - /* - * RHS - * - missing is allowed, but LHS then must be a - * valid looking ref. - * - empty is not allowed. - * - otherwise it must be a valid looking ref. - */ - if (!rs[i].dst) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } else if (!*rs[i].dst) { - goto invalid; - } else { - if (check_refname_format(rs[i].dst, flags)) - goto invalid; - } - } - } - return rs; - - invalid: - if (verify) { - /* - * nr_refspec must be greater than zero and i must be valid - * since it is only possible to reach this point from within - * the for loop above. - */ - free_refspec(i+1, rs); - return NULL; - } - die("Invalid refspec '%s'", refspec[i]); -} - -int valid_fetch_refspec(const char *fetch_refspec_str) -{ - struct refspec *refspec; - - refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1); - free_refspec(1, refspec); - return !!refspec; -} - -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) -{ - return parse_refspec_internal(nr_refspec, refspec, 1, 0); -} - -struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) -{ - return parse_refspec_internal(nr_refspec, refspec, 0, 0); -} - -void free_refspec(int nr_refspec, struct refspec *refspec) -{ - int i; - - if (!refspec) - return; - - for (i = 0; i < nr_refspec; i++) { - free(refspec[i].src); - free(refspec[i].dst); - } - free(refspec); -} - static int valid_remote_nick(const char *name) { if (!name[0] || is_dot_or_dotdot(name)) @@ -705,9 +524,8 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push, pushremote_for_branch(branch, NULL); struct remote *remote = remote_get(remote_name); - if (remote && remote->push_refspec_nr && - (dst = apply_refspecs(remote->push, - remote->push_refspec_nr, + if (remote && remote->push.nr && + (dst = apply_refspecs(&remote->push, branch->refname))) { if (explicit) *explicit = 1; @@ -744,8 +562,6 @@ static struct remote *remote_get_1(const char *name, add_url_alias(ret, name); if (!valid_remote(ret)) return NULL; - ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec); return ret; } @@ -776,12 +592,6 @@ int for_each_remote(each_remote_fn fn, void *priv) struct remote *r = remotes[i]; if (!r) continue; - if (!r->fetch) - r->fetch = parse_fetch_refspec(r->fetch_refspec_nr, - r->fetch_refspec); - if (!r->push) - r->push = parse_push_refspec(r->push_refspec_nr, - r->push_refspec); result = fn(r, priv); } return result; @@ -887,7 +697,9 @@ static int match_name_with_pattern(const char *key, const char *name, return ret; } -static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results) +static void query_refspecs_multiple(struct refspec *rs, + struct refspec_item *query, + struct string_list *results) { int i; int find_src = !query->src; @@ -895,8 +707,8 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct if (find_src && !query->dst) error("query_refspecs_multiple: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + 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; const char *needle = find_src ? query->dst : query->src; @@ -913,7 +725,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct } } -int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) +int query_refspecs(struct refspec *rs, struct refspec_item *query) { int i; int find_src = !query->src; @@ -923,8 +735,8 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) if (find_src && !query->dst) return error("query_refspecs: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + 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; @@ -944,23 +756,22 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) return -1; } -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name) +char *apply_refspecs(struct refspec *rs, const char *name) { - struct refspec query; + struct refspec_item query; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.src = (char *)name; - if (query_refspecs(refspecs, nr_refspec, &query)) + if (query_refspecs(rs, &query)) return NULL; return query.dst; } -int remote_find_tracking(struct remote *remote, struct refspec *refspec) +int remote_find_tracking(struct remote *remote, struct refspec_item *refspec) { - return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); + return query_refspecs(&remote->fetch, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen, @@ -1167,7 +978,7 @@ static char *guess_ref(const char *name, struct ref *peer) } static int match_explicit_lhs(struct ref *src, - struct refspec *rs, + struct refspec_item *rs, struct ref **match, int *allocated_match) { @@ -1193,7 +1004,7 @@ static int match_explicit_lhs(struct ref *src, static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, - struct refspec *rs) + struct refspec_item *rs) { struct ref *matched_src, *matched_dst; int allocated_src; @@ -1262,36 +1073,37 @@ static int match_explicit(struct ref *src, struct ref *dst, } static int match_explicit_refs(struct ref *src, struct ref *dst, - struct ref ***dst_tail, struct refspec *rs, - int rs_nr) + struct ref ***dst_tail, struct refspec *rs) { int i, errs; - for (i = errs = 0; i < rs_nr; i++) - errs += match_explicit(src, dst, dst_tail, &rs[i]); + for (i = errs = 0; i < rs->nr; i++) + errs += match_explicit(src, dst, dst_tail, &rs->items[i]); return errs; } -static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, - int send_mirror, int direction, const struct refspec **ret_pat) +static char *get_ref_match(const struct refspec *rs, const struct ref *ref, + int send_mirror, int direction, + const struct refspec_item **ret_pat) { - const struct refspec *pat; + const struct refspec_item *pat; char *name; int i; int matching_refs = -1; - for (i = 0; i < rs_nr; i++) { - if (rs[i].matching && - (matching_refs == -1 || rs[i].force)) { + for (i = 0; i < rs->nr; i++) { + const struct refspec_item *item = &rs->items[i]; + if (item->matching && + (matching_refs == -1 || item->force)) { matching_refs = i; continue; } - if (rs[i].pattern) { - const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; + if (item->pattern) { + const char *dst_side = item->dst ? item->dst : item->src; int match; if (direction == FROM_SRC) - match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name); + match = match_name_with_pattern(item->src, ref->name, dst_side, &name); else - match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name); + match = match_name_with_pattern(dst_side, ref->name, item->src, &name); if (match) { matching_refs = i; break; @@ -1301,7 +1113,7 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref if (matching_refs == -1) return NULL; - pat = rs + matching_refs; + pat = &rs->items[matching_refs]; if (pat->matching) { /* * "matching refs"; traditionally we pushed everything @@ -1443,22 +1255,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref) * but we can catch some errors early before even talking to the * remote side. */ -int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) +int check_push_refs(struct ref *src, struct refspec *rs) { - struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names); int ret = 0; int i; - for (i = 0; i < nr_refspec; i++) { - struct refspec *rs = refspec + i; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *item = &rs->items[i]; - if (rs->pattern || rs->matching) + if (item->pattern || item->matching) continue; - ret |= match_explicit_lhs(src, rs, NULL, NULL); + ret |= match_explicit_lhs(src, item, NULL, NULL); } - free_refspec(nr_refspec, refspec); return ret; } @@ -1471,32 +1281,29 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) * dst (e.g. pushing to a new branch, done in match_explicit_refs). */ int match_push_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int flags) + struct refspec *rs, int flags) { - struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; int send_prune = flags & MATCH_REFS_PRUNE; int errs; - static const char *default_refspec[] = { ":", NULL }; struct ref *ref, **dst_tail = tail_ref(dst); struct string_list dst_ref_index = STRING_LIST_INIT_NODUP; - if (!nr_refspec) { - nr_refspec = 1; - refspec = default_refspec; - } - rs = parse_push_refspec(nr_refspec, (const char **) refspec); - errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec); + /* If no refspec is provided, use the default ":" */ + if (!rs->nr) + refspec_append(rs, ":"); + + errs = match_explicit_refs(src, *dst, &dst_tail, rs); /* pick the remainder */ for (ref = src; ref; ref = ref->next) { struct string_list_item *dst_item; struct ref *dst_peer; - const struct refspec *pat = NULL; + const struct refspec_item *pat = NULL; char *dst_name; - dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat); + dst_name = get_ref_match(rs, ref, send_mirror, FROM_SRC, &pat); if (!dst_name) continue; @@ -1545,7 +1352,7 @@ int match_push_refs(struct ref *src, struct ref **dst, /* We're already sending something to this ref. */ continue; - src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL); + src_name = get_ref_match(rs, ref, send_mirror, FROM_DST, NULL); if (src_name) { if (!src_ref_index.nr) prepare_ref_index(&src_ref_index, src); @@ -1557,6 +1364,7 @@ int match_push_refs(struct ref *src, struct ref **dst, } string_list_clear(&src_ref_index, 0); } + if (errs) return -1; return 0; @@ -1753,7 +1561,7 @@ static const char *tracking_for_push_dest(struct remote *remote, { char *ret; - ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + ret = apply_refspecs(&remote->fetch, refname); if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"), @@ -1771,12 +1579,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err) _("branch '%s' has no remote for pushing"), branch->name); - if (remote->push_refspec_nr) { + if (remote->push.nr) { char *dst; const char *ret; - dst = apply_refspecs(remote->push, remote->push_refspec_nr, - branch->refname); + dst = apply_refspecs(&remote->push, branch->refname); if (!dst) return error_buf(err, _("push refspecs for '%s' do not include '%s'"), @@ -1849,7 +1656,7 @@ static int ignore_symref_update(const char *refname) * local symbolic ref. */ static struct ref *get_expanded_map(const struct ref *remote_refs, - const struct refspec *refspec) + const struct refspec_item *refspec) { const struct ref *ref; struct ref *ret = NULL; @@ -1914,7 +1721,7 @@ static struct ref *get_local_ref(const char *name) } int get_fetch_map(const struct ref *remote_refs, - const struct refspec *refspec, + const struct refspec_item *refspec, struct ref ***tail, int missing_ok) { @@ -2252,8 +2059,7 @@ struct ref *guess_remote_head(const struct ref *head, struct stale_heads_info { struct string_list *ref_names; struct ref **stale_refs_tail; - struct refspec *refs; - int ref_count; + struct refspec *rs; }; static int get_stale_heads_cb(const char *refname, const struct object_id *oid, @@ -2261,12 +2067,12 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid, { struct stale_heads_info *info = cb_data; struct string_list matches = STRING_LIST_INIT_DUP; - struct refspec query; + struct refspec_item query; int i, stale = 1; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.dst = (char *)refname; - query_refspecs_multiple(info->refs, info->ref_count, &query, &matches); + query_refspecs_multiple(info->rs, &query, &matches); if (matches.nr == 0) goto clean_exit; /* No matches */ @@ -2294,7 +2100,7 @@ clean_exit: return 0; } -struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map) +struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map) { struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; @@ -2302,8 +2108,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; - info.refs = refs; - info.ref_count = ref_count; + info.rs = rs; for (ref = fetch_map; ref; ref = ref->next) string_list_append(&ref_names, ref->name); string_list_sort(&ref_names); @@ -2387,7 +2192,7 @@ static int remote_tracking(struct remote *remote, const char *refname, { char *dst; - dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + dst = apply_refspecs(&remote->fetch, refname); if (!dst) return -1; /* no tracking ref for refname at remote */ if (read_ref(dst, oid)) @@ -3,6 +3,7 @@ #include "parse-options.h" #include "hashmap.h" +#include "refspec.h" enum { REMOTE_UNCONFIGURED = 0, @@ -27,15 +28,9 @@ struct remote { int pushurl_nr; int pushurl_alloc; - const char **push_refspec; - struct refspec *push; - int push_refspec_nr; - int push_refspec_alloc; + struct refspec push; - const char **fetch_refspec; - struct refspec *fetch; - int fetch_refspec_nr; - int fetch_refspec_alloc; + struct refspec fetch; /* * -1 to never fetch tags @@ -68,18 +63,6 @@ int for_each_remote(each_remote_fn fn, void *priv); int remote_has_url(struct remote *remote, const char *url); -struct refspec { - unsigned force : 1; - unsigned pattern : 1; - unsigned matching : 1; - unsigned exact_sha1 : 1; - - char *src; - char *dst; -}; - -extern const struct refspec *tag_refspec; - struct ref { struct ref *next; struct object_id old_oid; @@ -177,19 +160,12 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); */ struct ref *ref_remove_duplicates(struct ref *ref_map); -int valid_fetch_refspec(const char *refspec); -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); -extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); +int query_refspecs(struct refspec *rs, struct refspec_item *query); +char *apply_refspecs(struct refspec *rs, const char *name); -void free_refspec(int nr_refspec, struct refspec *refspec); - -extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query); -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name); - -int check_push_refs(struct ref *src, int nr_refspec, const char **refspec); +int check_push_refs(struct ref *src, struct refspec *rs); int match_push_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int all); + struct refspec *rs, int flags); void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, int force_update); @@ -205,7 +181,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, * missing_ok is usually false, but when we are adding branch.$name.merge * it is Ok if the branch is not at the remote anymore. */ -int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec, +int get_fetch_map(const struct ref *remote_refs, const struct refspec_item *refspec, struct ref ***tail, int missing_ok); struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); @@ -213,7 +189,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); /* * For the given remote, reads the refspec's src and sets the other fields. */ -int remote_find_tracking(struct remote *remote, struct refspec *refspec); +int remote_find_tracking(struct remote *remote, struct refspec_item *refspec); struct branch { const char *name; @@ -223,7 +199,7 @@ struct branch { const char *pushremote_name; const char **merge_name; - struct refspec **merge; + struct refspec_item **merge; int merge_nr; int merge_alloc; @@ -292,7 +268,7 @@ struct ref *guess_remote_head(const struct ref *head, int all); /* Return refs which no longer exist on remote */ -struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); +struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map); /* * Compare-and-swap @@ -315,8 +291,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int extern int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); -#define TAG_REFSPEC "refs/tags/*:refs/tags/*" - -void add_prune_tags_to_fetch_refspec(struct remote *remote); - #endif diff --git a/submodule.c b/submodule.c index 1f88623893..47d005797e 100644 --- a/submodule.c +++ b/submodule.c @@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits, static int push_submodule(const char *path, const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run) { @@ -991,8 +991,8 @@ static int push_submodule(const char *path, if (remote->origin != REMOTE_UNCONFIGURED) { int i; argv_array_push(&cp.args, remote->name); - for (i = 0; i < refspec_nr; i++) - argv_array_push(&cp.args, refspec[i]); + for (i = 0; i < rs->raw_nr; i++) + argv_array_push(&cp.args, rs->raw[i]); } prepare_submodule_repo_env(&cp.env_array); @@ -1013,7 +1013,7 @@ static int push_submodule(const char *path, */ static void submodule_push_check(const char *path, const char *head, const struct remote *remote, - const char **refspec, int refspec_nr) + const struct refspec *rs) { struct child_process cp = CHILD_PROCESS_INIT; int i; @@ -1023,8 +1023,8 @@ static void submodule_push_check(const char *path, const char *head, argv_array_push(&cp.args, head); argv_array_push(&cp.args, remote->name); - for (i = 0; i < refspec_nr; i++) - argv_array_push(&cp.args, refspec[i]); + for (i = 0; i < rs->raw_nr; i++) + argv_array_push(&cp.args, rs->raw[i]); prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; @@ -1043,7 +1043,7 @@ static void submodule_push_check(const char *path, const char *head, int push_unpushed_submodules(struct oid_array *commits, const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run) { @@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits, for (i = 0; i < needs_pushing.nr; i++) submodule_push_check(needs_pushing.items[i].string, - head, remote, - refspec, refspec_nr); + head, remote, rs); free(head); } @@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits, for (i = 0; i < needs_pushing.nr; i++) { const char *path = needs_pushing.items[i].string; fprintf(stderr, "Pushing submodule '%s'\n", path); - if (!push_submodule(path, remote, refspec, refspec_nr, + if (!push_submodule(path, remote, rs, push_options, dry_run)) { fprintf(stderr, "Unable to push submodule '%s'\n", path); ret = 0; diff --git a/submodule.h b/submodule.h index e5526f6aaa..aae0c9c8ff 100644 --- a/submodule.h +++ b/submodule.h @@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a, extern int find_unpushed_submodules(struct oid_array *commits, const char *remotes_name, struct string_list *needs_pushing); +struct refspec; extern int push_unpushed_submodules(struct oid_array *commits, const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run); /* diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh index 4ad5c5769b..a4fe6508bd 100755 --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@ -345,6 +345,20 @@ test_expect_success 'even with handcrafted request, filter does not work if not git -C server serve --stateless-rpc <in >/dev/null ' +test_expect_success 'default refspec is used to filter ref when fetchcing' ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \ + fetch origin && + + git -C file_child log -1 --format=%s three >actual && + git -C file_parent log -1 --format=%s three >expect && + test_cmp expect actual && + + grep "ref-prefix refs/heads/" log && + grep "ref-prefix refs/tags/" log +' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh diff --git a/transport-helper.c b/transport-helper.c index 11f1055b47..1f8ff7e942 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -11,6 +11,7 @@ #include "sigchain.h" #include "argv-array.h" #include "refs.h" +#include "refspec.h" #include "transport-internal.h" #include "protocol.h" @@ -35,8 +36,7 @@ struct helper_data { char *export_marks; char *import_marks; /* These go from remote name (as in "list") to private name */ - struct refspec *refspecs; - int refspec_nr; + struct refspec rs; /* Transport options for fetch-pack/send-pack (should one of * those be invoked). */ @@ -106,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport) struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; struct child_process *helper; - const char **refspecs = NULL; - int refspec_nr = 0; - int refspec_alloc = 0; int duped; int code; @@ -138,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport) data->helper = helper; data->no_disconnect_req = 0; + refspec_init(&data->rs, REFSPEC_FETCH); /* * Open the output as FILE* so strbuf_getline_*() family of @@ -183,11 +181,8 @@ static struct child_process *get_helper(struct transport *transport) data->export = 1; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity = 1; - else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { - ALLOC_GROW(refspecs, - refspec_nr + 1, - refspec_alloc); - refspecs[refspec_nr++] = xstrdup(arg); + else if (skip_prefix(capname, "refspec ", &arg)) { + refspec_append(&data->rs, arg); } else if (!strcmp(capname, "connect")) { data->connect = 1; } else if (!strcmp(capname, "stateless-connect")) { @@ -206,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport) capname); } } - if (refspecs) { - int i; - data->refspec_nr = refspec_nr; - data->refspecs = parse_fetch_refspec(refspec_nr, refspecs); - for (i = 0; i < refspec_nr; i++) - free((char *)refspecs[i]); - free(refspecs); - } else if (data->import || data->bidi_import || data->export) { + if (!data->rs.nr && (data->import || data->bidi_import || data->export)) { warning("This remote helper should implement refspec capability."); } strbuf_release(&buf); @@ -377,8 +365,7 @@ static int release_helper(struct transport *transport) { int res = 0; struct helper_data *data = transport->data; - free_refspec(data->refspec_nr, data->refspecs); - data->refspecs = NULL; + refspec_clear(&data->rs); res = disconnect_helper(transport); free(transport->data); return res; @@ -535,8 +522,8 @@ static int fetch_with_import(struct transport *transport, if (posn->status & REF_STATUS_UPTODATE) continue; name = posn->symref ? posn->symref : posn->name; - if (data->refspecs) - private = apply_refspecs(data->refspecs, data->refspec_nr, name); + if (data->rs.nr) + private = apply_refspecs(&data->rs, name); else private = xstrdup(name); if (private) { @@ -814,11 +801,11 @@ static int push_update_refs_status(struct helper_data *data, if (push_update_ref_status(&buf, &ref, remote_refs)) continue; - if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update) + if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update) continue; /* propagate back the update to the remote namespace */ - private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name); + private = apply_refspecs(&data->rs, ref->name); if (!private) continue; update_ref("update by helper", private, &ref->new_oid, NULL, @@ -938,7 +925,7 @@ static int push_refs_with_export(struct transport *transport, struct string_list revlist_args = STRING_LIST_INIT_DUP; struct strbuf buf = STRBUF_INIT; - if (!data->refspecs) + if (!data->rs.nr) die("remote-helper doesn't support push; refspec needed"); set_common_push_options(transport, data->name, flags); @@ -955,7 +942,7 @@ static int push_refs_with_export(struct transport *transport, char *private; struct object_id oid; - private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name); + private = apply_refspecs(&data->rs, ref->name); if (private && !get_oid(private, &oid)) { strbuf_addf(&buf, "^%s", private); string_list_append_nodup(&revlist_args, diff --git a/transport.c b/transport.c index 6785fcceed..a32da30dee 100644 --- a/transport.c +++ b/transport.c @@ -11,6 +11,7 @@ #include "bundle.h" #include "dir.h" #include "refs.h" +#include "refspec.h" #include "branch.h" #include "url.h" #include "submodule.h" @@ -390,7 +391,7 @@ int transport_refs_pushed(struct ref *ref) void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) { - struct refspec rs; + struct refspec_item rs; if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) return; @@ -619,29 +620,6 @@ void transport_print_push_status(const char *dest, struct ref *refs, free(head); } -void transport_verify_remote_names(int nr_heads, const char **heads) -{ - int i; - - for (i = 0; i < nr_heads; i++) { - const char *local = heads[i]; - const char *remote = strrchr(heads[i], ':'); - - if (*local == '+') - local++; - - /* A matching refspec is okay. */ - if (remote == local && remote[1] == '\0') - continue; - - remote = remote ? (remote + 1) : local; - if (check_refname_format(remote, - REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN)) - die("remote part of refspec is not a valid name in %s", - heads[i]); - } -} - static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags) { struct git_transport_data *data = transport->data; @@ -1093,11 +1071,10 @@ static int run_pre_push_hook(struct transport *transport, } int transport_push(struct transport *transport, - int refspec_nr, const char **refspec, int flags, + struct refspec *rs, int flags, unsigned int *reject_reasons) { *reject_reasons = 0; - transport_verify_remote_names(refspec_nr, refspec); if (transport_color_config() < 0) return -1; @@ -1111,38 +1088,17 @@ int transport_push(struct transport *transport, int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int push_ret, ret, err; - struct refspec *tmp_rs; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; - int i; - if (check_push_refs(local_refs, refspec_nr, refspec) < 0) + if (check_push_refs(local_refs, rs) < 0) return -1; - tmp_rs = parse_push_refspec(refspec_nr, refspec); - for (i = 0; i < refspec_nr; i++) { - const char *prefix = NULL; - - if (tmp_rs[i].dst) - prefix = tmp_rs[i].dst; - else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1) - prefix = tmp_rs[i].src; - - if (prefix) { - const char *glob = strchr(prefix, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - prefix), - prefix); - else - expand_ref_prefix(&ref_prefixes, prefix); - } - } + refspec_ref_prefixes(rs, &ref_prefixes); remote_refs = transport->vtable->get_refs_list(transport, 1, &ref_prefixes); argv_array_clear(&ref_prefixes); - free_refspec(refspec_nr, tmp_rs); if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; @@ -1153,10 +1109,8 @@ int transport_push(struct transport *transport, if (flags & TRANSPORT_PUSH_FOLLOW_TAGS) match_flags |= MATCH_REFS_FOLLOW_TAGS; - if (match_push_refs(local_refs, &remote_refs, - refspec_nr, refspec, match_flags)) { + if (match_push_refs(local_refs, &remote_refs, rs, match_flags)) return -1; - } if (transport->smart_options && transport->smart_options->cas && @@ -1185,7 +1139,7 @@ int transport_push(struct transport *transport, if (!push_unpushed_submodules(&commits, transport->remote, - refspec, refspec_nr, + rs, transport->push_options, pretend)) { oid_array_clear(&commits); diff --git a/transport.h b/transport.h index 73a7be3c8a..7792b08582 100644 --- a/transport.h +++ b/transport.h @@ -203,7 +203,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity, #define REJECT_NEEDS_FORCE 0x10 int transport_push(struct transport *connection, - int refspec_nr, const char **refspec, int flags, + struct refspec *rs, int flags, unsigned int * reject_reasons); /* @@ -233,8 +233,6 @@ int transport_helper_init(struct transport *transport, const char *name); int bidirectional_transfer_loop(int input, int output); /* common methods used by transport.c and builtin/send-pack.c */ -void transport_verify_remote_names(int nr_heads, const char **heads); - void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose); int transport_refs_pushed(struct ref *ref); |