From: Junio C Hamano Date: Wed, 26 Oct 2011 23:16:29 +0000 (-0700) Subject: Merge branch 'cn/fetch-prune' X-Git-Tag: v1.7.8-rc0~14 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/9c0c09f791b1bfd2a04aa0e48190d304627293d2?ds=inline;hp=-c Merge branch 'cn/fetch-prune' * cn/fetch-prune: fetch: treat --tags like refs/tags/*:refs/tags/* when pruning fetch: honor the user-provided refspecs when pruning refs remote: separate out the remote_find_tracking logic into query_refspecs t5510: add tests for fetch --prune fetch: free all the additional refspecs Conflicts: remote.c --- 9c0c09f791b1bfd2a04aa0e48190d304627293d2 diff --combined builtin/fetch.c index 1adf6c176f,9d481f8ca9..91731b909a --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@ -13,7 -13,6 +13,7 @@@ #include "sigchain.h" #include "transport.h" #include "submodule.h" +#include "connected.h" static const char * const builtin_fetch_usage[] = { "git fetch [] [ [...]]", @@@ -346,18 -345,6 +346,18 @@@ static int update_local_ref(struct ref } } +static int iterate_ref_map(void *cb_data, unsigned char sha1[20]) +{ + struct ref **rm = cb_data; + struct ref *ref = *rm; + + if (!ref) + return -1; /* end of the list */ + *rm = ref->next; + hashcpy(sha1, ref->old_sha1); + return 0; +} + static int store_updated_refs(const char *raw_url, const char *remote_name, struct ref *ref_map) { @@@ -377,13 -364,6 +377,13 @@@ url = transport_anonymize_url(raw_url); else url = xstrdup("foreign"); + + rm = ref_map; + if (check_everything_connected(iterate_ref_map, 0, &rm)) { + rc = error(_("%s did not send all necessary objects\n"), url); + goto abort; + } + for (rm = ref_map; rm; rm = rm->next) { struct ref *ref = NULL; @@@ -464,15 -444,12 +464,15 @@@ fprintf(stderr, " %s\n", note); } } - free(url); - fclose(fp); + if (rc & STORE_REF_ERROR_DF_CONFLICT) error(_("some local refs could not be updated; try running\n" " 'git remote prune %s' to remove any old, conflicting " "branches"), remote_name); + + abort: + free(url); + fclose(fp); return rc; } @@@ -480,10 -457,23 +480,10 @@@ * We would want to bypass the object transfer altogether if * everything we are going to fetch already exists and is connected * locally. - * - * The refs we are going to fetch are in ref_map. If running - * - * $ git rev-list --objects --stdin --not --all - * - * (feeding all the refs in ref_map on its standard input) - * does not error out, that means everything reachable from the - * refs we are going to fetch exists and is connected to some of - * our existing refs. */ static int quickfetch(struct ref *ref_map) { - struct child_process revlist; - struct ref *ref; - int err; - const char *argv[] = {"rev-list", - "--quiet", "--objects", "--stdin", "--not", "--all", NULL}; + struct ref *rm = ref_map; /* * If we are deepening a shallow clone we already have these @@@ -494,7 -484,47 +494,7 @@@ */ if (depth) return -1; - - if (!ref_map) - return 0; - - memset(&revlist, 0, sizeof(revlist)); - revlist.argv = argv; - revlist.git_cmd = 1; - revlist.no_stdout = 1; - revlist.no_stderr = 1; - revlist.in = -1; - - err = start_command(&revlist); - if (err) { - error(_("could not run rev-list")); - return err; - } - - /* - * If rev-list --stdin encounters an unknown commit, it terminates, - * which will cause SIGPIPE in the write loop below. - */ - sigchain_push(SIGPIPE, SIG_IGN); - - for (ref = ref_map; ref; ref = ref->next) { - if (write_in_full(revlist.in, sha1_to_hex(ref->old_sha1), 40) < 0 || - write_str_in_full(revlist.in, "\n") < 0) { - if (errno != EPIPE && errno != EINVAL) - error(_("failed write to rev-list: %s"), strerror(errno)); - err = -1; - break; - } - } - - if (close(revlist.in)) { - error(_("failed to close rev-list's stdin: %s"), strerror(errno)); - err = -1; - } - - sigchain_pop(SIGPIPE); - - return finish_command(&revlist) || err; + return check_everything_connected(iterate_ref_map, 1, &rm); } static int fetch_refs(struct transport *transport, struct ref *ref_map) @@@ -510,10 -540,10 +510,10 @@@ return ret; } - static int prune_refs(struct transport *transport, struct ref *ref_map) + static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map) { int result = 0; - struct ref *ref, *stale_refs = get_stale_heads(transport->remote, ref_map); + struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map); const char *dangling_msg = dry_run ? _(" (%s will become dangling)\n") : _(" (%s has become dangling)\n"); @@@ -704,8 -734,31 +704,31 @@@ static int do_fetch(struct transport *t free_refs(ref_map); return 1; } - if (prune) - prune_refs(transport, ref_map); + if (prune) { + /* If --tags was specified, pretend the user gave us the canonical tags refspec */ + if (tags == TAGS_SET) { + const char *tags_str = "refs/tags/*:refs/tags/*"; + struct refspec *tags_refspec, *refspec; + + /* Copy the refspec and add the tags to it */ + refspec = xcalloc(ref_count + 1, sizeof(struct refspec)); + tags_refspec = parse_fetch_refspec(1, &tags_str); + memcpy(refspec, refs, ref_count * sizeof(struct refspec)); + memcpy(&refspec[ref_count], tags_refspec, sizeof(struct refspec)); + ref_count++; + + prune_refs(refspec, ref_count, ref_map); + + ref_count--; + /* The rest of the strings belong to fetch_one */ + free_refspec(1, tags_refspec); + free(refspec); + } else if (ref_count) { + prune_refs(refs, ref_count, ref_map); + } else { + prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map); + } + } free_refs(ref_map); /* if neither --no-tags nor --tags was specified, do automated tag @@@ -888,7 -941,7 +911,7 @@@ static int fetch_one(struct remote *rem atexit(unlock_pack); refspec = parse_fetch_refspec(ref_nr, refs); exit_code = do_fetch(transport, refspec, ref_nr); - free(refspec); + free_refspec(ref_nr, refspec); transport_disconnect(transport); transport = NULL; return exit_code; diff --combined builtin/remote.c index 44eb8795cd,de52367927..7335149799 --- a/builtin/remote.c +++ b/builtin/remote.c @@@ -349,7 -349,8 +349,8 @@@ static int get_ref_states(const struct else string_list_append(&states->tracked, abbrev_branch(ref->name)); } - stale_refs = get_stale_heads(states->remote, fetch_map); + stale_refs = get_stale_heads(states->remote->fetch, + states->remote->fetch_refspec_nr, fetch_map); for (ref = stale_refs; ref; ref = ref->next) { struct string_list_item *item = string_list_append(&states->stale, abbrev_branch(ref->name)); @@@ -389,8 -390,8 +390,8 @@@ static int get_push_ref_states(const st local_refs = get_local_heads(); push_map = copy_ref_list(remote_refs); - match_refs(local_refs, &push_map, remote->push_refspec_nr, - remote->push_refspec, MATCH_REFS_NONE); + match_push_refs(local_refs, &push_map, remote->push_refspec_nr, + remote->push_refspec, MATCH_REFS_NONE); states->push.strdup_strings = 1; for (ref = push_map; ref; ref = ref->next) { @@@ -570,7 -571,7 +571,7 @@@ static int read_remote_branches(const c unsigned char orig_sha1[20]; const char *symref; - strbuf_addf(&buf, "refs/remotes/%s", rename->old); + strbuf_addf(&buf, "refs/remotes/%s/", rename->old); if (!prefixcmp(refname, buf.buf)) { item = string_list_append(rename->remote_branches, xstrdup(refname)); symref = resolve_ref(refname, orig_sha1, 1, &flag); @@@ -621,11 -622,10 +622,11 @@@ static int mv(int argc, const char **ar OPT_END() }; struct remote *oldremote, *newremote; - struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT, + old_remote_context = STRBUF_INIT; struct string_list remote_branches = STRING_LIST_INIT_NODUP; struct rename_info rename; - int i; + int i, refspec_updated = 0; if (argc != 3) usage_with_options(builtin_remote_rename_usage, options); @@@ -660,25 -660,15 +661,25 @@@ strbuf_addf(&buf, "remote.%s.fetch", rename.new); if (git_config_set_multivar(buf.buf, NULL, NULL, 1)) return error("Could not remove config section '%s'", buf.buf); + strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old); for (i = 0; i < oldremote->fetch_refspec_nr; i++) { char *ptr; strbuf_reset(&buf2); strbuf_addstr(&buf2, oldremote->fetch_refspec[i]); - ptr = strstr(buf2.buf, rename.old); - if (ptr) - strbuf_splice(&buf2, ptr-buf2.buf, strlen(rename.old), - rename.new, strlen(rename.new)); + ptr = strstr(buf2.buf, old_remote_context.buf); + if (ptr) { + refspec_updated = 1; + strbuf_splice(&buf2, + ptr-buf2.buf + strlen(":refs/remotes/"), + strlen(rename.old), rename.new, + strlen(rename.new)); + } else + warning("Not updating non-default fetch respec\n" + "\t%s\n" + "\tPlease update the configuration manually if necessary.", + buf2.buf); + if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) return error("Could not append '%s'", buf.buf); } @@@ -696,9 -686,6 +697,9 @@@ } } + if (!refspec_updated) + return 0; + /* * First remove symrefs, then rename the rest, finally create * the new symrefs. diff --combined remote.c index 2f62c9a3ed,6ececc4a77..e2ef991144 --- a/remote.c +++ b/remote.c @@@ -492,6 -492,23 +492,6 @@@ static void read_config(void alias_all_urls(); } -/* - * We need to make sure the remote-tracking branches are well formed, but a - * wildcard refspec in "struct refspec" must have a trailing slash. We - * temporarily drop the trailing '/' while calling check_ref_format(), - * and put it back. The caller knows that a CHECK_REF_FORMAT_ONELEVEL - * error return is Ok for a wildcard refspec. - */ -static int verify_refname(char *name, int is_glob) -{ - int result; - - result = check_ref_format(name); - if (is_glob && result == CHECK_REF_FORMAT_WILDCARD) - result = CHECK_REF_FORMAT_OK; - return result; -} - /* * This function frees a refspec array. * Warning: code paths should be checked to ensure that the src @@@ -515,13 -532,13 +515,13 @@@ static void free_refspecs(struct refspe static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; - int st; struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); for (i = 0; i < nr_refspec; i++) { size_t llen; int is_glob; const char *lhs, *rhs; + int flags; is_glob = 0; @@@ -559,7 -576,6 +559,7 @@@ rs[i].pattern = is_glob; rs[i].src = xstrndup(lhs, llen); + flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); if (fetch) { /* @@@ -569,20 -585,26 +569,20 @@@ */ if (!*rs[i].src) ; /* empty is ok */ - else { - st = verify_refname(rs[i].src, is_glob); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) - goto invalid; - } + else if (check_refname_format(rs[i].src, flags)) + goto invalid; /* * RHS * - missing is ok, and is same as empty. * - empty is ok; it means not to store. * - otherwise it must be a valid looking ref. */ - if (!rs[i].dst) { + if (!rs[i].dst) ; /* ok */ - } else if (!*rs[i].dst) { + else if (!*rs[i].dst) ; /* ok */ - } else { - st = verify_refname(rs[i].dst, is_glob); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) - goto invalid; - } + else if (check_refname_format(rs[i].dst, flags)) + goto invalid; } else { /* * LHS @@@ -594,7 -616,8 +594,7 @@@ if (!*rs[i].src) ; /* empty is ok */ else if (is_glob) { - st = verify_refname(rs[i].src, is_glob); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) + if (check_refname_format(rs[i].src, flags)) goto invalid; } else @@@ -607,12 -630,14 +607,12 @@@ * - otherwise it must be a valid looking ref. */ if (!rs[i].dst) { - st = verify_refname(rs[i].src, is_glob); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) + if (check_refname_format(rs[i].src, flags)) goto invalid; } else if (!*rs[i].dst) { goto invalid; } else { - st = verify_refname(rs[i].dst, is_glob); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) + if (check_refname_format(rs[i].dst, flags)) goto invalid; } } @@@ -803,59 -828,56 +803,56 @@@ static int match_name_with_pattern(cons return ret; } - char *apply_refspecs(struct refspec *refspecs, int nr_refspec, - const char *name) + static int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) { int i; - char *ret = NULL; - for (i = 0; i < nr_refspec; i++) { - struct refspec *refspec = refspecs + i; - if (refspec->pattern) { - if (match_name_with_pattern(refspec->src, name, - refspec->dst, &ret)) - return ret; - } else if (!strcmp(refspec->src, name)) - return xstrdup(refspec->dst); - } - return NULL; - } + int find_src = !query->src; - int remote_find_tracking(struct remote *remote, struct refspec *refspec) - { - int find_src = refspec->src == NULL; - char *needle, **result; - int i; + if (find_src && !query->dst) + return error("query_refspecs: need either src or dst"); - if (find_src) { - if (!refspec->dst) - return error("find_tracking: need either src or dst"); - needle = refspec->dst; - result = &refspec->src; - } else { - needle = refspec->src; - result = &refspec->dst; - } + for (i = 0; i < ref_count; i++) { + struct refspec *refspec = &refs[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; + char **result = find_src ? &query->src : &query->dst; - for (i = 0; i < remote->fetch_refspec_nr; i++) { - struct refspec *fetch = &remote->fetch[i]; - const char *key = find_src ? fetch->dst : fetch->src; - const char *value = find_src ? fetch->src : fetch->dst; - if (!fetch->dst) + if (!refspec->dst) continue; - if (fetch->pattern) { + if (refspec->pattern) { if (match_name_with_pattern(key, needle, value, result)) { - refspec->force = fetch->force; + query->force = refspec->force; return 0; } } else if (!strcmp(needle, key)) { *result = xstrdup(value); - refspec->force = fetch->force; + query->force = refspec->force; return 0; } } return -1; } + char *apply_refspecs(struct refspec *refspecs, int nr_refspec, + const char *name) + { + struct refspec query; + + memset(&query, 0, sizeof(struct refspec)); + query.src = (char *)name; + + if (query_refspecs(refspecs, nr_refspec, &query)) + return NULL; + + return query.dst; + } + + int remote_find_tracking(struct remote *remote, struct refspec *refspec) + { + return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); + } + static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen, const char *name) { @@@ -1145,15 -1167,12 +1142,15 @@@ static struct ref **tail_ref(struct re } /* - * Note. This is used only by "push"; refspec matching rules for - * push and fetch are subtly different, so do not try to reuse it - * without thinking. + * Given the set of refs the local repository has, the set of refs the + * remote repository has, and the refspec used for push, determine + * what remote refs we will update and with what value by setting + * peer_ref (which object is being pushed) and force (if the push is + * forced) in elements of "dst". The function may add new elements to + * dst (e.g. pushing to a new branch, done in match_explicit_refs). */ -int match_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int flags) +int match_push_refs(struct ref *src, struct ref **dst, + int nr_refspec, const char **refspec, int flags) { struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; @@@ -1405,8 -1424,8 +1402,8 @@@ int get_fetch_map(const struct ref *rem for (rmp = &ref_map; *rmp; ) { if ((*rmp)->peer_ref) { - int st = check_ref_format((*rmp)->peer_ref->name + 5); - if (st && st != CHECK_REF_FORMAT_ONELEVEL) { + if (check_refname_format((*rmp)->peer_ref->name + 5, + REFNAME_ALLOW_ONELEVEL)) { struct ref *ignore = *rmp; error("* Ignoring funny ref '%s' locally", (*rmp)->peer_ref->name); @@@ -1598,7 -1617,7 +1595,7 @@@ static int one_local_ref(const char *re int len; /* we already know it starts with refs/ to get here */ - if (check_ref_format(refname + 5)) + if (check_refname_format(refname + 5, 0)) return 0; len = strlen(refname) + 1; @@@ -1659,36 -1678,47 +1656,47 @@@ struct ref *guess_remote_head(const str } struct stale_heads_info { - struct remote *remote; struct string_list *ref_names; struct ref **stale_refs_tail; + struct refspec *refs; + int ref_count; }; static int get_stale_heads_cb(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct stale_heads_info *info = cb_data; - struct refspec refspec; - memset(&refspec, 0, sizeof(refspec)); - refspec.dst = (char *)refname; - if (!remote_find_tracking(info->remote, &refspec)) { - if (!((flags & REF_ISSYMREF) || - string_list_has_string(info->ref_names, refspec.src))) { - struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail); - hashcpy(ref->new_sha1, sha1); - } + struct refspec query; + memset(&query, 0, sizeof(struct refspec)); + query.dst = (char *)refname; + + if (query_refspecs(info->refs, info->ref_count, &query)) + return 0; /* No matches */ + + /* + * If we did find a suitable refspec and it's not a symref and + * it's not in the list of refs that currently exist in that + * remote we consider it to be stale. + */ + if (!((flags & REF_ISSYMREF) || + string_list_has_string(info->ref_names, query.src))) { + struct ref *ref = make_linked_ref(refname, &info->stale_refs_tail); + hashcpy(ref->new_sha1, sha1); } + + free(query.src); return 0; } - struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map) + struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map) { struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; struct stale_heads_info info; - info.remote = remote; info.ref_names = &ref_names; info.stale_refs_tail = &stale_refs; + info.refs = refs; + info.ref_count = ref_count; for (ref = fetch_map; ref; ref = ref->next) string_list_append(&ref_names, ref->name); sort_string_list(&ref_names); diff --combined remote.h index 67294778b6,f2541b5a29..b3955983ba --- a/remote.h +++ b/remote.h @@@ -96,8 -96,8 +96,8 @@@ void free_refspec(int nr_refspec, struc char *apply_refspecs(struct refspec *refspecs, int nr_refspec, const char *name); -int match_refs(struct ref *src, struct ref **dst, - int nr_refspec, const char **refspec, int all); +int match_push_refs(struct ref *src, struct ref **dst, + int nr_refspec, const char **refspec, int all); void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, int force_update); @@@ -164,6 -164,6 +164,6 @@@ struct ref *guess_remote_head(const str int all); /* Return refs which no longer exist on remote */ - struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map); + struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); #endif