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
  ...
This commit is contained in:
Junio C Hamano 2018-05-30 21:51:26 +09:00
commit e12cbeaa62
23 changed files with 568 additions and 611 deletions

View File

@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
LIB_OBJS += refs/iterator.o LIB_OBJS += refs/iterator.o
LIB_OBJS += refs/packed-backend.o LIB_OBJS += refs/packed-backend.o
LIB_OBJS += refs/ref-cache.o LIB_OBJS += refs/ref-cache.o
LIB_OBJS += refspec.o
LIB_OBJS += ref-filter.o LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o LIB_OBJS += remote.o
LIB_OBJS += replace-object.o LIB_OBJS += replace-object.o

View File

@ -3,12 +3,13 @@
#include "config.h" #include "config.h"
#include "branch.h" #include "branch.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "remote.h" #include "remote.h"
#include "commit.h" #include "commit.h"
#include "worktree.h" #include "worktree.h"
struct tracking { struct tracking {
struct refspec spec; struct refspec_item spec;
char *src; char *src;
const char *remote; const char *remote;
int matches; 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) static int check_tracking_branch(struct remote *remote, void *cb_data)
{ {
char *tracking_branch = cb_data; char *tracking_branch = cb_data;
struct refspec query; struct refspec_item query;
memset(&query, 0, sizeof(struct refspec)); memset(&query, 0, sizeof(struct refspec_item));
query.dst = tracking_branch; query.dst = tracking_branch;
return !remote_find_tracking(remote, &query); return !remote_find_tracking(remote, &query);
} }

View File

@ -14,6 +14,7 @@
#include "parse-options.h" #include "parse-options.h"
#include "fetch-pack.h" #include "fetch-pack.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "tree.h" #include "tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "unpack-trees.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, 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 *head = copy_ref(find_ref_by_name(refs, "HEAD"));
struct ref *local_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 err = 0, complete_refs_before_fetch = 1;
int submodule_progress; int submodule_progress;
struct refspec *refspec; struct refspec_item refspec;
const char *fetch_pattern;
fetch_if_missing = 0; 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) if (option_required_reference.nr || option_optional_reference.nr)
setup_reference(); setup_reference();
fetch_pattern = value.buf; refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
refspec = parse_fetch_refspec(1, &fetch_pattern);
strbuf_reset(&value); 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); refs = transport_get_remote_refs(transport, NULL);
if (refs) { 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 * transport_get_remote_refs() may return refs with null sha-1
* in mapped_refs (see struct transport->get_refs_list * 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); strbuf_release(&value);
junk_mode = JUNK_LEAVE_ALL; junk_mode = JUNK_LEAVE_ALL;
free(refspec); refspec_item_clear(&refspec);
return err; return err;
} }

View File

