From: Junio C Hamano Date: Wed, 30 May 2018 12:51:26 +0000 (+0900) Subject: Merge branch 'bw/ref-prefix-for-configured-refspec' X-Git-Tag: v2.18.0-rc0~10 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/e12cbeaa624b82bc00d585bb24c8034fbf5f9de2?ds=inline;hp=-c 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 ... --- e12cbeaa624b82bc00d585bb24c8034fbf5f9de2 diff --combined builtin/clone.c index ecd8495dab,8c5f4d8f07..99e73dae85 --- a/builtin/clone.c +++ b/builtin/clone.c @@@ -14,6 -14,7 +14,7 @@@ #include "parse-options.h" #include "fetch-pack.h" #include "refs.h" + #include "refspec.h" #include "tree.h" #include "tree-walk.h" #include "unpack-trees.h" @@@ -546,7 -547,7 +547,7 @@@ static struct ref *find_remote_branch(c } static struct ref *wanted_peer_refs(const struct ref *refs, - struct refspec *refspec) + struct refspec_item *refspec) { struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD")); struct ref *local_refs = head; @@@ -823,7 -824,7 +824,7 @@@ static void write_refspec_config(const } else if (remote_head_points_at) { const char *head = remote_head_points_at->name; if (!skip_prefix(head, "refs/heads/", &head)) - die("BUG: remote HEAD points at non-head?"); + BUG("remote HEAD points at non-head?"); strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name, branch_top->buf, head); @@@ -894,8 -895,7 +895,7 @@@ int cmd_clone(int argc, const char **ar int err = 0, complete_refs_before_fetch = 1; int submodule_progress; - struct refspec *refspec; - const char *fetch_pattern; + struct refspec_item refspec; fetch_if_missing = 0; @@@ -1077,8 -1077,7 +1077,7 @@@ if (option_required_reference.nr || option_optional_reference.nr) setup_reference(); - fetch_pattern = value.buf; - refspec = parse_fetch_refspec(1, &fetch_pattern); + refspec_item_init(&refspec, value.buf, REFSPEC_FETCH); strbuf_reset(&value); @@@ -1138,7 -1137,7 +1137,7 @@@ refs = transport_get_remote_refs(transport, NULL); if (refs) { - mapped_refs = wanted_peer_refs(refs, refspec); + mapped_refs = wanted_peer_refs(refs, &refspec); /* * transport_get_remote_refs() may return refs with null sha-1 * in mapped_refs (see struct transport->get_refs_list @@@ -1232,6 -1231,6 +1231,6 @@@ strbuf_release(&value); junk_mode = JUNK_LEAVE_ALL; - free(refspec); + refspec_item_clear(&refspec); return err; } diff --combined builtin/fast-export.c index f9568ddba0,41fe49e4d6..6c9768742f --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@@ -7,6 -7,7 +7,7 @@@ #include "cache.h" #include "config.h" #include "refs.h" + #include "refspec.h" #include "commit.h" #include "object.h" #include "tag.h" @@@ -35,8 -36,7 +36,7 @@@ static int use_done_feature static int no_data; static int full_tree; static struct string_list extra_refs = STRING_LIST_INIT_NODUP; - static struct refspec *refspecs; - static int refspecs_nr; + static struct refspec refspecs = REFSPEC_INIT_FETCH; static int anonymize; static int parse_opt_signed_tag_mode(const struct option *opt, @@@ -156,14 -156,15 +156,14 @@@ static void anonymize_path(struct strbu } } -/* Since intptr_t is C99, we do not use it here */ -static inline uint32_t *mark_to_ptr(uint32_t mark) +static inline void *mark_to_ptr(uint32_t mark) { - return ((uint32_t *)NULL) + mark; + return (void *)(uintptr_t)mark; } static inline uint32_t ptr_to_mark(void * mark) { - return (uint32_t *)mark - (uint32_t *)NULL; + return (uint32_t)(uintptr_t)mark; } static inline void mark_object(struct object *object, uint32_t mark) @@@ -516,7 -517,7 +516,7 @@@ static void anonymize_ident_line(const /* skip "committer", "author", "tagger", etc */ end_of_header = strchr(*beg, ' '); if (!end_of_header) - die("BUG: malformed line fed to anonymize_ident_line: %.*s", + BUG("malformed line fed to anonymize_ident_line: %.*s", (int)(*end - *beg), *beg); end_of_header++; strbuf_add(out, *beg, end_of_header - *beg); @@@ -577,11 -578,11 +577,11 @@@ static void handle_commit(struct commi get_object_mark(&commit->parents->item->object) != 0 && !full_tree) { parse_commit_or_die(commit->parents->item); - diff_tree_oid(&commit->parents->item->tree->object.oid, - &commit->tree->object.oid, "", &rev->diffopt); + diff_tree_oid(get_commit_tree_oid(commit->parents->item), + get_commit_tree_oid(commit), "", &rev->diffopt); } else - diff_root_tree_oid(&commit->tree->object.oid, + diff_root_tree_oid(get_commit_tree_oid(commit), "", &rev->diffopt); /* Export the referenced blobs, and remember the marks. */ @@@ -828,9 -829,9 +828,9 @@@ static void get_tags_and_duplicates(str if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1) continue; - if (refspecs) { + if (refspecs.nr) { char *private; - private = apply_refspecs(refspecs, refspecs_nr, full_name); + private = apply_refspecs(&refspecs, full_name); if (private) { free(full_name); full_name = private; @@@ -949,7 -950,7 +949,7 @@@ static void import_marks(char *input_fi if (last_idnum < mark) last_idnum = mark; - type = oid_object_info(&oid, NULL); + type = oid_object_info(the_repository, &oid, NULL); if (type < 0) die("object not found: %s", oid_to_hex(&oid)); @@@ -976,8 -977,8 +976,8 @@@ static void handle_deletes(void) { int i; - for (i = 0; i < refspecs_nr; i++) { - struct refspec *refspec = &refspecs[i]; + for (i = 0; i < refspecs.nr; i++) { + struct refspec_item *refspec = &refspecs.items[i]; if (*refspec->src) continue; @@@ -1038,18 -1039,12 +1038,12 @@@ int cmd_fast_export(int argc, const cha usage_with_options (fast_export_usage, options); if (refspecs_list.nr) { - const char **refspecs_str; int i; - ALLOC_ARRAY(refspecs_str, refspecs_list.nr); for (i = 0; i < refspecs_list.nr; i++) - refspecs_str[i] = refspecs_list.items[i].string; - - refspecs_nr = refspecs_list.nr; - refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str); + refspec_append(&refspecs, refspecs_list.items[i].string); string_list_clear(&refspecs_list, 1); - free(refspecs_str); } if (use_done_feature) @@@ -1088,7 -1083,7 +1082,7 @@@ if (use_done_feature) printf("done\n"); - free_refspec(refspecs_nr, refspecs); + refspec_clear(&refspecs); return 0; } diff --combined builtin/fetch.c index 1f037e8e4b,7cc7a52dee..c0d8ad1fe2 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@ -5,6 -5,7 +5,7 @@@ #include "config.h" #include "repository.h" #include "refs.h" + #include "refspec.h" #include "commit.h" #include "builtin.h" #include "string-list.h" @@@ -59,10 -60,8 +60,9 @@@ static const char *submodule_prefix = " static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND; static int shown_url = 0; - static int refmap_alloc, refmap_nr; - static const char **refmap_array; + static struct refspec refmap = REFSPEC_INIT_FETCH; static struct list_objects_filter_options filter_options; +static struct string_list server_options = STRING_LIST_INIT_DUP; static int git_fetch_config(const char *k, const char *v, void *cb) { @@@ -108,14 -107,12 +108,12 @@@ static int gitmodules_fetch_config(cons static int parse_refmap_arg(const struct option *opt, const char *arg, int unset) { - ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc); - /* * "git fetch --refmap='' origin foo" * can be used to tell the command not to store anywhere */ - if (*arg) - refmap_array[refmap_nr++] = arg; + refspec_append(&refmap, arg); + return 0; } @@@ -171,7 -168,6 +169,7 @@@ static struct option builtin_fetch_opti N_("accept refs that update .git/shallow")), { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"), N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg }, + OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")), OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), TRANSPORT_FAMILY_IPV4), OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), @@@ -204,7 -200,7 +202,7 @@@ static void add_merge_config(struct re for (i = 0; i < branch->merge_nr; i++) { struct ref *rm, **old_tail = *tail; - struct refspec refspec; + struct refspec_item refspec; for (rm = *head; rm; rm = rm->next) { if (branch_merge_matches(branch, i, rm->name)) { @@@ -341,7 -337,7 +339,7 @@@ static void find_non_local_tags(struct } static struct ref *get_ref_map(struct transport *transport, - struct refspec *refspecs, int refspec_count, + struct refspec *rs, int tags, int *autotags) { int i; @@@ -355,29 -351,26 +353,26 @@@ const struct ref *remote_refs; - for (i = 0; i < refspec_count; i++) { - if (!refspecs[i].exact_sha1) { - const char *glob = strchr(refspecs[i].src, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - refspecs[i].src), - refspecs[i].src); - else - expand_ref_prefix(&ref_prefixes, refspecs[i].src); - } + if (rs->nr) + refspec_ref_prefixes(rs, &ref_prefixes); + else if (transport->remote && transport->remote->fetch.nr) + refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes); + + if (ref_prefixes.argc && + (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) { + argv_array_push(&ref_prefixes, "refs/tags/"); } remote_refs = transport_get_remote_refs(transport, &ref_prefixes); argv_array_clear(&ref_prefixes); - if (refspec_count) { + if (rs->nr) { struct refspec *fetch_refspec; - int fetch_refspec_nr; - for (i = 0; i < refspec_count; i++) { - get_fetch_map(remote_refs, &refspecs[i], &tail, 0); - if (refspecs[i].dst && refspecs[i].dst[0]) + for (i = 0; i < rs->nr; i++) { + get_fetch_map(remote_refs, &rs->items[i], &tail, 0); + if (rs->items[i].dst && rs->items[i].dst[0]) *autotags = 1; } /* Merge everything on the command line (but not --tags) */ @@@ -404,17 -397,14 +399,14 @@@ * by ref_remove_duplicates() in favor of one of these * opportunistic entries with FETCH_HEAD_IGNORE. */ - if (refmap_array) { - fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array); - fetch_refspec_nr = refmap_nr; - } else { - fetch_refspec = transport->remote->fetch; - fetch_refspec_nr = transport->remote->fetch_refspec_nr; - } + if (refmap.nr) + fetch_refspec = &refmap; + else + fetch_refspec = &transport->remote->fetch; - for (i = 0; i < fetch_refspec_nr; i++) - get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1); - } else if (refmap_array) { + for (i = 0; i < fetch_refspec->nr; i++) + get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1); + } else if (refmap.nr) { die("--refmap option is only meaningful with command-line refspec(s)."); } else { /* Use the defaults */ @@@ -422,16 -412,16 +414,16 @@@ struct branch *branch = branch_get(NULL); int has_merge = branch_has_merge_config(branch); if (remote && - (remote->fetch_refspec_nr || + (remote->fetch.nr || /* Note: has_merge implies non-NULL branch->remote_name */ (has_merge && !strcmp(branch->remote_name, remote->name)))) { - for (i = 0; i < remote->fetch_refspec_nr; i++) { - get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0); - if (remote->fetch[i].dst && - remote->fetch[i].dst[0]) + for (i = 0; i < remote->fetch.nr; i++) { + get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0); + if (remote->fetch.items[i].dst && + remote->fetch.items[i].dst[0]) *autotags = 1; if (!i && !has_merge && ref_map && - !remote->fetch[0].pattern) + !remote->fetch.items[0].pattern) ref_map->fetch_head_status = FETCH_HEAD_MERGE; } /* @@@ -656,7 -646,7 +648,7 @@@ static int update_local_ref(struct ref struct branch *current_branch = branch_get(NULL); const char *pretty_ref = prettify_refname(ref->name); - type = oid_object_info(&ref->new_oid, NULL); + type = oid_object_info(the_repository, &ref->new_oid, NULL); if (type < 0) die(_("object %s not found"), oid_to_hex(&ref->new_oid)); @@@ -966,11 -956,11 +958,11 @@@ static int fetch_refs(struct transport return ret; } - static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map, - const char *raw_url) + static int prune_refs(struct refspec *rs, struct ref *ref_map, + const char *raw_url) { int url_len, i, result = 0; - struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map); + struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map); char *url; int summary_width = transport_summary_width(stale_refs); const char *dangling_msg = dry_run @@@ -1116,7 -1106,7 +1108,7 @@@ static void backfill_tags(struct transp } static int do_fetch(struct transport *transport, - struct refspec *refs, int ref_count) + struct refspec *rs) { struct string_list existing_refs = STRING_LIST_INIT_DUP; struct ref *ref_map; @@@ -1140,7 -1130,7 +1132,7 @@@ goto cleanup; } - ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags); + ref_map = get_ref_map(transport, rs, tags, &autotags); if (!update_head_ok) check_not_current_branch(ref_map); @@@ -1164,11 -1154,10 +1156,10 @@@ * explicitly (via command line or configuration); we * don't care whether --tags was specified. */ - if (ref_count) { - prune_refs(refs, ref_count, ref_map, transport->url); + if (rs->nr) { + prune_refs(rs, ref_map, transport->url); } else { - prune_refs(transport->remote->fetch, - transport->remote->fetch_refspec_nr, + prune_refs(&transport->remote->fetch, ref_map, transport->url); } @@@ -1357,10 -1346,8 +1348,8 @@@ static inline void fetch_one_setup_part static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok) { - static const char **refs = NULL; - struct refspec *refspec; - int ref_nr = 0; - int j = 0; + struct refspec rs = REFSPEC_INIT_FETCH; + int i; int exit_code; int maybe_prune_tags; int remote_via_config = remote_is_configured(remote, 0); @@@ -1393,40 -1380,31 +1382,34 @@@ maybe_prune_tags = prune_tags_ok && prune_tags; if (maybe_prune_tags && remote_via_config) - add_prune_tags_to_fetch_refspec(remote); - - if (argc > 0 || (maybe_prune_tags && !remote_via_config)) { - size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1); - refs = xcalloc(nr_alloc, sizeof(const char *)); - if (maybe_prune_tags) { - refs[j++] = xstrdup("refs/tags/*:refs/tags/*"); - ref_nr++; - } - } - - if (argc > 0) { - int i; - for (i = 0; i < argc; i++) { - if (!strcmp(argv[i], "tag")) { - i++; - if (i >= argc) - die(_("You need to specify a tag name.")); - refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s", - argv[i], argv[i]); - } else - refs[j++] = argv[i]; - ref_nr++; + refspec_append(&remote->fetch, TAG_REFSPEC); + + if (maybe_prune_tags && (argc || !remote_via_config)) + refspec_append(&rs, TAG_REFSPEC); + + for (i = 0; i < argc; i++) { + if (!strcmp(argv[i], "tag")) { + char *tag; + i++; + if (i >= argc) + die(_("You need to specify a tag name.")); + + tag = xstrfmt("refs/tags/%s:refs/tags/%s", + argv[i], argv[i]); + refspec_append(&rs, tag); + free(tag); + } else { + refspec_append(&rs, argv[i]); } } + if (server_options.nr) + gtransport->server_options = &server_options; + sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); - refspec = parse_fetch_refspec(ref_nr, refs); - exit_code = do_fetch(gtransport, refspec, ref_nr); - free_refspec(ref_nr, refspec); + exit_code = do_fetch(gtransport, &rs); + refspec_clear(&rs); transport_disconnect(gtransport); gtransport = NULL; return exit_code; diff --combined builtin/merge.c index fba0a7fc79,c362cfe90d..d85f99b781 --- a/builtin/merge.c +++ b/builtin/merge.c @@@ -14,6 -14,7 +14,7 @@@ #include "run-command.h" #include "diff.h" #include "refs.h" + #include "refspec.h" #include "commit.h" #include "diffcore.h" #include "revision.h" @@@ -280,7 -281,7 +281,7 @@@ out return rc; } -static void read_empty(unsigned const char *sha1, int verbose) +static void read_empty(const struct object_id *oid, int verbose) { int i = 0; const char *args[7]; @@@ -290,15 -291,15 +291,15 @@@ args[i++] = "-v"; args[i++] = "-m"; args[i++] = "-u"; - args[i++] = EMPTY_TREE_SHA1_HEX; - args[i++] = sha1_to_hex(sha1); + args[i++] = empty_tree_oid_hex(); + args[i++] = oid_to_hex(oid); args[i] = NULL; if (run_command_v_opt(args, RUN_GIT_CMD)) die(_("read-tree failed")); } -static void reset_hard(unsigned const char *sha1, int verbose) +static void reset_hard(const struct object_id *oid, int verbose) { int i = 0; const char *args[6]; @@@ -308,7 -309,7 +309,7 @@@ args[i++] = "-v"; args[i++] = "--reset"; args[i++] = "-u"; - args[i++] = sha1_to_hex(sha1); + args[i++] = oid_to_hex(oid); args[i] = NULL; if (run_command_v_opt(args, RUN_GIT_CMD)) @@@ -324,7 -325,7 +325,7 @@@ static void restore_state(const struct if (is_null_oid(stash)) return; - reset_hard(head->hash, 1); + reset_hard(head, 1); args[2] = oid_to_hex(stash); @@@ -647,7 -648,7 +648,7 @@@ static int try_merge_strategy(const cha struct commit_list *remoteheads, struct commit *head) { - static struct lock_file lock; + struct lock_file lock = LOCK_INIT; const char *head_arg = "HEAD"; hold_locked_index(&lock, LOCK_DIE_ON_ERROR); @@@ -805,7 -806,7 +806,7 @@@ static int merge_trivial(struct commit { struct object_id result_tree, result_commit; struct commit_list *parents, **pptr = &parents; - static struct lock_file lock; + struct lock_file lock = LOCK_INIT; hold_locked_index(&lock, LOCK_DIE_ON_ERROR); refresh_cache(REFRESH_QUIET); @@@ -1297,7 -1298,7 +1298,7 @@@ int cmd_merge(int argc, const char **ar if (remoteheads->next) die(_("Can merge only exactly one commit into empty head")); remote_head_oid = &remoteheads->item->object.oid; - read_empty(remote_head_oid->hash, 0); + read_empty(remote_head_oid, 0); update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR); goto done; diff --combined builtin/pull.c index 25f7db5b3a,09575fd23c..1f2ecf3a88 --- a/builtin/pull.c +++ b/builtin/pull.c @@@ -15,6 -15,7 +15,7 @@@ #include "remote.h" #include "dir.h" #include "refs.h" + #include "refspec.h" #include "revision.h" #include "submodule.h" #include "submodule-config.h" @@@ -27,16 -28,14 +28,16 @@@ enum rebase_type REBASE_FALSE = 0, REBASE_TRUE, REBASE_PRESERVE, + REBASE_MERGES, REBASE_INTERACTIVE }; /** * Parses the value of --rebase. If value is a false value, returns * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is - * "preserve", returns REBASE_PRESERVE. If value is a invalid value, dies with - * a fatal error if fatal is true, otherwise returns REBASE_INVALID. + * "merges", returns REBASE_MERGES. If value is "preserve", returns + * REBASE_PRESERVE. If value is a invalid value, dies with a fatal error if + * fatal is true, otherwise returns REBASE_INVALID. */ static enum rebase_type parse_config_rebase(const char *key, const char *value, int fatal) @@@ -49,8 -48,6 +50,8 @@@ return REBASE_TRUE; else if (!strcmp(value, "preserve")) return REBASE_PRESERVE; + else if (!strcmp(value, "merges")) + return REBASE_MERGES; else if (!strcmp(value, "interactive")) return REBASE_INTERACTIVE; @@@ -134,7 -131,7 +135,7 @@@ static struct option pull_options[] = /* Options passed to git-merge or git-rebase */ OPT_GROUP(N_("Options related to merging")), { OPTION_CALLBACK, 'r', "rebase", &opt_rebase, - "false|true|preserve|interactive", + "false|true|merges|preserve|interactive", N_("incorporate changes by rebasing rather than merging"), PARSE_OPT_OPTARG, parse_opt_rebase }, OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL, @@@ -543,7 -540,7 +544,7 @@@ static int run_fetch(const char *repo, argv_array_push(&args, repo); argv_array_pushv(&args, refspecs); } else if (*refspecs) - die("BUG: refspecs without repo?"); + BUG("refspecs without repo?"); ret = run_command_v_opt(args.argv, RUN_GIT_CMD); argv_array_clear(&args); return ret; @@@ -679,12 -676,12 +680,12 @@@ static const char *get_upstream_branch( */ static const char *get_tracking_branch(const char *remote, const char *refspec) { - struct refspec *spec; + struct refspec_item spec; const char *spec_src; const char *merge_branch; - spec = parse_fetch_refspec(1, &refspec); - spec_src = spec->src; + refspec_item_init(&spec, refspec, REFSPEC_FETCH); + spec_src = spec.src; if (!*spec_src || !strcmp(spec_src, "HEAD")) spec_src = "HEAD"; else if (skip_prefix(spec_src, "heads/", &spec_src)) @@@ -704,7 -701,7 +705,7 @@@ } else merge_branch = NULL; - free_refspec(1, spec); + refspec_item_clear(&spec); return merge_branch; } @@@ -804,9 -801,7 +805,9 @@@ static int run_rebase(const struct obje argv_push_verbosity(&args); /* Options passed to git-rebase */ - if (opt_rebase == REBASE_PRESERVE) + if (opt_rebase == REBASE_MERGES) + argv_array_push(&args, "--rebase-merges"); + else if (opt_rebase == REBASE_PRESERVE) argv_array_push(&args, "--preserve-merges"); else if (opt_rebase == REBASE_INTERACTIVE) argv_array_push(&args, "--interactive"); diff --combined builtin/remote.c index 0bbf9f4c9e,b84175cc6c..1a82d850a2 --- a/builtin/remote.c +++ b/builtin/remote.c @@@ -7,6 -7,7 +7,7 @@@ #include "strbuf.h" #include "run-command.h" #include "refs.h" + #include "refspec.h" #include "argv-array.h" static const char * const builtin_remote_usage[] = { @@@ -245,9 -246,7 +246,9 @@@ static int add(int argc, const char **a struct branch_info { char *remote_name; struct string_list merge; - enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase; + enum { + NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES + } rebase; }; static struct string_list branch_list = STRING_LIST_INIT_NODUP; @@@ -308,8 -307,6 +309,8 @@@ static int config_read_branches(const c info->rebase = v; else if (!strcmp(value, "preserve")) info->rebase = NORMAL_REBASE; + else if (!strcmp(value, "merges")) + info->rebase = REBASE_MERGES; else if (!strcmp(value, "interactive")) info->rebase = INTERACTIVE_REBASE; } @@@ -336,10 -333,10 +337,10 @@@ static int get_ref_states(const struct struct ref *ref, *stale_refs; int i; - for (i = 0; i < states->remote->fetch_refspec_nr; i++) - if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1)) + for (i = 0; i < states->remote->fetch.nr; i++) + if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1)) die(_("Could not get fetch map for refspec %s"), - states->remote->fetch_refspec[i]); + states->remote->fetch.raw[i]); states->new_refs.strdup_strings = 1; states->tracked.strdup_strings = 1; @@@ -350,8 -347,7 +351,7 @@@ else string_list_append(&states->tracked, abbrev_branch(ref->name)); } - stale_refs = get_stale_heads(states->remote->fetch, - states->remote->fetch_refspec_nr, fetch_map); + stale_refs = get_stale_heads(&states->remote->fetch, fetch_map); for (ref = stale_refs; ref; ref = ref->next) { struct string_list_item *item = string_list_append(&states->stale, abbrev_branch(ref->name)); @@@ -391,8 -387,7 +391,7 @@@ static int get_push_ref_states(const st local_refs = get_local_heads(); push_map = copy_ref_list(remote_refs); - match_push_refs(local_refs, &push_map, remote->push_refspec_nr, - remote->push_refspec, MATCH_REFS_NONE); + match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE); states->push.strdup_strings = 1; for (ref = push_map; ref; ref = ref->next) { @@@ -438,14 -433,14 +437,14 @@@ static int get_push_ref_states_noquery( return 0; states->push.strdup_strings = 1; - if (!remote->push_refspec_nr) { + if (!remote->push.nr) { item = string_list_append(&states->push, _("(matching)")); info = item->util = xcalloc(1, sizeof(struct push_info)); info->status = PUSH_STATUS_NOTQUERIED; info->dest = xstrdup(item->string); } - for (i = 0; i < remote->push_refspec_nr; i++) { - struct refspec *spec = remote->push + i; + for (i = 0; i < remote->push.nr; i++) { + const struct refspec_item *spec = &remote->push.items[i]; if (spec->matching) item = string_list_append(&states->push, _("(matching)")); else if (strlen(spec->src)) @@@ -465,7 -460,7 +464,7 @@@ static int get_head_names(const struct { struct ref *ref, *matches; struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; - struct refspec refspec; + struct refspec_item refspec; refspec.force = 0; refspec.pattern = 1; @@@ -518,7 -513,7 +517,7 @@@ static int add_branch_for_removal(cons const struct object_id *oid, int flags, void *cb_data) { struct branches_for_remote *branches = cb_data; - struct refspec refspec; + struct refspec_item refspec; struct known_remote *kr; memset(&refspec, 0, sizeof(refspec)); @@@ -589,12 -584,12 +588,12 @@@ static int migrate_file(struct remote * git_config_set_multivar(buf.buf, remote->url[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); - for (i = 0; i < remote->push_refspec_nr; i++) - git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0); + for (i = 0; i < remote->push.raw_nr; i++) + git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); - for (i = 0; i < remote->fetch_refspec_nr; i++) - git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0); + for (i = 0; i < remote->fetch.raw_nr; i++) + git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0); if (remote->origin == REMOTE_REMOTES) unlink_or_warn(git_path("remotes/%s", remote->name)); else if (remote->origin == REMOTE_BRANCHES) @@@ -649,11 -644,11 +648,11 @@@ static int mv(int argc, const char **ar strbuf_addf(&buf, "remote.%s.fetch", rename.new_name); git_config_set_multivar(buf.buf, NULL, NULL, 1); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name); - for (i = 0; i < oldremote->fetch_refspec_nr; i++) { + for (i = 0; i < oldremote->fetch.raw_nr; i++) { char *ptr; strbuf_reset(&buf2); - strbuf_addstr(&buf2, oldremote->fetch_refspec[i]); + strbuf_addstr(&buf2, oldremote->fetch.raw[i]); ptr = strstr(buf2.buf, old_remote_context.buf); if (ptr) { refspec_updated = 1; @@@ -837,7 -832,7 +836,7 @@@ static int append_ref_to_tracked_list(c const struct object_id *oid, int flags, void *cb_data) { struct ref_states *states = cb_data; - struct refspec refspec; + struct refspec_item refspec; if (flags & REF_ISSYMREF) return 0; @@@ -967,15 -962,9 +966,15 @@@ static int show_local_info_item(struct printf(" %-*s ", show_info->width, item->string); if (branch_info->rebase) { - printf_ln(branch_info->rebase == INTERACTIVE_REBASE - ? _("rebases interactively onto remote %s") - : _("rebases onto remote %s"), merge->items[0].string); + const char *msg; + if (branch_info->rebase == INTERACTIVE_REBASE) + msg = _("rebases interactively onto remote %s"); + else if (branch_info->rebase == REBASE_MERGES) + msg = _("rebases interactively (with merges) onto " + "remote %s"); + else + msg = _("rebases onto remote %s"); + printf_ln(msg, merge->items[0].string); return 0; } else if (show_info->any_rebase) { printf_ln(_(" merges with remote %s"), merge->items[0].string); diff --combined builtin/submodule--helper.c index 7c3cd9dbeb,88a149a2c3..bd250ca216 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@@ -12,6 -12,7 +12,7 @@@ #include "run-command.h" #include "remote.h" #include "refs.h" + #include "refspec.h" #include "connect.h" #include "revision.h" #include "diffcore.h" @@@ -1065,7 -1066,7 +1066,7 @@@ static int module_deinit(int argc, cons } static int clone_submodule(const char *path, const char *gitdir, const char *url, - const char *depth, struct string_list *reference, + const char *depth, struct string_list *reference, int dissociate, int quiet, int progress) { struct child_process cp = CHILD_PROCESS_INIT; @@@ -1084,8 -1085,6 +1085,8 @@@ argv_array_pushl(&cp.args, "--reference", item->string, NULL); } + if (dissociate) + argv_array_push(&cp.args, "--dissociate"); if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); @@@ -1201,7 -1200,6 +1202,7 @@@ static int module_clone(int argc, cons char *p, *path = NULL, *sm_gitdir; struct strbuf sb = STRBUF_INIT; struct string_list reference = STRING_LIST_INIT_NODUP; + int dissociate = 0; char *sm_alternate = NULL, *error_strategy = NULL; struct option module_clone_options[] = { @@@ -1220,8 -1218,6 +1221,8 @@@ OPT_STRING_LIST(0, "reference", &reference, N_("repo"), N_("reference repository")), + OPT_BOOL(0, "dissociate", &dissociate, + N_("use --reference only while cloning")), OPT_STRING(0, "depth", &depth, N_("string"), N_("depth for shallow clones")), @@@ -1261,7 -1257,7 +1262,7 @@@ prepare_possible_alternates(name, &reference); - if (clone_submodule(path, sm_gitdir, url, depth, &reference, + if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate, quiet, progress)) die(_("clone of '%s' into submodule path '%s' failed"), url, path); @@@ -1313,7 -1309,6 +1314,7 @@@ struct submodule_update_clone int quiet; int recommend_shallow; struct string_list references; + int dissociate; const char *depth; const char *recursive_prefix; const char *prefix; @@@ -1329,7 -1324,7 +1330,7 @@@ int failed_clones_nr, failed_clones_alloc; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ - SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \ + SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \ NULL, NULL, NULL, \ STRING_LIST_INIT_DUP, 0, NULL, 0, 0} @@@ -1456,8 -1451,6 +1457,8 @@@ static int prepare_to_clone_next_submod for_each_string_list_item(item, &suc->references) argv_array_pushl(&child->args, "--reference", item->string, NULL); } + if (suc->dissociate) + argv_array_push(&child->args, "--dissociate"); if (suc->depth) argv_array_push(&child->args, suc->depth); @@@ -1591,8 -1584,6 +1592,8 @@@ static int update_clone(int argc, cons N_("rebase, merge, checkout or none")), OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"), N_("reference repository")), + OPT_BOOL(0, "dissociate", &suc.dissociate, + N_("use --reference only while cloning")), OPT_STRING(0, "depth", &suc.depth, "", N_("Create a shallow clone truncated to the " "specified number of revisions")), @@@ -1753,13 -1744,14 +1754,14 @@@ static int push_check(int argc, const c /* Check the refspec */ if (argc > 2) { - int i, refspec_nr = argc - 2; + int i; struct ref *local_refs = get_local_heads(); - struct refspec *refspec = parse_push_refspec(refspec_nr, - argv + 2); + struct refspec refspec = REFSPEC_INIT_PUSH; - for (i = 0; i < refspec_nr; i++) { - struct refspec *rs = refspec + i; + refspec_appendn(&refspec, argv + 2, argc - 2); + + for (i = 0; i < refspec.nr; i++) { + const struct refspec_item *rs = &refspec.items[i]; if (rs->pattern || rs->matching) continue; @@@ -1786,7 -1778,7 +1788,7 @@@ rs->src); } } - free_refspec(refspec_nr, refspec); + refspec_clear(&refspec); } free(head); @@@ -1835,29 -1827,6 +1837,29 @@@ static int is_active(int argc, const ch return !is_submodule_active(the_repository, argv[1]); } +/* + * Exit non-zero if any of the submodule names given on the command line is + * invalid. If no names are given, filter stdin to print only valid names + * (which is primarily intended for testing). + */ +static int check_name(int argc, const char **argv, const char *prefix) +{ + if (argc > 1) { + while (*++argv) { + if (check_submodule_name(*argv) < 0) + return 1; + } + } else { + struct strbuf buf = STRBUF_INIT; + while (strbuf_getline(&buf, stdin) != EOF) { + if (!check_submodule_name(buf.buf)) + printf("%s\n", buf.buf); + } + strbuf_release(&buf); + } + return 0; +} + #define SUPPORT_SUPER_PREFIX (1<<0) struct cmd_struct { @@@ -1883,7 -1852,6 +1885,7 @@@ static struct cmd_struct commands[] = {"push-check", push_check, 0}, {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, {"is-active", is_active, 0}, + {"check-name", check_name, 0}, }; int cmd_submodule__helper(int argc, const char **argv, const char *prefix) diff --combined http-push.c index 2669f4bfa1,ea5af6227e..7e38522098 --- a/http-push.c +++ b/http-push.c @@@ -1331,7 -1331,7 +1331,7 @@@ static int get_delta(struct rev_info *r int count = 0; while ((commit = get_revision(revs)) != NULL) { - p = process_tree(commit->tree, p); + p = process_tree(get_commit_tree(commit), p); commit->object.flags |= LOCAL; if (!(commit->object.flags & UNINTERESTING)) count += add_send_request(&commit->object, lock); @@@ -1692,8 -1692,7 +1692,7 @@@ int cmd_main(int argc, const char **arg { struct transfer_request *request; struct transfer_request *next_request; - int nr_refspec = 0; - const char **refspec = NULL; + struct refspec rs = REFSPEC_INIT_PUSH; struct remote_lock *ref_lock = NULL; struct remote_lock *info_ref_lock = NULL; struct rev_info revs; @@@ -1756,8 -1755,7 +1755,7 @@@ } continue; } - refspec = argv; - nr_refspec = argc - i; + refspec_appendn(&rs, argv, argc - i); break; } @@@ -1768,7 -1766,7 +1766,7 @@@ if (!repo->url) usage(http_push_usage); - if (delete_branch && nr_refspec != 1) + if (delete_branch && rs.nr != 1) die("You must specify only one branch name when deleting a remote branch"); setup_git_directory(); @@@ -1814,18 -1812,18 +1812,18 @@@ /* Remove a remote branch if -d or -D was specified */ if (delete_branch) { - if (delete_remote_branch(refspec[0], force_delete) == -1) { + const char *branch = rs.items[i].src; + if (delete_remote_branch(branch, force_delete) == -1) { fprintf(stderr, "Unable to delete remote branch %s\n", - refspec[0]); + branch); if (helper_status) - printf("error %s cannot remove\n", refspec[0]); + printf("error %s cannot remove\n", branch); } goto cleanup; } /* match them up */ - if (match_push_refs(local_refs, &remote_refs, - nr_refspec, (const char **) refspec, push_all)) { + if (match_push_refs(local_refs, &remote_refs, &rs, push_all)) { rc = -1; goto cleanup; } diff --combined remote.c index 238689ae28,0d1a3d07f8..abe80c1397 --- a/remote.c +++ b/remote.c @@@ -2,6 -2,7 +2,7 @@@ #include "config.h" #include "remote.h" #include "refs.h" + #include "refspec.h" #include "commit.h" #include "diff.h" #include "revision.h" @@@ -13,18 -14,6 +14,6 @@@ enum map_direction { FROM_SRC, FROM_DST }; - static struct refspec s_tag_refspec = { - 0, - 1, - 0, - 0, - "refs/tags/*", - "refs/tags/*" - }; - - /* See TAG_REFSPEC for the string version */ - const struct refspec *tag_refspec = &s_tag_refspec; - struct counted_string { size_t len; const char *s; @@@ -88,33 -77,6 +77,6 @@@ static const char *alias_url(const cha return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len); } - static void add_push_refspec(struct remote *remote, const char *ref) - { - ALLOC_GROW(remote->push_refspec, - remote->push_refspec_nr + 1, - remote->push_refspec_alloc); - remote->push_refspec[remote->push_refspec_nr++] = ref; - } - - static void add_fetch_refspec(struct remote *remote, const char *ref) - { - ALLOC_GROW(remote->fetch_refspec, - remote->fetch_refspec_nr + 1, - remote->fetch_refspec_alloc); - remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; - } - - void add_prune_tags_to_fetch_refspec(struct remote *remote) - { - int nr = remote->fetch_refspec_nr; - int bufsize = nr + 1; - int size = sizeof(struct refspec); - - remote->fetch = xrealloc(remote->fetch, size * bufsize); - memcpy(&remote->fetch[nr], tag_refspec, size); - add_fetch_refspec(remote, xstrdup(TAG_REFSPEC)); - } - static void add_url(struct remote *remote, const char *url) { ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); @@@ -186,9 -148,12 +148,12 @@@ static struct remote *make_remote(cons ret = xcalloc(1, sizeof(struct remote)); ret->prune = -1; /* unspecified */ ret->prune_tags = -1; /* unspecified */ + ret->name = xstrndup(name, len); + refspec_init(&ret->push, REFSPEC_PUSH); + refspec_init(&ret->fetch, REFSPEC_FETCH); + ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); remotes[remotes_nr++] = ret; - ret->name = xstrndup(name, len); hashmap_entry_init(ret, lookup_entry.hash); replaced = hashmap_put(&remotes_hash, ret); @@@ -286,9 -251,9 +251,9 @@@ static void read_remotes_file(struct re if (skip_prefix(buf.buf, "URL:", &v)) add_url_alias(remote, xstrdup(skip_spaces(v))); else if (skip_prefix(buf.buf, "Push:", &v)) - add_push_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->push, skip_spaces(v)); else if (skip_prefix(buf.buf, "Pull:", &v)) - add_fetch_refspec(remote, xstrdup(skip_spaces(v))); + refspec_append(&remote->fetch, skip_spaces(v)); } strbuf_release(&buf); fclose(f); @@@ -327,15 -292,19 +292,19 @@@ static void read_branches_file(struct r frag = "master"; add_url_alias(remote, strbuf_detach(&buf, NULL)); - add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s", - frag, remote->name)); + strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s", + frag, remote->name); + refspec_append(&remote->fetch, buf.buf); /* * Cogito compatible push: push current HEAD to remote #branch * (master if missing) */ - add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag)); + strbuf_reset(&buf); + strbuf_addf(&buf, "HEAD:refs/heads/%s", frag); + refspec_append(&remote->push, buf.buf); remote->fetch_tags = 1; /* always auto-follow */ + strbuf_release(&buf); } static int handle_config(const char *key, const char *value, void *cb) @@@ -420,12 -389,14 +389,14 @@@ const char *v; if (git_config_string(&v, key, value)) return -1; - add_push_refspec(remote, v); + refspec_append(&remote->push, v); + free((char *)v); } else if (!strcmp(subkey, "fetch")) { const char *v; if (git_config_string(&v, key, value)) return -1; - add_fetch_refspec(remote, v); + refspec_append(&remote->fetch, v); + free((char *)v); } else if (!strcmp(subkey, "receivepack")) { const char *v; if (git_config_string(&v, key, value)) @@@ -499,158 -470,6 +470,6 @@@ static void read_config(void alias_all_urls(); } - static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) - { - int i; - struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs)); - - for (i = 0; i < nr_refspec; i++) { - size_t llen; - int is_glob; - const char *lhs, *rhs; - int flags; - - is_glob = 0; - - lhs = refspec[i]; - if (*lhs == '+') { - rs[i].force = 1; - lhs++; - } - - rhs = strrchr(lhs, ':'); - - /* - * Before going on, special case ":" (or "+:") as a refspec - * for pushing matching refs. - */ - if (!fetch && rhs == lhs && rhs[1] == '\0') { - rs[i].matching = 1; - continue; - } - - if (rhs) { - size_t rlen = strlen(++rhs); - is_glob = (1 <= rlen && strchr(rhs, '*')); - rs[i].dst = xstrndup(rhs, rlen); - } - - llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); - if (1 <= llen && memchr(lhs, '*', llen)) { - if ((rhs && !is_glob) || (!rhs && fetch)) - goto invalid; - is_glob = 1; - } else if (rhs && is_glob) { - goto invalid; - } - - rs[i].pattern = is_glob; - rs[i].src = xstrndup(lhs, llen); - flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); - - if (fetch) { - struct object_id unused; - - /* LHS */ - if (!*rs[i].src) - ; /* empty is ok; it means "HEAD" */ - else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused)) - rs[i].exact_sha1 = 1; /* ok */ - else if (!check_refname_format(rs[i].src, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - /* RHS */ - if (!rs[i].dst) - ; /* missing is ok; it is the same as empty */ - else if (!*rs[i].dst) - ; /* empty is ok; it means "do not store" */ - else if (!check_refname_format(rs[i].dst, flags)) - ; /* valid looking ref is ok */ - else - goto invalid; - } else { - /* - * LHS - * - empty is allowed; it means delete. - * - when wildcarded, it must be a valid looking ref. - * - otherwise, it must be an extended SHA-1, but - * there is no existing way to validate this. - */ - if (!*rs[i].src) - ; /* empty is ok */ - else if (is_glob) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } - else - ; /* anything goes, for now */ - /* - * RHS - * - missing is allowed, but LHS then must be a - * valid looking ref. - * - empty is not allowed. - * - otherwise it must be a valid looking ref. - */ - if (!rs[i].dst) { - if (check_refname_format(rs[i].src, flags)) - goto invalid; - } else if (!*rs[i].dst) { - goto invalid; - } else { - if (check_refname_format(rs[i].dst, flags)) - goto invalid; - } - } - } - return rs; - - invalid: - if (verify) { - /* - * nr_refspec must be greater than zero and i must be valid - * since it is only possible to reach this point from within - * the for loop above. - */ - free_refspec(i+1, rs); - return NULL; - } - die("Invalid refspec '%s'", refspec[i]); - } - - int valid_fetch_refspec(const char *fetch_refspec_str) - { - struct refspec *refspec; - - refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1); - free_refspec(1, refspec); - return !!refspec; - } - - struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec) - { - return parse_refspec_internal(nr_refspec, refspec, 1, 0); - } - - struct refspec *parse_push_refspec(int nr_refspec, const char **refspec) - { - return parse_refspec_internal(nr_refspec, refspec, 0, 0); - } - - void free_refspec(int nr_refspec, struct refspec *refspec) - { - int i; - - if (!refspec) - return; - - for (i = 0; i < nr_refspec; i++) { - free(refspec[i].src); - free(refspec[i].dst); - } - free(refspec); - } - static int valid_remote_nick(const char *name) { if (!name[0] || is_dot_or_dotdot(name)) @@@ -705,9 -524,8 +524,8 @@@ const char *remote_ref_for_branch(struc pushremote_for_branch(branch, NULL); struct remote *remote = remote_get(remote_name); - if (remote && remote->push_refspec_nr && - (dst = apply_refspecs(remote->push, - remote->push_refspec_nr, + if (remote && remote->push.nr && + (dst = apply_refspecs(&remote->push, branch->refname))) { if (explicit) *explicit = 1; @@@ -744,8 -562,6 +562,6 @@@ static struct remote *remote_get_1(cons add_url_alias(ret, name); if (!valid_remote(ret)) return NULL; - ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec); - ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec); return ret; } @@@ -776,12 -592,6 +592,6 @@@ int for_each_remote(each_remote_fn fn, struct remote *r = remotes[i]; if (!r) continue; - if (!r->fetch) - r->fetch = parse_fetch_refspec(r->fetch_refspec_nr, - r->fetch_refspec); - if (!r->push) - r->push = parse_push_refspec(r->push_refspec_nr, - r->push_refspec); result = fn(r, priv); } return result; @@@ -887,7 -697,9 +697,9 @@@ static int match_name_with_pattern(cons return ret; } - static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results) + static void query_refspecs_multiple(struct refspec *rs, + struct refspec_item *query, + struct string_list *results) { int i; int find_src = !query->src; @@@ -895,8 -707,8 +707,8 @@@ if (find_src && !query->dst) error("query_refspecs_multiple: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *refspec = &rs->items[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; const char *needle = find_src ? query->dst : query->src; @@@ -913,7 -725,7 +725,7 @@@ } } - int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) + int query_refspecs(struct refspec *rs, struct refspec_item *query) { int i; int find_src = !query->src; @@@ -923,8 -735,8 +735,8 @@@ if (find_src && !query->dst) return error("query_refspecs: need either src or dst"); - for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *refspec = &rs->items[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; @@@ -944,23 -756,22 +756,22 @@@ return -1; } - char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name) + char *apply_refspecs(struct refspec *rs, const char *name) { - struct refspec query; + struct refspec_item query; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.src = (char *)name; - if (query_refspecs(refspecs, nr_refspec, &query)) + if (query_refspecs(rs, &query)) return NULL; return query.dst; } - int remote_find_tracking(struct remote *remote, struct refspec *refspec) + int remote_find_tracking(struct remote *remote, struct refspec_item *refspec) { - return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); + return query_refspecs(&remote->fetch, refspec); } static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen, @@@ -1167,7 -978,7 +978,7 @@@ static char *guess_ref(const char *name } static int match_explicit_lhs(struct ref *src, - struct refspec *rs, + struct refspec_item *rs, struct ref **match, int *allocated_match) { @@@ -1193,7 -1004,7 +1004,7 @@@ static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, - struct refspec *rs) + struct refspec_item *rs) { struct ref *matched_src, *matched_dst; int allocated_src; @@@ -1262,36 -1073,37 +1073,37 @@@ } static int match_explicit_refs(struct ref *src, struct ref *dst, - struct ref ***dst_tail, struct refspec *rs, - int rs_nr) + struct ref ***dst_tail, struct refspec *rs) { int i, errs; - for (i = errs = 0; i < rs_nr; i++) - errs += match_explicit(src, dst, dst_tail, &rs[i]); + for (i = errs = 0; i < rs->nr; i++) + errs += match_explicit(src, dst, dst_tail, &rs->items[i]); return errs; } - static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, - int send_mirror, int direction, const struct refspec **ret_pat) + static char *get_ref_match(const struct refspec *rs, const struct ref *ref, + int send_mirror, int direction, + const struct refspec_item **ret_pat) { - const struct refspec *pat; + const struct refspec_item *pat; char *name; int i; int matching_refs = -1; - for (i = 0; i < rs_nr; i++) { - if (rs[i].matching && - (matching_refs == -1 || rs[i].force)) { + for (i = 0; i < rs->nr; i++) { + const struct refspec_item *item = &rs->items[i]; + if (item->matching && + (matching_refs == -1 || item->force)) { matching_refs = i; continue; } - if (rs[i].pattern) { - const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; + if (item->pattern) { + const char *dst_side = item->dst ? item->dst : item->src; int match; if (direction == FROM_SRC) - match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name); + match = match_name_with_pattern(item->src, ref->name, dst_side, &name); else - match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name); + match = match_name_with_pattern(dst_side, ref->name, item->src, &name); if (match) { matching_refs = i; break; @@@ -1301,7 -1113,7 +1113,7 @@@ if (matching_refs == -1) return NULL; - pat = rs + matching_refs; + pat = &rs->items[matching_refs]; if (pat->matching) { /* * "matching refs"; traditionally we pushed everything @@@ -1376,7 -1188,7 +1188,7 @@@ static void add_missing_tags(struct re continue; /* not a tag */ if (string_list_has_string(&dst_tag, ref->name)) continue; /* they already have it */ - if (oid_object_info(&ref->new_oid, NULL) != OBJ_TAG) + if (oid_object_info(the_repository, &ref->new_oid, NULL) != OBJ_TAG) continue; /* be conservative */ item = string_list_append(&src_tag, ref->name); item->util = ref; @@@ -1443,22 -1255,20 +1255,20 @@@ static void prepare_ref_index(struct st * but we can catch some errors early before even talking to the * remote side. */ - int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) + int check_push_refs(struct ref *src, struct refspec *rs) { - struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names); int ret = 0; int i; - for (i = 0; i < nr_refspec; i++) { - struct refspec *rs = refspec + i; + for (i = 0; i < rs->nr; i++) { + struct refspec_item *item = &rs->items[i]; - if (rs->pattern || rs->matching) + if (item->pattern || item->matching) continue; - ret |= match_explicit_lhs(src, rs, NULL, NULL); + ret |= match_explicit_lhs(src, item, NULL, NULL); } - free_refspec(nr_refspec, refspec); return ret; } @@@ -1471,32 -1281,29 +1281,29 @@@ * dst (e.g. pushing to a new branch, done in match_explicit_refs). */ int match_push_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int flags) + struct refspec *rs, int flags) { - struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; int send_prune = flags & MATCH_REFS_PRUNE; int errs; - static const char *default_refspec[] = { ":", NULL }; struct ref *ref, **dst_tail = tail_ref(dst); struct string_list dst_ref_index = STRING_LIST_INIT_NODUP; - if (!nr_refspec) { - nr_refspec = 1; - refspec = default_refspec; - } - rs = parse_push_refspec(nr_refspec, (const char **) refspec); - errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec); + /* If no refspec is provided, use the default ":" */ + if (!rs->nr) + refspec_append(rs, ":"); + + errs = match_explicit_refs(src, *dst, &dst_tail, rs); /* pick the remainder */ for (ref = src; ref; ref = ref->next) { struct string_list_item *dst_item; struct ref *dst_peer; - const struct refspec *pat = NULL; + const struct refspec_item *pat = NULL; char *dst_name; - dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat); + dst_name = get_ref_match(rs, ref, send_mirror, FROM_SRC, &pat); if (!dst_name) continue; @@@ -1545,7 -1352,7 +1352,7 @@@ /* We're already sending something to this ref. */ continue; - src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL); + src_name = get_ref_match(rs, ref, send_mirror, FROM_DST, NULL); if (src_name) { if (!src_ref_index.nr) prepare_ref_index(&src_ref_index, src); @@@ -1557,6 -1364,7 +1364,7 @@@ } string_list_clear(&src_ref_index, 0); } + if (errs) return -1; return 0; @@@ -1753,7 -1561,7 +1561,7 @@@ static const char *tracking_for_push_de { char *ret; - ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + ret = apply_refspecs(&remote->fetch, refname); if (!ret) return error_buf(err, _("push destination '%s' on remote '%s' has no local tracking branch"), @@@ -1771,12 -1579,11 +1579,11 @@@ static const char *branch_get_push_1(st _("branch '%s' has no remote for pushing"), branch->name); - if (remote->push_refspec_nr) { + if (remote->push.nr) { char *dst; const char *ret; - dst = apply_refspecs(remote->push, remote->push_refspec_nr, - branch->refname); + dst = apply_refspecs(&remote->push, branch->refname); if (!dst) return error_buf(err, _("push refspecs for '%s' do not include '%s'"), @@@ -1819,7 -1626,7 +1626,7 @@@ } } - die("BUG: unhandled push situation"); + BUG("unhandled push situation"); } const char *branch_get_push(struct branch *branch, struct strbuf *err) @@@ -1849,7 -1656,7 +1656,7 @@@ static int ignore_symref_update(const c * local symbolic ref. */ static struct ref *get_expanded_map(const struct ref *remote_refs, - const struct refspec *refspec) + const struct refspec_item *refspec) { const struct ref *ref; struct ref *ret = NULL; @@@ -1914,7 -1721,7 +1721,7 @@@ static struct ref *get_local_ref(const } int get_fetch_map(const struct ref *remote_refs, - const struct refspec *refspec, + const struct refspec_item *refspec, struct ref ***tail, int missing_ok) { @@@ -2252,8 -2059,7 +2059,7 @@@ struct ref *guess_remote_head(const str struct stale_heads_info { struct string_list *ref_names; struct ref **stale_refs_tail; - struct refspec *refs; - int ref_count; + struct refspec *rs; }; static int get_stale_heads_cb(const char *refname, const struct object_id *oid, @@@ -2261,12 -2067,12 +2067,12 @@@ { struct stale_heads_info *info = cb_data; struct string_list matches = STRING_LIST_INIT_DUP; - struct refspec query; + struct refspec_item query; int i, stale = 1; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.dst = (char *)refname; - query_refspecs_multiple(info->refs, info->ref_count, &query, &matches); + query_refspecs_multiple(info->rs, &query, &matches); if (matches.nr == 0) goto clean_exit; /* No matches */ @@@ -2294,7 -2100,7 +2100,7 @@@ clean_exit return 0; } - struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map) + struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map) { struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; @@@ -2302,8 -2108,7 +2108,7 @@@ info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; - info.refs = refs; - info.ref_count = ref_count; + info.rs = rs; for (ref = fetch_map; ref; ref = ref->next) string_list_append(&ref_names, ref->name); string_list_sort(&ref_names); @@@ -2387,7 -2192,7 +2192,7 @@@ static int remote_tracking(struct remot { char *dst; - dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname); + dst = apply_refspecs(&remote->fetch, refname); if (!dst) return -1; /* no tracking ref for refname at remote */ if (read_ref(dst, oid)) diff --combined remote.h index 93dd97e25f,62a6566594..45ecc6cefa --- a/remote.h +++ b/remote.h @@@ -3,6 -3,7 +3,7 @@@ #include "parse-options.h" #include "hashmap.h" + #include "refspec.h" enum { REMOTE_UNCONFIGURED = 0, @@@ -27,15 -28,9 +28,9 @@@ struct remote int pushurl_nr; int pushurl_alloc; - const char **push_refspec; - struct refspec *push; - int push_refspec_nr; - int push_refspec_alloc; + struct refspec push; - const char **fetch_refspec; - struct refspec *fetch; - int fetch_refspec_nr; - int fetch_refspec_alloc; + struct refspec fetch; /* * -1 to never fetch tags @@@ -68,18 -63,6 +63,6 @@@ int for_each_remote(each_remote_fn fn, int remote_has_url(struct remote *remote, const char *url); - struct refspec { - unsigned force : 1; - unsigned pattern : 1; - unsigned matching : 1; - unsigned exact_sha1 : 1; - - char *src; - char *dst; - }; - - extern const struct refspec *tag_refspec; - struct ref { struct ref *next; struct object_id old_oid; @@@ -153,7 -136,6 +136,7 @@@ void free_refs(struct ref *ref) struct oid_array; struct packet_reader; struct argv_array; +struct string_list; extern struct ref **get_remote_heads(struct packet_reader *reader, struct ref **list, unsigned int flags, struct oid_array *extra_have, @@@ -162,8 -144,7 +145,8 @@@ /* Used for protocol v2 in order to retrieve refs from a remote */ extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, struct ref **list, int for_push, - const struct argv_array *ref_prefixes); + const struct argv_array *ref_prefixes, + const struct string_list *server_options); int resolve_remote_symref(struct ref *ref, struct ref *list); int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); @@@ -177,19 -158,12 +160,12 @@@ */ struct ref *ref_remove_duplicates(struct ref *ref_map); - int valid_fetch_refspec(const char *refspec); - struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); - extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); + int query_refspecs(struct refspec *rs, struct refspec_item *query); + char *apply_refspecs(struct refspec *rs, const char *name); - void free_refspec(int nr_refspec, struct refspec *refspec); - - extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query); - char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name); - - int check_push_refs(struct ref *src, int nr_refspec, const char **refspec); + int check_push_refs(struct ref *src, struct refspec *rs); int match_push_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int all); + struct refspec *rs, int flags); void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, int force_update); @@@ -205,7 -179,7 +181,7 @@@ * missing_ok is usually false, but when we are adding branch.$name.merge * it is Ok if the branch is not at the remote anymore. */ - int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec, + int get_fetch_map(const struct ref *remote_refs, const struct refspec_item *refspec, struct ref ***tail, int missing_ok); struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); @@@ -213,7 -187,7 +189,7 @@@ /* * For the given remote, reads the refspec's src and sets the other fields. */ - int remote_find_tracking(struct remote *remote, struct refspec *refspec); + int remote_find_tracking(struct remote *remote, struct refspec_item *refspec); struct branch { const char *name; @@@ -223,7 -197,7 +199,7 @@@ const char *pushremote_name; const char **merge_name; - struct refspec **merge; + struct refspec_item **merge; int merge_nr; int merge_alloc; @@@ -292,7 -266,7 +268,7 @@@ struct ref *guess_remote_head(const str int all); /* Return refs which no longer exist on remote */ - struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); + struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map); /* * Compare-and-swap @@@ -315,8 -289,4 +291,4 @@@ extern int parseopt_push_cas_option(con extern int is_empty_cas(const struct push_cas_option *); void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *); - #define TAG_REFSPEC "refs/tags/*:refs/tags/*" - - void add_prune_tags_to_fetch_refspec(struct remote *remote); - #endif diff --combined submodule.c index 1f88623893,cdeadd80e7..47d005797e --- a/submodule.c +++ b/submodule.c @@@ -820,7 -820,7 +820,7 @@@ static int check_has_commit(const struc { struct has_commit_data *cb = data; - enum object_type type = oid_object_info(oid, NULL); + enum object_type type = oid_object_info(the_repository, oid, NULL); switch (type) { case OBJ_COMMIT: @@@ -968,7 -968,7 +968,7 @@@ int find_unpushed_submodules(struct oid static int push_submodule(const char *path, const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run) { @@@ -991,8 -991,8 +991,8 @@@ if (remote->origin != REMOTE_UNCONFIGURED) { int i; argv_array_push(&cp.args, remote->name); - for (i = 0; i < refspec_nr; i++) - argv_array_push(&cp.args, refspec[i]); + for (i = 0; i < rs->raw_nr; i++) + argv_array_push(&cp.args, rs->raw[i]); } prepare_submodule_repo_env(&cp.env_array); @@@ -1013,7 -1013,7 +1013,7 @@@ */ static void submodule_push_check(const char *path, const char *head, const struct remote *remote, - const char **refspec, int refspec_nr) + const struct refspec *rs) { struct child_process cp = CHILD_PROCESS_INIT; int i; @@@ -1023,8 -1023,8 +1023,8 @@@ argv_array_push(&cp.args, head); argv_array_push(&cp.args, remote->name); - for (i = 0; i < refspec_nr; i++) - argv_array_push(&cp.args, refspec[i]); + for (i = 0; i < rs->raw_nr; i++) + argv_array_push(&cp.args, rs->raw[i]); prepare_submodule_repo_env(&cp.env_array); cp.git_cmd = 1; @@@ -1043,7 -1043,7 +1043,7 @@@ int push_unpushed_submodules(struct oid_array *commits, const struct remote *remote, - const char **refspec, int refspec_nr, + const struct refspec *rs, const struct string_list *push_options, int dry_run) { @@@ -1069,8 -1069,7 +1069,7 @@@ for (i = 0; i < needs_pushing.nr; i++) submodule_push_check(needs_pushing.items[i].string, - head, remote, - refspec, refspec_nr); + head, remote, rs); free(head); } @@@ -1078,7 -1077,7 +1077,7 @@@ for (i = 0; i < needs_pushing.nr; i++) { const char *path = needs_pushing.items[i].string; fprintf(stderr, "Pushing submodule '%s'\n", path); - if (!push_submodule(path, remote, refspec, refspec_nr, + if (!push_submodule(path, remote, rs, push_options, dry_run)) { fprintf(stderr, "Unable to push submodule '%s'\n", path); ret = 0; @@@ -1400,7 -1399,7 +1399,7 @@@ unsigned is_submodule_modified(const ch buf.buf[0] == '2') { /* T = line type, XY = status, SSSS = submodule state */ if (buf.len < strlen("T XY SSSS")) - die("BUG: invalid status --porcelain=2 line %s", + BUG("invalid status --porcelain=2 line %s", buf.buf); if (buf.buf[5] == 'S' && buf.buf[8] == 'U') @@@ -1569,7 -1568,7 +1568,7 @@@ static void submodule_reset_index(cons get_super_prefix_or_empty(), path); argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL); - argv_array_push(&cp.args, EMPTY_TREE_SHA1_HEX); + argv_array_push(&cp.args, empty_tree_oid_hex()); if (run_command(&cp)) die("could not reset submodule index"); @@@ -1609,7 -1608,7 +1608,7 @@@ int submodule_move_head(const char *pat sub = submodule_from_path(the_repository, &null_oid, path); if (!sub) - die("BUG: could not get submodule information for '%s'", path); + BUG("could not get submodule information for '%s'", path); if (old_head && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) { /* Check if the submodule has a dirty index. */ @@@ -1661,9 -1660,9 +1660,9 @@@ argv_array_push(&cp.args, "-m"); if (!(flags & SUBMODULE_MOVE_HEAD_FORCE)) - argv_array_push(&cp.args, old_head ? old_head : EMPTY_TREE_SHA1_HEX); + argv_array_push(&cp.args, old_head ? old_head : empty_tree_oid_hex()); - argv_array_push(&cp.args, new_head ? new_head : EMPTY_TREE_SHA1_HEX); + argv_array_push(&cp.args, new_head ? new_head : empty_tree_oid_hex()); if (run_command(&cp)) { ret = -1; @@@ -1967,7 -1966,7 +1966,7 @@@ void absorb_git_dir_into_superproject(c struct strbuf sb = STRBUF_INIT; if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES) - die("BUG: we don't know how to pass the flags down?"); + BUG("we don't know how to pass the flags down?"); strbuf_addstr(&sb, get_super_prefix_or_empty()); strbuf_addstr(&sb, path); @@@ -2045,7 -2044,7 +2044,7 @@@ const char *get_superproject_working_tr if (super_sub_len > cwd_len || strcmp(&cwd[cwd_len - super_sub_len], super_sub)) - die (_("BUG: returned path string doesn't match cwd?")); + BUG("returned path string doesn't match cwd?"); super_wt = xstrdup(cwd); super_wt[cwd_len - super_sub_len] = '\0'; diff --combined t/t5702-protocol-v2.sh index 4ad5c5769b,b6c72ab51e..a4fe6508bd --- a/t/t5702-protocol-v2.sh +++ b/t/t5702-protocol-v2.sh @@@ -154,22 -154,6 +154,22 @@@ test_expect_success 'ref advertisment i test_cmp actual expect ' +test_expect_success 'server-options are sent when using ls-remote' ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \ + ls-remote -o hello -o world "file://$(pwd)/file_parent" master >actual && + + cat >expect <<-EOF && + $(git -C file_parent rev-parse refs/heads/master)$(printf "\t")refs/heads/master + EOF + + test_cmp actual expect && + grep "server-option=hello" log && + grep "server-option=world" log +' + + test_expect_success 'clone with file:// using protocol v2' ' test_when_finished "rm -f log" && @@@ -217,134 -201,20 +217,148 @@@ test_expect_success 'ref advertisment i ! grep "refs/tags/three" log ' +test_expect_success 'server-options are sent when fetching' ' + test_when_finished "rm -f log" && + + test_commit -C file_parent four && + + GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \ + fetch -o hello -o world origin master && + + git -C file_child log -1 --format=%s origin/master >actual && + git -C file_parent log -1 --format=%s >expect && + test_cmp expect actual && + + grep "server-option=hello" log && + grep "server-option=world" log +' + +test_expect_success 'upload-pack respects config using protocol v2' ' + git init server && + write_script server/.git/hook <<-\EOF && + touch hookout + "$@" + EOF + test_commit -C server one && + + test_config_global uploadpack.packobjectshook ./hook && + test_path_is_missing server/.git/hookout && + git -c protocol.version=2 clone "file://$(pwd)/server" client && + test_path_is_file server/.git/hookout +' + +test_expect_success 'setup filter tests' ' + rm -rf server client && + git init server && + + # 1 commit to create a file, and 1 commit to modify it + test_commit -C server message1 a.txt && + test_commit -C server message2 a.txt && + git -C server config protocol.version 2 && + git -C server config uploadpack.allowfilter 1 && + git -C server config uploadpack.allowanysha1inwant 1 && + git -C server config protocol.version 2 +' + +test_expect_success 'partial clone' ' + GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \ + clone --filter=blob:none "file://$(pwd)/server" client && + grep "version 2" trace && + + # Ensure that the old version of the file is missing + git -C client rev-list master --quiet --objects --missing=print \ + >observed.oids && + grep "$(git -C server rev-parse message1:a.txt)" observed.oids && + + # Ensure that client passes fsck + git -C client fsck +' + +test_expect_success 'dynamically fetch missing object' ' + rm "$(pwd)/trace" && + GIT_TRACE_PACKET="$(pwd)/trace" git -C client -c protocol.version=2 \ + cat-file -p $(git -C server rev-parse message1:a.txt) && + grep "version 2" trace +' + +test_expect_success 'partial fetch' ' + rm -rf client "$(pwd)/trace" && + git init client && + SERVER="file://$(pwd)/server" && + test_config -C client extensions.partialClone "$SERVER" && + + GIT_TRACE_PACKET="$(pwd)/trace" git -C client -c protocol.version=2 \ + fetch --filter=blob:none "$SERVER" master:refs/heads/other && + grep "version 2" trace && + + # Ensure that the old version of the file is missing + git -C client rev-list other --quiet --objects --missing=print \ + >observed.oids && + grep "$(git -C server rev-parse message1:a.txt)" observed.oids && + + # Ensure that client passes fsck + git -C client fsck +' + +test_expect_success 'do not advertise filter if not configured to do so' ' + SERVER="file://$(pwd)/server" && + + rm "$(pwd)/trace" && + git -C server config uploadpack.allowfilter 1 && + GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \ + ls-remote "$SERVER" && + grep "fetch=.*filter" trace && + + rm "$(pwd)/trace" && + git -C server config uploadpack.allowfilter 0 && + GIT_TRACE_PACKET="$(pwd)/trace" git -c protocol.version=2 \ + ls-remote "$SERVER" && + grep "fetch=" trace >fetch_capabilities && + ! grep filter fetch_capabilities +' + +test_expect_success 'partial clone warns if filter is not advertised' ' + rm -rf client && + git -C server config uploadpack.allowfilter 0 && + git -c protocol.version=2 \ + clone --filter=blob:none "file://$(pwd)/server" client 2>err && + test_i18ngrep "filtering not recognized by server, ignoring" err +' + +test_expect_success 'even with handcrafted request, filter does not work if not advertised' ' + git -C server config uploadpack.allowfilter 0 && + + # Custom request that tries to filter even though it is not advertised. + test-pkt-line pack >in <<-EOF && + command=fetch + 0001 + want $(git -C server rev-parse master) + filter blob:none + 0000 + EOF + + test_must_fail git -C server serve --stateless-rpc /dev/null 2>err && + grep "unexpected line: .filter blob:none." err && + + # Exercise to ensure that if advertised, filter works + git -C server config uploadpack.allowfilter 1 && + git -C server serve --stateless-rpc /dev/null +' + + test_expect_success 'default refspec is used to filter ref when fetchcing' ' + test_when_finished "rm -f log" && + + GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \ + fetch origin && + + git -C file_child log -1 --format=%s three >actual && + git -C file_parent log -1 --format=%s three >expect && + test_cmp expect actual && + + grep "ref-prefix refs/heads/" log && + grep "ref-prefix refs/tags/" log + ' + # Test protocol v2 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh diff --combined transport.c index 6785fcceed,cbf0044c3e..a32da30dee --- a/transport.c +++ b/transport.c @@@ -11,6 -11,7 +11,7 @@@ #include "bundle.h" #include "dir.h" #include "refs.h" + #include "refspec.h" #include "branch.h" #include "url.h" #include "submodule.h" @@@ -268,7 -269,7 +269,7 @@@ static struct ref *get_refs_via_connect switch (data->version) { case protocol_v2: get_remote_refs(data->fd[1], &reader, &refs, for_push, - ref_prefixes); + ref_prefixes, transport->server_options); break; case protocol_v1: case protocol_v0: @@@ -316,7 -317,6 +317,7 @@@ static int fetch_refs_via_pack(struct t args.no_dependents = data->options.no_dependents; args.filter_options = data->options.filter_options; args.stateless_rpc = transport->stateless_rpc; + args.server_options = transport->server_options; if (!data->got_remote_heads) refs_tmp = get_refs_via_connect(transport, 0, NULL); @@@ -390,7 -390,7 +391,7 @@@ int transport_refs_pushed(struct ref *r void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) { - struct refspec rs; + struct refspec_item rs; if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) return; @@@ -619,29 -619,6 +620,6 @@@ void transport_print_push_status(const free(head); } - void transport_verify_remote_names(int nr_heads, const char **heads) - { - int i; - - for (i = 0; i < nr_heads; i++) { - const char *local = heads[i]; - const char *remote = strrchr(heads[i], ':'); - - if (*local == '+') - local++; - - /* A matching refspec is okay. */ - if (remote == local && remote[1] == '\0') - continue; - - remote = remote ? (remote + 1) : local; - if (check_refname_format(remote, - REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN)) - die("remote part of refspec is not a valid name in %s", - heads[i]); - } - } - static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags) { struct git_transport_data *data = transport->data; @@@ -737,7 -714,7 +715,7 @@@ void transport_take_over(struct transpo struct git_transport_data *data; if (!transport->smart_options) - die("BUG: taking over transport requires non-NULL " + BUG("taking over transport requires non-NULL " "smart_options field."); data = xcalloc(1, sizeof(*data)); @@@ -862,7 -839,7 +840,7 @@@ int is_transport_allowed(const char *ty return from_user; } - die("BUG: invalid protocol_allow_config type"); + BUG("invalid protocol_allow_config type"); } void transport_check_allowed(const char *type) @@@ -1093,11 -1070,10 +1071,10 @@@ static int run_pre_push_hook(struct tra } int transport_push(struct transport *transport, - int refspec_nr, const char **refspec, int flags, + struct refspec *rs, int flags, unsigned int *reject_reasons) { *reject_reasons = 0; - transport_verify_remote_names(refspec_nr, refspec); if (transport_color_config() < 0) return -1; @@@ -1111,38 -1087,17 +1088,17 @@@ int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int push_ret, ret, err; - struct refspec *tmp_rs; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; - int i; - if (check_push_refs(local_refs, refspec_nr, refspec) < 0) + if (check_push_refs(local_refs, rs) < 0) return -1; - tmp_rs = parse_push_refspec(refspec_nr, refspec); - for (i = 0; i < refspec_nr; i++) { - const char *prefix = NULL; - - if (tmp_rs[i].dst) - prefix = tmp_rs[i].dst; - else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1) - prefix = tmp_rs[i].src; - - if (prefix) { - const char *glob = strchr(prefix, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - prefix), - prefix); - else - expand_ref_prefix(&ref_prefixes, prefix); - } - } + refspec_ref_prefixes(rs, &ref_prefixes); remote_refs = transport->vtable->get_refs_list(transport, 1, &ref_prefixes); argv_array_clear(&ref_prefixes); - free_refspec(refspec_nr, tmp_rs); if (flags & TRANSPORT_PUSH_ALL) match_flags |= MATCH_REFS_ALL; @@@ -1153,10 -1108,8 +1109,8 @@@ if (flags & TRANSPORT_PUSH_FOLLOW_TAGS) match_flags |= MATCH_REFS_FOLLOW_TAGS; - if (match_push_refs(local_refs, &remote_refs, - refspec_nr, refspec, match_flags)) { + if (match_push_refs(local_refs, &remote_refs, rs, match_flags)) return -1; - } if (transport->smart_options && transport->smart_options->cas && @@@ -1185,7 -1138,7 +1139,7 @@@ if (!push_unpushed_submodules(&commits, transport->remote, - refspec, refspec_nr, + rs, transport->push_options, pretend)) { oid_array_clear(&commits); diff --combined transport.h index 73a7be3c8a,bac085ce0e..7792b08582 --- a/transport.h +++ b/transport.h @@@ -71,12 -71,6 +71,12 @@@ struct transport */ const struct string_list *push_options; + /* + * These strings will be passed to the remote side on each command + * request, if both sides support the server-option capability. + */ + const struct string_list *server_options; + char *pack_lockfile; signed verbose : 3; /** @@@ -203,7 -197,7 +203,7 @@@ void transport_set_verbosity(struct tra #define REJECT_NEEDS_FORCE 0x10 int transport_push(struct transport *connection, - int refspec_nr, const char **refspec, int flags, + struct refspec *rs, int flags, unsigned int * reject_reasons); /* @@@ -233,8 -227,6 +233,6 @@@ int transport_helper_init(struct transp int bidirectional_transfer_loop(int input, int output); /* common methods used by transport.c and builtin/send-pack.c */ - void transport_verify_remote_names(int nr_heads, const char **heads); - void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose); int transport_refs_pushed(struct ref *ref);