@ -7,6 +7,7 @@
#include "cache.h" #include "cache.h"
#include "config.h" #include "config.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "commit.h" #include "commit.h"
#include "object.h" #include "object.h"
#include "tag.h" #include "tag.h"
@ -35,8 +36,7 @@ static int use_done_feature;
static int no_data; static int no_data;
static int full_tree; static int full_tree;
static struct string_list extra_refs = STRING_LIST_INIT_NODUP; static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
static struct refspec *refspecs; static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int refspecs_nr;
static int anonymize; static int anonymize;
static int parse_opt_signed_tag_mode(const struct option *opt, 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) if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
continue; continue;
if (refspecs) { if (refspecs.nr) {
char *private; char *private;
private = apply_refspecs(refspecs, refspecs_nr, full_name); private = apply_refspecs(&refspecs, full_name);
if (private) { if (private) {
free(full_name); free(full_name);
full_name = private; full_name = private;
@ -976,8 +976,8 @@ static void import_marks(char *input_file)
static void handle_deletes(void) static void handle_deletes(void)
{ {
int i; int i;
for (i = 0; i < refspecs_nr; i++) { for (i = 0; i < refspecs.nr; i++) {
struct refspec *refspec = &refspecs[i]; struct refspec_item *refspec = &refspecs.items[i];
if (*refspec->src) if (*refspec->src)
continue; continue;
@ -1038,18 +1038,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
usage_with_options (fast_export_usage, options); usage_with_options (fast_export_usage, options);
if (refspecs_list.nr) { if (refspecs_list.nr) {
const char **refspecs_str;
int i; int i;
ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
for (i = 0; i < refspecs_list.nr; i++) for (i = 0; i < refspecs_list.nr; i++)
refspecs_str[i] = refspecs_list.items[i].string; refspec_append(&refspecs, refspecs_list.items[i].string);
refspecs_nr = refspecs_list.nr;
refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
string_list_clear(&refspecs_list, 1); string_list_clear(&refspecs_list, 1);
free(refspecs_str);
} }
if (use_done_feature) if (use_done_feature)
@ -1088,7 +1082,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
if (use_done_feature) if (use_done_feature)
printf("done\n"); printf("done\n");
free_refspec(refspecs_nr, refspecs); refspec_clear(&refspecs);
return 0; return 0;
} }

View File

@ -5,6 +5,7 @@
#include "config.h" #include "config.h"
#include "repository.h" #include "repository.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "commit.h" #include "commit.h"
#include "builtin.h" #include "builtin.h"
#include "string-list.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 = RECURSE_SUBMODULES_DEFAULT;
static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
static int shown_url = 0; static int shown_url = 0;
static int refmap_alloc, refmap_nr; static struct refspec refmap = REFSPEC_INIT_FETCH;
static const char **refmap_array;
static struct list_objects_filter_options filter_options; static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP; 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) 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" * "git fetch --refmap='' origin foo"
* can be used to tell the command not to store anywhere * can be used to tell the command not to store anywhere
*/ */
if (*arg) refspec_append(&refmap, arg);
refmap_array[refmap_nr++] = arg;
return 0; return 0;
} }
@ -204,7 +202,7 @@ static void add_merge_config(struct ref **head,
for (i = 0; i < branch->merge_nr; i++) { for (i = 0; i < branch->merge_nr; i++) {
struct ref *rm, **old_tail = *tail; struct ref *rm, **old_tail = *tail;
struct refspec refspec; struct refspec_item refspec;
for (rm = *head; rm; rm = rm->next) { for (rm = *head; rm; rm = rm->next) {
if (branch_merge_matches(branch, i, rm->name)) { 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, static struct ref *get_ref_map(struct transport *transport,
struct refspec *refspecs, int refspec_count, struct refspec *rs,
int tags, int *autotags) int tags, int *autotags)
{ {
int i; int i;
@ -355,29 +353,26 @@ static struct ref *get_ref_map(struct transport *transport,
const struct ref *remote_refs; const struct ref *remote_refs;
for (i = 0; i < refspec_count; i++) { if (rs->nr)
if (!refspecs[i].exact_sha1) { refspec_ref_prefixes(rs, &ref_prefixes);
const char *glob = strchr(refspecs[i].src, '*'); else if (transport->remote && transport->remote->fetch.nr)
if (glob) refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
argv_array_pushf(&ref_prefixes, "%.*s",
(int)(glob - refspecs[i].src), if (ref_prefixes.argc &&
refspecs[i].src); (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
else argv_array_push(&ref_prefixes, "refs/tags/");
expand_ref_prefix(&ref_prefixes, refspecs[i].src);
}
} }
remote_refs = transport_get_remote_refs(transport, &ref_prefixes); remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
argv_array_clear(&ref_prefixes); argv_array_clear(&ref_prefixes);
if (refspec_count) { if (rs->nr) {
struct refspec *fetch_refspec; struct refspec *fetch_refspec;
int fetch_refspec_nr;
for (i = 0; i < refspec_count; i++) { for (i = 0; i < rs->nr; i++) {
get_fetch_map(remote_refs, &refspecs[i], &tail, 0); get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
if (refspecs[i].dst && refspecs[i].dst[0]) if (rs->items[i].dst && rs->items[i].dst[0])
*autotags = 1; *autotags = 1;
} }
/* Merge everything on the command line (but not --tags) */ /* 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 * by ref_remove_duplicates() in favor of one of these
* opportunistic entries with FETCH_HEAD_IGNORE. * opportunistic entries with FETCH_HEAD_IGNORE.
*/ */
if (refmap_array) { if (refmap.nr)
fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array); fetch_refspec = &refmap;
fetch_refspec_nr = refmap_nr; else
} else { fetch_refspec = &transport->remote->fetch;
fetch_refspec = transport->remote->fetch;
fetch_refspec_nr = transport->remote->fetch_refspec_nr;
}
for (i = 0; i < fetch_refspec_nr; i++) for (i = 0; i < fetch_refspec->nr; i++)
get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1); get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
} else if (refmap_array) { } else if (refmap.nr) {
die("--refmap option is only meaningful with command-line refspec(s)."); die("--refmap option is only meaningful with command-line refspec(s).");
} else { } else {
/* Use the defaults */ /* Use the defaults */
@ -422,16 +414,16 @@ static struct ref *get_ref_map(struct transport *transport,
struct branch *branch = branch_get(NULL); struct branch *branch = branch_get(NULL);
int has_merge = branch_has_merge_config(branch); int has_merge = branch_has_merge_config(branch);
if (remote && if (remote &&
(remote->fetch_refspec_nr || (remote->fetch.nr ||
/* Note: has_merge implies non-NULL branch->remote_name */ /* Note: has_merge implies non-NULL branch->remote_name */
(has_merge && !strcmp(branch->remote_name, remote->name)))) { (has_merge && !strcmp(branch->remote_name, remote->name)))) {
for (i = 0; i < remote->fetch_refspec_nr; i++) { for (i = 0; i < remote->fetch.nr; i++) {
get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0); get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
if (remote->fetch[i].dst && if (remote->fetch.items[i].dst &&
remote->fetch[i].dst[0]) remote->fetch.items[i].dst[0])
*autotags = 1; *autotags = 1;
if (!i && !has_merge && ref_map && if (!i && !has_merge && ref_map &&
!remote->fetch[0].pattern) !remote->fetch.items[0].pattern)
ref_map->fetch_head_status = FETCH_HEAD_MERGE; 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; return ret;
} }
static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map, static int prune_refs(struct refspec *rs, struct ref *ref_map,
const char *raw_url) const char *raw_url)
{ {
int url_len, i, result = 0; 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; char *url;
int summary_width = transport_summary_width(stale_refs); int summary_width = transport_summary_width(stale_refs);
const char *dangling_msg = dry_run 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, 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 string_list existing_refs = STRING_LIST_INIT_DUP;
struct ref *ref_map; struct ref *ref_map;
@ -1140,7 +1132,7 @@ static int do_fetch(struct transport *transport,
goto cleanup; 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) if (!update_head_ok)
check_not_current_branch(ref_map); check_not_current_branch(ref_map);
@ -1164,11 +1156,10 @@ static int do_fetch(struct transport *transport,
* explicitly (via command line or configuration); we * explicitly (via command line or configuration); we
* don't care whether --tags was specified. * don't care whether --tags was specified.
*/ */
if (ref_count) { if (rs->nr) {
prune_refs(refs, ref_count, ref_map, transport->url); prune_refs(rs, ref_map, transport->url);
} else { } else {
prune_refs(transport->remote->fetch, prune_refs(&transport->remote->fetch,
transport->remote->fetch_refspec_nr,
ref_map, ref_map,
transport->url); 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 int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
{ {
static const char **refs = NULL; struct refspec rs = REFSPEC_INIT_FETCH;
struct refspec *refspec; int i;
int ref_nr = 0;
int j = 0;
int exit_code; int exit_code;
int maybe_prune_tags; int maybe_prune_tags;
int remote_via_config = remote_is_configured(remote, 0); 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; maybe_prune_tags = prune_tags_ok && prune_tags;
if (maybe_prune_tags && remote_via_config) if (maybe_prune_tags && remote_via_config)
add_prune_tags_to_fetch_refspec(remote); refspec_append(&remote->fetch, TAG_REFSPEC);
if (argc > 0 || (maybe_prune_tags && !remote_via_config)) { if (maybe_prune_tags && (argc || !remote_via_config))
size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1); refspec_append(&rs, TAG_REFSPEC);
refs = xcalloc(nr_alloc, sizeof(const char *));
if (maybe_prune_tags) {
refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
ref_nr++;
}
}
if (argc > 0) { for (i = 0; i < argc; i++) {
int i; if (!strcmp(argv[i], "tag")) {
for (i = 0; i < argc; i++) { char *tag;
if (!strcmp(argv[i], "tag")) { i++;
i++; if (i >= argc)
if (i >= argc) die(_("You need to specify a tag name."));
die(_("You need to specify a tag name."));
refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s", tag = xstrfmt("refs/tags/%s:refs/tags/%s",
argv[i], argv[i]); argv[i], argv[i]);
} else refspec_append(&rs, tag);
refs[j++] = argv[i]; free(tag);
ref_nr++; } 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); sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack); atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs); exit_code = do_fetch(gtransport, &rs);
exit_code = do_fetch(gtransport, refspec, ref_nr); refspec_clear(&rs);
free_refspec(ref_nr, refspec);
transport_disconnect(gtransport); transport_disconnect(gtransport);
gtransport = NULL; gtransport = NULL;
return exit_code; return exit_code;

View File

@ -14,6 +14,7 @@
#include "run-command.h" #include "run-command.h"
#include "diff.h" #include "diff.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "commit.h" #include "commit.h"
#include "diffcore.h" #include "diffcore.h"
#include "revision.h" #include "revision.h"

View File

@ -15,6 +15,7 @@
#include "remote.h" #include "remote.h"
#include "dir.h" #include "dir.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "revision.h" #include "revision.h"
#include "submodule.h" #include "submodule.h"
#include "submodule-config.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) 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 *spec_src;
const char *merge_branch; const char *merge_branch;
spec = parse_fetch_refspec(1, &refspec); refspec_item_init(&spec, refspec, REFSPEC_FETCH);
spec_src = spec->src; spec_src = spec.src;
if (!*spec_src || !strcmp(spec_src, "HEAD")) if (!*spec_src || !strcmp(spec_src, "HEAD"))
spec_src = "HEAD"; spec_src = "HEAD";
else if (skip_prefix(spec_src, "heads/", &spec_src)) 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 } else
merge_branch = NULL; merge_branch = NULL;
free_refspec(1, spec); refspec_item_clear(&spec);
return merge_branch; return merge_branch;
} }

View File

@ -4,6 +4,7 @@
#include "cache.h" #include "cache.h"
#include "config.h" #include "config.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "run-command.h" #include "run-command.h"
#include "builtin.h" #include "builtin.h"
#include "remote.h" #include "remote.h"
@ -56,19 +57,10 @@ static enum transport_family family;
static struct push_cas_option cas; static struct push_cas_option cas;
static const char **refspec; static struct refspec rs = REFSPEC_INIT_PUSH;
static int refspec_nr;
static int refspec_alloc;
static struct string_list push_options_config = STRING_LIST_INIT_DUP; 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, static const char *map_refspec(const char *ref,
struct remote *remote, struct ref *local_refs) 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) if (count_refspec_match(ref, local_refs, &matched) != 1)
return ref; return ref;
if (remote->push) { if (remote->push.nr) {
struct refspec query; struct refspec_item query;
memset(&query, 0, sizeof(struct refspec)); memset(&query, 0, sizeof(struct refspec_item));
query.src = matched->name; query.src = matched->name;
if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) && if (!query_refspecs(&remote->push, &query) && query.dst) {
query.dst) {
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%s%s:%s", strbuf_addf(&buf, "%s%s:%s",
query.force ? "+" : "", 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); 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); 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) 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) if (!branch)
die(_(message_detached_head_die), remote->name); die(_(message_detached_head_die), remote->name);
strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname); 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) static int is_workflow_triangular(struct remote *remote)
@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)
switch (push_default) { switch (push_default) {
default: default:
case PUSH_DEFAULT_MATCHING: case PUSH_DEFAULT_MATCHING:
add_refspec(":"); refspec_append(&rs, ":");
break; break;
case PUSH_DEFAULT_UNSPECIFIED: case PUSH_DEFAULT_UNSPECIFIED:
@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)
advise(_(message_advice_ref_needs_force)); 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; int err;
unsigned int reject_reasons; unsigned int reject_reasons;
@ -363,8 +355,7 @@ static int push_with_options(struct transport *transport, int flags)
if (verbosity > 0) if (verbosity > 0)
fprintf(stderr, _("Pushing to %s\n"), transport->url); fprintf(stderr, _("Pushing to %s\n"), transport->url);
err = transport_push(transport, refspec_nr, refspec, flags, err = transport_push(transport, rs, flags, &reject_reasons);
&reject_reasons);
if (err != 0) { if (err != 0) {
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR)); fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
error(_("failed to push some refs to '%s'"), transport->url); 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); struct remote *remote = pushremote_get(repo);
const char **url; const char **url;
int url_nr; int url_nr;
struct refspec *push_refspec = &rs;
if (!remote) { if (!remote) {
if (repo) if (repo)
@ -417,27 +409,9 @@ static int do_push(const char *repo, int flags,
if (push_options->nr) if (push_options->nr)
flags |= TRANSPORT_PUSH_OPTIONS; flags |= TRANSPORT_PUSH_OPTIONS;
if ((flags & TRANSPORT_PUSH_ALL) && refspec) { if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) {
if (!strcmp(*refspec, "refs/tags/*")) if (remote->push.nr) {
return error(_("--all and --tags are incompatible")); push_refspec = &remote->push;
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;
} else if (!(flags & TRANSPORT_PUSH_MIRROR)) } else if (!(flags & TRANSPORT_PUSH_MIRROR))
setup_default_push_refspecs(remote); setup_default_push_refspecs(remote);
} }
@ -449,7 +423,7 @@ static int do_push(const char *repo, int flags,
transport_get(remote, url[i]); transport_get(remote, url[i]);
if (flags & TRANSPORT_PUSH_OPTIONS) if (flags & TRANSPORT_PUSH_OPTIONS)
transport->push_options = push_options; transport->push_options = push_options;
if (push_with_options(transport, flags)) if (push_with_options(transport, push_refspec, flags))
errs++; errs++;
} }
} else { } else {
@ -457,7 +431,7 @@ static int do_push(const char *repo, int flags,
transport_get(remote, NULL); transport_get(remote, NULL);
if (flags & TRANSPORT_PUSH_OPTIONS) if (flags & TRANSPORT_PUSH_OPTIONS)
transport->push_options = push_options; transport->push_options = push_options;
if (push_with_options(transport, flags)) if (push_with_options(transport, push_refspec, flags))
errs++; errs++;
} }
return !!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")); die(_("--delete is incompatible with --all, --mirror and --tags"));
if (deleterefs && argc < 2) if (deleterefs && argc < 2)
die(_("--delete doesn't make sense without any refs")); 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) if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
flags |= TRANSPORT_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; flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
if (tags) if (tags)
add_refspec("refs/tags/*"); refspec_append(&rs, "refs/tags/*");
if (argc > 0) { if (argc > 0) {
repo = argv[0]; repo = argv[0];

View File

@ -7,6 +7,7 @@
#include "strbuf.h" #include "strbuf.h"
#include "run-command.h" #include "run-command.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "argv-array.h" #include "argv-array.h"
static const char * const builtin_remote_usage[] = { 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; struct ref *ref, *stale_refs;
int i; int i;
for (i = 0; i < states->remote->fetch_refspec_nr; i++) for (i = 0; i < states->remote->fetch.nr; i++)
if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1)) if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
die(_("Could not get fetch map for refspec %s"), 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->new_refs.strdup_strings = 1;
states->tracked.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 else
string_list_append(&states->tracked, abbrev_branch(ref->name)); string_list_append(&states->tracked, abbrev_branch(ref->name));
} }
stale_refs = get_stale_heads(states->remote->fetch, stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
states->remote->fetch_refspec_nr, fetch_map);
for (ref = stale_refs; ref; ref = ref->next) { for (ref = stale_refs; ref; ref = ref->next) {
struct string_list_item *item = struct string_list_item *item =
string_list_append(&states->stale, abbrev_branch(ref->name)); 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(); local_refs = get_local_heads();
push_map = copy_ref_list(remote_refs); push_map = copy_ref_list(remote_refs);
match_push_refs(local_refs, &push_map, remote->push_refspec_nr, match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
remote->push_refspec, MATCH_REFS_NONE);
states->push.strdup_strings = 1; states->push.strdup_strings = 1;
for (ref = push_map; ref; ref = ref->next) { 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; return 0;
states->push.strdup_strings = 1; states->push.strdup_strings = 1;
if (!remote->push_refspec_nr) { if (!remote->push.nr) {
item = string_list_append(&states->push, _("(matching)")); item = string_list_append(&states->push, _("(matching)"));
info = item->util = xcalloc(1, sizeof(struct push_info)); info = item->util = xcalloc(1, sizeof(struct push_info));
info->status = PUSH_STATUS_NOTQUERIED; info->status = PUSH_STATUS_NOTQUERIED;
info->dest = xstrdup(item->string); info->dest = xstrdup(item->string);
} }
for (i = 0; i < remote->push_refspec_nr; i++) { for (i = 0; i < remote->push.nr; i++) {
struct refspec *spec = remote->push + i; const struct refspec_item *spec = &remote->push.items[i];
if (spec->matching) if (spec->matching)
item = string_list_append(&states->push, _("(matching)")); item = string_list_append(&states->push, _("(matching)"));
else if (strlen(spec->src)) 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 *ref, *matches;
struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
struct refspec refspec; struct refspec_item refspec;
refspec.force = 0; refspec.force = 0;
refspec.pattern = 1; 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) const struct object_id *oid, int flags, void *cb_data)
{ {
struct branches_for_remote *branches = cb_data; struct branches_for_remote *branches = cb_data;
struct refspec refspec; struct refspec_item refspec;
struct known_remote *kr; struct known_remote *kr;
memset(&refspec, 0, sizeof(refspec)); 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); git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.push", remote->name); strbuf_addf(&buf, "remote.%s.push", remote->name);
for (i = 0; i < remote->push_refspec_nr; i++) for (i = 0; i < remote->push.raw_nr; i++)
git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0); git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
strbuf_reset(&buf); strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", remote->name); strbuf_addf(&buf, "remote.%s.fetch", remote->name);
for (i = 0; i < remote->fetch_refspec_nr; i++) for (i = 0; i < remote->fetch.raw_nr; i++)
git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0); git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
if (remote->origin == REMOTE_REMOTES) if (remote->origin == REMOTE_REMOTES)
unlink_or_warn(git_path("remotes/%s", remote->name)); unlink_or_warn(git_path("remotes/%s", remote->name));
else if (remote->origin == REMOTE_BRANCHES) 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); strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
git_config_set_multivar(buf.buf, NULL, NULL, 1); git_config_set_multivar(buf.buf, NULL, NULL, 1);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); 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; char *ptr;
strbuf_reset(&buf2); 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); ptr = strstr(buf2.buf, old_remote_context.buf);
if (ptr) { if (ptr) {
refspec_updated = 1; 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) const struct object_id *oid, int flags, void *cb_data)
{ {
struct ref_states *states = cb_data; struct ref_states *states = cb_data;
struct refspec refspec; struct refspec_item refspec;
if (flags & REF_ISSYMREF) if (flags & REF_ISSYMREF)
return 0; return 0;

View File

@ -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 cmd_send_pack(int argc, const char **argv, const char *prefix)
{ {
int i, nr_refspecs = 0; struct refspec rs = REFSPEC_INIT_PUSH;
const char **refspecs = NULL;
const char *remote_name = NULL; const char *remote_name = NULL;
struct remote *remote = NULL; struct remote *remote = NULL;
const char *dest = 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); argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
if (argc > 0) { if (argc > 0) {
dest = argv[0]; dest = argv[0];
refspecs = (const char **)(argv + 1); refspec_appendn(&rs, argv + 1, argc - 1);
nr_refspecs = argc - 1;
} }
if (!dest) 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; args.push_options = push_options.nr ? &push_options : NULL;
if (from_stdin) { 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) { if (args.stateless_rpc) {
const char *buf; const char *buf;
while ((buf = packet_read_line(0, NULL))) while ((buf = packet_read_line(0, NULL)))
argv_array_push(&all_refspecs, buf); refspec_append(&rs, buf);
} else { } else {
struct strbuf line = STRBUF_INIT; struct strbuf line = STRBUF_INIT;
while (strbuf_getline(&line, stdin) != EOF) while (strbuf_getline(&line, stdin) != EOF)
argv_array_push(&all_refspecs, line.buf); refspec_append(&rs, line.buf);
strbuf_release(&line); strbuf_release(&line);
} }
refspecs = all_refspecs.argv;
nr_refspecs = all_refspecs.argc;
} }
/* /*
* --all and --mirror are incompatible; neither makes sense * --all and --mirror are incompatible; neither makes sense
* with any refspecs. * 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)) (send_all && args.send_mirror))
usage_with_options(send_pack_usage, options); 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"); BUG("unknown protocol version");
} }
transport_verify_remote_names(nr_refspecs, refspecs);
local_refs = get_local_heads(); local_refs = get_local_heads();
flags = MATCH_REFS_NONE; flags = MATCH_REFS_NONE;
@ -287,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
flags |= MATCH_REFS_MIRROR; flags |= MATCH_REFS_MIRROR;
/* match them up */ /* 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; return -1;
if (!is_empty_cas(&cas)) if (!is_empty_cas(&cas))

View File

@ -12,6 +12,7 @@
#include "run-command.h" #include "run-command.h"
#include "remote.h" #include "remote.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "connect.h" #include "connect.h"
#include "revision.h" #include "revision.h"
#include "diffcore.h" #include "diffcore.h"
@ -1753,13 +1754,14 @@ static int push_check(int argc, const char **argv, const char *prefix)
/* Check the refspec */ /* Check the refspec */
if (argc > 2) { if (argc > 2) {
int i, refspec_nr = argc - 2; int i;
struct ref *local_refs = get_local_heads(); struct ref *local_refs = get_local_heads();
struct refspec *refspec = parse_push_refspec(refspec_nr, struct refspec refspec = REFSPEC_INIT_PUSH;
argv + 2);
for (i = 0; i < refspec_nr; i++) { refspec_appendn(&refspec, argv + 2, argc - 2);
struct refspec *rs = refspec + i;
for (i = 0; i < refspec.nr; i++) {
const struct refspec_item *rs = &refspec.items[i];
if (rs->pattern || rs->matching) if (rs->pattern || rs->matching)
continue; continue;
@ -1786,7 +1788,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
rs->src); rs->src);
} }
} }
free_refspec(refspec_nr, refspec); refspec_clear(&refspec);
} }
free(head); free(head);

View File

@ -1,5 +1,6 @@
#include "cache.h" #include "cache.h"
#include "remote.h" #include "remote.h"
#include "refspec.h"
#include "checkout.h" #include "checkout.h"
struct tracking_name_data { struct tracking_name_data {
@ -12,8 +13,8 @@ struct tracking_name_data {
static int check_tracking_name(struct remote *remote, void *cb_data) static int check_tracking_name(struct remote *remote, void *cb_data)
{ {
struct tracking_name_data *cb = cb_data; struct tracking_name_data *cb = cb_data;
struct refspec query; struct refspec_item query;
memset(&query, 0, sizeof(struct refspec)); memset(&query, 0, sizeof(struct refspec_item));
query.src = cb->src_ref; query.src = cb->src_ref;
if (remote_find_tracking(remote, &query) || if (remote_find_tracking(remote, &query) ||
get_oid(query.dst, cb->dst_oid)) { get_oid(query.dst, cb->dst_oid)) {

View File

@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv)
{ {
struct transfer_request *request; struct transfer_request *request;
struct transfer_request *next_request; struct transfer_request *next_request;
int nr_refspec = 0; struct refspec rs = REFSPEC_INIT_PUSH;
const char **refspec = NULL;
struct remote_lock *ref_lock = NULL; struct remote_lock *ref_lock = NULL;
struct remote_lock *info_ref_lock = NULL; struct remote_lock *info_ref_lock = NULL;
struct rev_info revs; struct rev_info revs;
@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv)
} }
continue; continue;
} }
refspec = argv; refspec_appendn(&rs, argv, argc - i);
nr_refspec = argc - i;
break; break;
} }
@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv)
if (!repo->url) if (!repo->url)
usage(http_push_usage); 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"); die("You must specify only one branch name when deleting a remote branch");
setup_git_directory(); 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 */ /* Remove a remote branch if -d or -D was specified */
if (delete_branch) { 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", fprintf(stderr, "Unable to delete remote branch %s\n",
refspec[0]); branch);
if (helper_status) if (helper_status)
printf("error %s cannot remove\n", refspec[0]); printf("error %s cannot remove\n", branch);
} }
goto cleanup; goto cleanup;
} }
/* match them up */ /* match them up */
if (match_push_refs(local_refs, &remote_refs, if (match_push_refs(local_refs, &remote_refs, &rs, push_all)) {
nr_refspec, (const char **) refspec, push_all)) {
rc = -1; rc = -1;
goto cleanup; goto cleanup;
} }

223
refspec.c Normal file
View File

@ -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);
}
}
}
}

48
refspec.h Normal file
View File

@ -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 */

353
remote.c
View File

@ -2,6 +2,7 @@
#include "config.h" #include "config.h"
#include "remote.h" #include "remote.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "commit.h" #include "commit.h"
#include "diff.h" #include "diff.h"
#include "revision.h" #include "revision.h"
@ -13,18 +14,6 @@
enum map_direction { FROM_SRC, FROM_DST }; 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 { struct counted_string {
size_t len; size_t len;
const char *s; 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); 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) static void add_url(struct remote *remote, const char *url)
{ {
ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); 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 = xcalloc(1, sizeof(struct remote));
ret->prune = -1; /* unspecified */ ret->prune = -1; /* unspecified */
ret->prune_tags = -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); ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
remotes[remotes_nr++] = ret; remotes[remotes_nr++] = ret;
ret->name = xstrndup(name, len);
hashmap_entry_init(ret, lookup_entry.hash); hashmap_entry_init(ret, lookup_entry.hash);
replaced = hashmap_put(&remotes_hash, ret); 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)) if (skip_prefix(buf.buf, "URL:", &v))
add_url_alias(remote, xstrdup(skip_spaces(v))); add_url_alias(remote, xstrdup(skip_spaces(v)));
else if (skip_prefix(buf.buf, "Push:", &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)) 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); strbuf_release(&buf);
fclose(f); fclose(f);
@ -327,15 +292,19 @@ static void read_branches_file(struct remote *remote)
frag = "master"; frag = "master";
add_url_alias(remote, strbuf_detach(&buf, NULL)); add_url_alias(remote, strbuf_detach(&buf, NULL));
add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s", strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s",
frag, remote->name)); frag, remote->name);
refspec_append(&remote->fetch, buf.buf);
/* /*
* Cogito compatible push: push current HEAD to remote #branch * Cogito compatible push: push current HEAD to remote #branch
* (master if missing) * (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 */ remote->fetch_tags = 1; /* always auto-follow */
strbuf_release(&buf);
} }
static int handle_config(const char *key, const char *value, void *cb) 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; const char *v;
if (git_config_string(&v, key, value)) if (git_config_string(&v, key, value))
return -1; return -1;
add_push_refspec(remote, v); refspec_append(&remote->push, v);
free((char *)v);
} else if (!strcmp(subkey, "fetch")) { } else if (!strcmp(subkey, "fetch")) {
const char *v; const char *v;
if (git_config_string(&v, key, value)) if (git_config_string(&v, key, value))
return -1; return -1;
add_fetch_refspec(remote, v); refspec_append(&remote->fetch, v);
free((char *)v);
} else if (!strcmp(subkey, "receivepack")) { } else if (!strcmp(subkey, "receivepack")) {
const char *v; const char *v;
if (git_config_string(&v, key, value)) if (git_config_string(&v, key, value))
@ -499,158 +470,6 @@ static void read_config(void)
alias_all_urls(); 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) static int valid_remote_nick(const char *name)
{ {
if (!name[0] || is_dot_or_dotdot(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); pushremote_for_branch(branch, NULL);
struct remote *remote = remote_get(remote_name); struct remote *remote = remote_get(remote_name);
if (remote && remote->push_refspec_nr && if (remote && remote->push.nr &&
(dst = apply_refspecs(remote->push, (dst = apply_refspecs(&remote->push,
remote->push_refspec_nr,
branch->refname))) { branch->refname))) {
if (explicit) if (explicit)
*explicit = 1; *explicit = 1;
@ -744,8 +562,6 @@ static struct remote *remote_get_1(const char *name,
add_url_alias(ret, name); add_url_alias(ret, name);
if (!valid_remote(ret)) if (!valid_remote(ret))
return NULL; 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; return ret;
} }
@ -776,12 +592,6 @@ int for_each_remote(each_remote_fn fn, void *priv)
struct remote *r = remotes[i]; struct remote *r = remotes[i];
if (!r) if (!r)
continue; 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); result = fn(r, priv);
} }
return result; return result;
@ -887,7 +697,9 @@ static int match_name_with_pattern(const char *key, const char *name,
return ret; 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 i;
int find_src = !query->src; 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) if (find_src && !query->dst)
error("query_refspecs_multiple: need either src or dst"); error("query_refspecs_multiple: need either src or dst");
for (i = 0; i < ref_count; i++) { for (i = 0; i < rs->nr; i++) {
struct refspec *refspec = &refs[i]; struct refspec_item *refspec = &rs->items[i];
const char *key = find_src ? refspec->dst : refspec->src; const char *key = find_src ? refspec->dst : refspec->src;
const char *value = find_src ? refspec->src : refspec->dst; const char *value = find_src ? refspec->src : refspec->dst;
const char *needle = find_src ? query->dst : query->src; 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 i;
int find_src = !query->src; 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) if (find_src && !query->dst)
return error("query_refspecs: need either src or dst"); return error("query_refspecs: need either src or dst");
for (i = 0; i < ref_count; i++) { for (i = 0; i < rs->nr; i++) {
struct refspec *refspec = &refs[i]; struct refspec_item *refspec = &rs->items[i];
const char *key = find_src ? refspec->dst : refspec->src; const char *key = find_src ? refspec->dst : refspec->src;
const char *value = find_src ? refspec->src : refspec->dst; 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; return -1;
} }
char *apply_refspecs(struct refspec *refspecs, int nr_refspec, char *apply_refspecs(struct refspec *rs, const char *name)
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; query.src = (char *)name;
if (query_refspecs(refspecs, nr_refspec, &query)) if (query_refspecs(rs, &query))
return NULL; return NULL;
return query.dst; 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, 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, static int match_explicit_lhs(struct ref *src,
struct refspec *rs, struct refspec_item *rs,
struct ref **match, struct ref **match,
int *allocated_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, static int match_explicit(struct ref *src, struct ref *dst,
struct ref ***dst_tail, struct ref ***dst_tail,
struct refspec *rs) struct refspec_item *rs)
{ {
struct ref *matched_src, *matched_dst; struct ref *matched_src, *matched_dst;
int allocated_src; 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, static int match_explicit_refs(struct ref *src, struct ref *dst,
struct ref ***dst_tail, struct refspec *rs, struct ref ***dst_tail, struct refspec *rs)
int rs_nr)
{ {
int i, errs; int i, errs;
for (i = errs = 0; i < rs_nr; i++) for (i = errs = 0; i < rs->nr; i++)
errs += match_explicit(src, dst, dst_tail, &rs[i]); errs += match_explicit(src, dst, dst_tail, &rs->items[i]);
return errs; return errs;
} }
static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
int send_mirror, int direction, const struct refspec **ret_pat) int send_mirror, int direction,
const struct refspec_item **ret_pat)
{ {
const struct refspec *pat; const struct refspec_item *pat;
char *name; char *name;
int i; int i;
int matching_refs = -1; int matching_refs = -1;
for (i = 0; i < rs_nr; i++) { for (i = 0; i < rs->nr; i++) {
if (rs[i].matching && const struct refspec_item *item = &rs->items[i];
(matching_refs == -1 || rs[i].force)) { if (item->matching &&
(matching_refs == -1 || item->force)) {
matching_refs = i; matching_refs = i;
continue; continue;
} }
if (rs[i].pattern) { if (item->pattern) {
const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; const char *dst_side = item->dst ? item->dst : item->src;
int match; int match;
if (direction == FROM_SRC) 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 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) { if (match) {
matching_refs = i; matching_refs = i;
break; break;
@ -1301,7 +1113,7 @@ static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref
if (matching_refs == -1) if (matching_refs == -1)
return NULL; return NULL;
pat = rs + matching_refs; pat = &rs->items[matching_refs];
if (pat->matching) { if (pat->matching) {
/* /*
* "matching refs"; traditionally we pushed everything * "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 * but we can catch some errors early before even talking to the
* remote side. * 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 ret = 0;
int i; int i;
for (i = 0; i < nr_refspec; i++) { for (i = 0; i < rs->nr; i++) {
struct refspec *rs = refspec + i; struct refspec_item *item = &rs->items[i];
if (rs->pattern || rs->matching) if (item->pattern || item->matching)
continue; continue;
ret |= match_explicit_lhs(src, rs, NULL, NULL); ret |= match_explicit_lhs(src, item, NULL, NULL);
} }
free_refspec(nr_refspec, refspec);
return ret; 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). * dst (e.g. pushing to a new branch, done in match_explicit_refs).
*/ */
int match_push_refs(struct ref *src, struct ref **dst, 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_all = flags & MATCH_REFS_ALL;
int send_mirror = flags & MATCH_REFS_MIRROR; int send_mirror = flags & MATCH_REFS_MIRROR;
int send_prune = flags & MATCH_REFS_PRUNE; int send_prune = flags & MATCH_REFS_PRUNE;
int errs; int errs;
static const char *default_refspec[] = { ":", NULL };
struct ref *ref, **dst_tail = tail_ref(dst); struct ref *ref, **dst_tail = tail_ref(dst);
struct string_list dst_ref_index = STRING_LIST_INIT_NODUP; struct string_list dst_ref_index = STRING_LIST_INIT_NODUP;
if (!nr_refspec) { /* If no refspec is provided, use the default ":" */
nr_refspec = 1; if (!rs->nr)
refspec = default_refspec; refspec_append(rs, ":");
}
rs = parse_push_refspec(nr_refspec, (const char **) refspec); errs = match_explicit_refs(src, *dst, &dst_tail, rs);
errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
/* pick the remainder */ /* pick the remainder */
for (ref = src; ref; ref = ref->next) { for (ref = src; ref; ref = ref->next) {
struct string_list_item *dst_item; struct string_list_item *dst_item;
struct ref *dst_peer; struct ref *dst_peer;
const struct refspec *pat = NULL; const struct refspec_item *pat = NULL;
char *dst_name; 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) if (!dst_name)
continue; continue;
@ -1545,7 +1352,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
/* We're already sending something to this ref. */ /* We're already sending something to this ref. */
continue; 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_name) {
if (!src_ref_index.nr) if (!src_ref_index.nr)
prepare_ref_index(&src_ref_index, src); 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); string_list_clear(&src_ref_index, 0);
} }
if (errs) if (errs)
return -1; return -1;
return 0; return 0;
@ -1753,7 +1561,7 @@ static const char *tracking_for_push_dest(struct remote *remote,
{ {
char *ret; char *ret;
ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); ret = apply_refspecs(&remote->fetch, refname);
if (!ret) if (!ret)
return error_buf(err, return error_buf(err,
_("push destination '%s' on remote '%s' has no local tracking branch"), _("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 '%s' has no remote for pushing"),
branch->name); branch->name);
if (remote->push_refspec_nr) { if (remote->push.nr) {
char *dst; char *dst;
const char *ret; const char *ret;
dst = apply_refspecs(remote->push, remote->push_refspec_nr, dst = apply_refspecs(&remote->push, branch->refname);
branch->refname);
if (!dst) if (!dst)
return error_buf(err, return error_buf(err,
_("push refspecs for '%s' do not include '%s'"), _("push refspecs for '%s' do not include '%s'"),
@ -1849,7 +1656,7 @@ static int ignore_symref_update(const char *refname)
* local symbolic ref. * local symbolic ref.
*/ */
static struct ref *get_expanded_map(const struct ref *remote_refs, static struct ref *get_expanded_map(const struct ref *remote_refs,
const struct refspec *refspec) const struct refspec_item *refspec)
{ {
const struct ref *ref; const struct ref *ref;
struct ref *ret = NULL; 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, int get_fetch_map(const struct ref *remote_refs,
const struct refspec *refspec, const struct refspec_item *refspec,
struct ref ***tail, struct ref ***tail,
int missing_ok) int missing_ok)
{ {
@ -2252,8 +2059,7 @@ struct ref *guess_remote_head(const struct ref *head,
struct stale_heads_info { struct stale_heads_info {
struct string_list *ref_names; struct string_list *ref_names;
struct ref **stale_refs_tail; struct ref **stale_refs_tail;
struct refspec *refs; struct refspec *rs;
int ref_count;
}; };
static int get_stale_heads_cb(const char *refname, const struct object_id *oid, 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 stale_heads_info *info = cb_data;
struct string_list matches = STRING_LIST_INIT_DUP; struct string_list matches = STRING_LIST_INIT_DUP;
struct refspec query; struct refspec_item query;
int i, stale = 1; int i, stale = 1;
memset(&query, 0, sizeof(struct refspec)); memset(&query, 0, sizeof(struct refspec_item));
query.dst = (char *)refname; 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) if (matches.nr == 0)
goto clean_exit; /* No matches */ goto clean_exit; /* No matches */
@ -2294,7 +2100,7 @@ clean_exit:
return 0; 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 ref *ref, *stale_refs = NULL;
struct string_list ref_names = STRING_LIST_INIT_NODUP; 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.ref_names = &ref_names;
info.stale_refs_tail = &stale_refs; info.stale_refs_tail = &stale_refs;
info.refs = refs; info.rs = rs;
info.ref_count = ref_count;
for (ref = fetch_map; ref; ref = ref->next) for (ref = fetch_map; ref; ref = ref->next)
string_list_append(&ref_names, ref->name); string_list_append(&ref_names, ref->name);
string_list_sort(&ref_names); string_list_sort(&ref_names);
@ -2387,7 +2192,7 @@ static int remote_tracking(struct remote *remote, const char *refname,
{ {
char *dst; char *dst;
dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); dst = apply_refspecs(&remote->fetch, refname);
if (!dst) if (!dst)
return -1; /* no tracking ref for refname at remote */ return -1; /* no tracking ref for refname at remote */
if (read_ref(dst, oid)) if (read_ref(dst, oid))

View File

@ -3,6 +3,7 @@
#include "parse-options.h" #include "parse-options.h"
#include "hashmap.h" #include "hashmap.h"
#include "refspec.h"
enum { enum {
REMOTE_UNCONFIGURED = 0, REMOTE_UNCONFIGURED = 0,
@ -27,15 +28,9 @@ struct remote {
int pushurl_nr; int pushurl_nr;
int pushurl_alloc; int pushurl_alloc;
const char **push_refspec; struct refspec push;
struct refspec *push;
int push_refspec_nr;
int push_refspec_alloc;
const char **fetch_refspec; struct refspec fetch;
struct refspec *fetch;
int fetch_refspec_nr;
int fetch_refspec_alloc;
/* /*
* -1 to never fetch tags * -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); 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 {
struct ref *next; struct ref *next;
struct object_id old_oid; 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); struct ref *ref_remove_duplicates(struct ref *ref_map);
int valid_fetch_refspec(const char *refspec); int query_refspecs(struct refspec *rs, struct refspec_item *query);
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); char *apply_refspecs(struct refspec *rs, const char *name);
extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
void free_refspec(int nr_refspec, struct refspec *refspec); int check_push_refs(struct ref *src, struct refspec *rs);
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 match_push_refs(struct ref *src, struct ref **dst, 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, void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
int force_update); 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 * 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. * 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 ***tail, int missing_ok);
struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); 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. * 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 { struct branch {
const char *name; const char *name;
@ -223,7 +199,7 @@ struct branch {
const char *pushremote_name; const char *pushremote_name;
const char **merge_name; const char **merge_name;
struct refspec **merge; struct refspec_item **merge;
int merge_nr; int merge_nr;
int merge_alloc; int merge_alloc;
@ -292,7 +268,7 @@ struct ref *guess_remote_head(const struct ref *head,
int all); int all);
/* Return refs which no longer exist on remote */ /* 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 * 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 *); extern int is_empty_cas(const struct push_cas_option *);
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); 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 #endif

View File

@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits,
static int push_submodule(const char *path, static int push_submodule(const char *path,
const struct remote *remote, const struct remote *remote,
const char **refspec, int refspec_nr, const struct refspec *rs,
const struct string_list *push_options, const struct string_list *push_options,
int dry_run) int dry_run)
{ {
@ -991,8 +991,8 @@ static int push_submodule(const char *path,
if (remote->origin != REMOTE_UNCONFIGURED) { if (remote->origin != REMOTE_UNCONFIGURED) {
int i; int i;
argv_array_push(&cp.args, remote->name); argv_array_push(&cp.args, remote->name);
for (i = 0; i < refspec_nr; i++) for (i = 0; i < rs->raw_nr; i++)
argv_array_push(&cp.args, refspec[i]); argv_array_push(&cp.args, rs->raw[i]);
} }
prepare_submodule_repo_env(&cp.env_array); 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, static void submodule_push_check(const char *path, const char *head,
const struct remote *remote, const struct remote *remote,
const char **refspec, int refspec_nr) const struct refspec *rs)
{ {
struct child_process cp = CHILD_PROCESS_INIT; struct child_process cp = CHILD_PROCESS_INIT;
int i; 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, head);
argv_array_push(&cp.args, remote->name); argv_array_push(&cp.args, remote->name);
for (i = 0; i < refspec_nr; i++) for (i = 0; i < rs->raw_nr; i++)
argv_array_push(&cp.args, refspec[i]); argv_array_push(&cp.args, rs->raw[i]);
prepare_submodule_repo_env(&cp.env_array); prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1; 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, int push_unpushed_submodules(struct oid_array *commits,
const struct remote *remote, const struct remote *remote,
const char **refspec, int refspec_nr, const struct refspec *rs,
const struct string_list *push_options, const struct string_list *push_options,
int dry_run) int dry_run)
{ {
@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits,
for (i = 0; i < needs_pushing.nr; i++) for (i = 0; i < needs_pushing.nr; i++)
submodule_push_check(needs_pushing.items[i].string, submodule_push_check(needs_pushing.items[i].string,
head, remote, head, remote, rs);
refspec, refspec_nr);
free(head); free(head);
} }
@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits,
for (i = 0; i < needs_pushing.nr; i++) { for (i = 0; i < needs_pushing.nr; i++) {
const char *path = needs_pushing.items[i].string; const char *path = needs_pushing.items[i].string;
fprintf(stderr, "Pushing submodule '%s'\n", path); 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)) { push_options, dry_run)) {
fprintf(stderr, "Unable to push submodule '%s'\n", path); fprintf(stderr, "Unable to push submodule '%s'\n", path);
ret = 0; ret = 0;

View File

@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
extern int find_unpushed_submodules(struct oid_array *commits, extern int find_unpushed_submodules(struct oid_array *commits,
const char *remotes_name, const char *remotes_name,
struct string_list *needs_pushing); struct string_list *needs_pushing);
struct refspec;
extern int push_unpushed_submodules(struct oid_array *commits, extern int push_unpushed_submodules(struct oid_array *commits,
const struct remote *remote, const struct remote *remote,
const char **refspec, int refspec_nr, const struct refspec *rs,
const struct string_list *push_options, const struct string_list *push_options,
int dry_run); int dry_run);
/* /*

View File

@ -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 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 protocol v2 with 'http://' transport
# #
. "$TEST_DIRECTORY"/lib-httpd.sh . "$TEST_DIRECTORY"/lib-httpd.sh

View File

@ -11,6 +11,7 @@
#include "sigchain.h" #include "sigchain.h"
#include "argv-array.h" #include "argv-array.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "transport-internal.h" #include "transport-internal.h"
#include "protocol.h" #include "protocol.h"
@ -35,8 +36,7 @@ struct helper_data {
char *export_marks; char *export_marks;
char *import_marks; char *import_marks;
/* These go from remote name (as in "list") to private name */ /* These go from remote name (as in "list") to private name */
struct refspec *refspecs; struct refspec rs;
int refspec_nr;
/* Transport options for fetch-pack/send-pack (should one of /* Transport options for fetch-pack/send-pack (should one of
* those be invoked). * those be invoked).
*/ */
@ -106,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport)
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct child_process *helper; struct child_process *helper;
const char **refspecs = NULL;
int refspec_nr = 0;
int refspec_alloc = 0;
int duped; int duped;
int code; int code;
@ -138,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport)
data->helper = helper; data->helper = helper;
data->no_disconnect_req = 0; data->no_disconnect_req = 0;
refspec_init(&data->rs, REFSPEC_FETCH);
/* /*
* Open the output as FILE* so strbuf_getline_*() family of * 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; data->export = 1;
else if (!strcmp(capname, "check-connectivity")) else if (!strcmp(capname, "check-connectivity"))
data->check_connectivity = 1; data->check_connectivity = 1;
else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { else if (skip_prefix(capname, "refspec ", &arg)) {
ALLOC_GROW(refspecs, refspec_append(&data->rs, arg);
refspec_nr + 1,
refspec_alloc);
refspecs[refspec_nr++] = xstrdup(arg);
} else if (!strcmp(capname, "connect")) { } else if (!strcmp(capname, "connect")) {
data->connect = 1; data->connect = 1;
} else if (!strcmp(capname, "stateless-connect")) { } else if (!strcmp(capname, "stateless-connect")) {
@ -206,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport)
capname); capname);
} }
} }
if (refspecs) { if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {
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) {
warning("This remote helper should implement refspec capability."); warning("This remote helper should implement refspec capability.");
} }
strbuf_release(&buf); strbuf_release(&buf);
@ -377,8 +365,7 @@ static int release_helper(struct transport *transport)
{ {
int res = 0; int res = 0;
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
free_refspec(data->refspec_nr, data->refspecs); refspec_clear(&data->rs);
data->refspecs = NULL;
res = disconnect_helper(transport); res = disconnect_helper(transport);
free(transport->data); free(transport->data);
return res; return res;
@ -535,8 +522,8 @@ static int fetch_with_import(struct transport *transport,
if (posn->status & REF_STATUS_UPTODATE) if (posn->status & REF_STATUS_UPTODATE)
continue; continue;
name = posn->symref ? posn->symref : posn->name; name = posn->symref ? posn->symref : posn->name;
if (data->refspecs) if (data->rs.nr)
private = apply_refspecs(data->refspecs, data->refspec_nr, name); private = apply_refspecs(&data->rs, name);
else else
private = xstrdup(name); private = xstrdup(name);
if (private) { 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)) if (push_update_ref_status(&buf, &ref, remote_refs))
continue; 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; continue;
/* propagate back the update to the remote namespace */ /* 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) if (!private)
continue; continue;
update_ref("update by helper", private, &ref->new_oid, NULL, 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 string_list revlist_args = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
if (!data->refspecs) if (!data->rs.nr)
die("remote-helper doesn't support push; refspec needed"); die("remote-helper doesn't support push; refspec needed");
set_common_push_options(transport, data->name, flags); set_common_push_options(transport, data->name, flags);
@ -955,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,
char *private; char *private;
struct object_id oid; 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)) { if (private && !get_oid(private, &oid)) {
strbuf_addf(&buf, "^%s", private); strbuf_addf(&buf, "^%s", private);
string_list_append_nodup(&revlist_args, string_list_append_nodup(&revlist_args,

View File

@ -11,6 +11,7 @@
#include "bundle.h" #include "bundle.h"
#include "dir.h" #include "dir.h"
#include "refs.h" #include "refs.h"
#include "refspec.h"
#include "branch.h" #include "branch.h"
#include "url.h" #include "url.h"
#include "submodule.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) 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) if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
return; return;
@ -619,29 +620,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,
free(head); 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) static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
{ {
struct git_transport_data *data = transport->data; 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 transport_push(struct transport *transport,
int refspec_nr, const char **refspec, int flags, struct refspec *rs, int flags,
unsigned int *reject_reasons) unsigned int *reject_reasons)
{ {
*reject_reasons = 0; *reject_reasons = 0;
transport_verify_remote_names(refspec_nr, refspec);
if (transport_color_config() < 0) if (transport_color_config() < 0)
return -1; return -1;
@ -1111,38 +1088,17 @@ int transport_push(struct transport *transport,
int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
int push_ret, ret, err; int push_ret, ret, err;
struct refspec *tmp_rs;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT; 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; return -1;
tmp_rs = parse_push_refspec(refspec_nr, refspec); refspec_ref_prefixes(rs, &ref_prefixes);
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);
}
}
remote_refs = transport->vtable->get_refs_list(transport, 1, remote_refs = transport->vtable->get_refs_list(transport, 1,
&ref_prefixes); &ref_prefixes);
argv_array_clear(&ref_prefixes); argv_array_clear(&ref_prefixes);
free_refspec(refspec_nr, tmp_rs);
if (flags & TRANSPORT_PUSH_ALL) if (flags & TRANSPORT_PUSH_ALL)
match_flags |= MATCH_REFS_ALL; match_flags |= MATCH_REFS_ALL;
@ -1153,10 +1109,8 @@ int transport_push(struct transport *transport,
if (flags & TRANSPORT_PUSH_FOLLOW_TAGS) if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
match_flags |= MATCH_REFS_FOLLOW_TAGS; match_flags |= MATCH_REFS_FOLLOW_TAGS;
if (match_push_refs(local_refs, &remote_refs, if (match_push_refs(local_refs, &remote_refs, rs, match_flags))
refspec_nr, refspec, match_flags)) {
return -1; return -1;
}
if (transport->smart_options && if (transport->smart_options &&
transport->smart_options->cas && transport->smart_options->cas &&
@ -1185,7 +1139,7 @@ int transport_push(struct transport *transport,
if (!push_unpushed_submodules(&commits, if (!push_unpushed_submodules(&commits,
transport->remote, transport->remote,
refspec, refspec_nr, rs,
transport->push_options, transport->push_options,
pretend)) { pretend)) {
oid_array_clear(&commits); oid_array_clear(&commits);

View File

@ -203,7 +203,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
#define REJECT_NEEDS_FORCE 0x10 #define REJECT_NEEDS_FORCE 0x10
int transport_push(struct transport *connection, int transport_push(struct transport *connection,
int refspec_nr, const char **refspec, int flags, struct refspec *rs, int flags,
unsigned int * reject_reasons); 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); int bidirectional_transfer_loop(int input, int output);
/* common methods used by transport.c and builtin/send-pack.c */ /* 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); void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
int transport_refs_pushed(struct ref *ref); int transport_refs_pushed(struct ref *ref);