From 0012ba2108aa42947dedf19f3db2de73a67cc4f5 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:02:51 -0400 Subject: Add uploadpack configuration info to remote. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- remote.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'remote.c') diff --git a/remote.c b/remote.c index bb774d0bc..a8196b1b5 100644 --- a/remote.c +++ b/remote.c @@ -196,6 +196,11 @@ static int handle_config(const char *key, const char *value) remote->receivepack = xstrdup(value); else error("more than one receivepack given, using the first"); + } else if (!strcmp(subkey, ".uploadpack")) { + if (!remote->uploadpack) + remote->uploadpack = xstrdup(value); + else + error("more than one uploadpack given, using the first"); } return 0; } -- cgit v1.2.1 From cf818348f1ab577d2ecb5d11a00a1d4122435ece Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:02:56 -0400 Subject: Report information on branches from remote.h This adds full parsing for branch. sections and functions to interpret the results usefully. It incidentally corrects the fetch configuration information for legacy branches/* files with '#' characters in the URLs. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- remote.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 146 insertions(+), 11 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index a8196b1b5..711aa04ce 100644 --- a/remote.c +++ b/remote.c @@ -5,6 +5,12 @@ static struct remote **remotes; static int allocated_remotes; +static struct branch **branches; +static int allocated_branches; + +static struct branch *current_branch; +static const char *default_remote_name; + #define BUF_SIZE (2048) static char buffer[BUF_SIZE]; @@ -67,6 +73,54 @@ static struct remote *make_remote(const char *name, int len) return remotes[empty]; } +static void add_merge(struct branch *branch, const char *name) +{ + int nr = branch->merge_nr + 1; + branch->merge_name = + xrealloc(branch->merge_name, nr * sizeof(char *)); + branch->merge_name[nr-1] = name; + branch->merge_nr = nr; +} + +static struct branch *make_branch(const char *name, int len) +{ + int i, empty = -1; + char *refname; + + for (i = 0; i < allocated_branches; i++) { + if (!branches[i]) { + if (empty < 0) + empty = i; + } else { + if (len ? (!strncmp(name, branches[i]->name, len) && + !branches[i]->name[len]) : + !strcmp(name, branches[i]->name)) + return branches[i]; + } + } + + if (empty < 0) { + empty = allocated_branches; + allocated_branches += allocated_branches ? allocated_branches : 1; + branches = xrealloc(branches, + sizeof(*branches) * allocated_branches); + memset(branches + empty, 0, + (allocated_branches - empty) * sizeof(*branches)); + } + branches[empty] = xcalloc(1, sizeof(struct branch)); + if (len) + branches[empty]->name = xstrndup(name, len); + else + branches[empty]->name = xstrdup(name); + refname = malloc(strlen(name) + strlen("refs/heads/") + 1); + strcpy(refname, "refs/heads/"); + strcpy(refname + strlen("refs/heads/"), + branches[empty]->name); + branches[empty]->refname = refname; + + return branches[empty]; +} + static void read_remotes_file(struct remote *remote) { FILE *f = fopen(git_path("remotes/%s", remote->name), "r"); @@ -116,6 +170,8 @@ static void read_remotes_file(struct remote *remote) static void read_branches_file(struct remote *remote) { const char *slash = strchr(remote->name, '/'); + char *frag; + char *branch; int n = slash ? slash - remote->name : 1000; FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r"); char *s, *p; @@ -141,23 +197,40 @@ static void read_branches_file(struct remote *remote) strcpy(p, s); if (slash) strcat(p, slash); + frag = strchr(p, '#'); + if (frag) { + *(frag++) = '\0'; + branch = xmalloc(strlen(frag) + 12); + strcpy(branch, "refs/heads/"); + strcat(branch, frag); + } else { + branch = "refs/heads/master"; + } add_uri(remote, p); + add_fetch_refspec(remote, branch); } -static char *default_remote_name = NULL; -static const char *current_branch = NULL; -static int current_branch_len = 0; - static int handle_config(const char *key, const char *value) { const char *name; const char *subkey; struct remote *remote; - if (!prefixcmp(key, "branch.") && current_branch && - !strncmp(key + 7, current_branch, current_branch_len) && - !strcmp(key + 7 + current_branch_len, ".remote")) { - free(default_remote_name); - default_remote_name = xstrdup(value); + struct branch *branch; + if (!prefixcmp(key, "branch.")) { + name = key + 7; + subkey = strrchr(name, '.'); + branch = make_branch(name, subkey - name); + if (!subkey) + return 0; + if (!value) + return 0; + if (!strcmp(subkey, ".remote")) { + branch->remote_name = xstrdup(value); + if (branch == current_branch) + default_remote_name = branch->remote_name; + } else if (!strcmp(subkey, ".merge")) + add_merge(branch, xstrdup(value)); + return 0; } if (prefixcmp(key, "remote.")) return 0; @@ -217,8 +290,8 @@ static void read_config(void) head_ref = resolve_ref("HEAD", sha1, 0, &flag); if (head_ref && (flag & REF_ISSYMREF) && !prefixcmp(head_ref, "refs/heads/")) { - current_branch = head_ref + strlen("refs/heads/"); - current_branch_len = strlen(current_branch); + current_branch = + make_branch(head_ref + strlen("refs/heads/"), 0); } git_config(handle_config); } @@ -313,6 +386,25 @@ int remote_has_uri(struct remote *remote, const char *uri) return 0; } +/* + * Returns true if, under the matching rules for fetching, name is the + * same as the given full name. + */ +static int ref_matches_abbrev(const char *name, const char *full) +{ + if (!prefixcmp(name, "refs/") || !strcmp(name, "HEAD")) + return !strcmp(name, full); + if (prefixcmp(full, "refs/")) + return 0; + if (!prefixcmp(name, "heads/") || + !prefixcmp(name, "tags/") || + !prefixcmp(name, "remotes/")) + return !strcmp(name, full + 5); + if (prefixcmp(full + 5, "heads/")) + return 0; + return !strcmp(full + 11, name); +} + int remote_find_tracking(struct remote *remote, struct refspec *refspec) { int find_src = refspec->src == NULL; @@ -636,3 +728,46 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, } return 0; } + +struct branch *branch_get(const char *name) +{ + struct branch *ret; + + read_config(); + if (!name || !*name || !strcmp(name, "HEAD")) + ret = current_branch; + else + ret = make_branch(name, 0); + if (ret && ret->remote_name) { + ret->remote = remote_get(ret->remote_name); + if (ret->merge_nr) { + int i; + ret->merge = xcalloc(sizeof(*ret->merge), + ret->merge_nr); + for (i = 0; i < ret->merge_nr; i++) { + ret->merge[i] = xcalloc(1, sizeof(**ret->merge)); + ret->merge[i]->src = xstrdup(ret->merge_name[i]); + remote_find_tracking(ret->remote, + ret->merge[i]); + } + } + } + return ret; +} + +int branch_has_merge_config(struct branch *branch) +{ + return branch && !!branch->merge; +} + +int branch_merges(struct branch *branch, const char *refname) +{ + int i; + if (!branch) + return 0; + for (i = 0; i < branch->merge_nr; i++) { + if (ref_matches_abbrev(branch->merge[i]->src, refname)) + return 1; + } + return 0; +} -- cgit v1.2.1 From d71ab17470ab2011c7cb398b75385bb0d0c4bdb4 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:03:08 -0400 Subject: Add matching and parsing for fetch-side refspec rules Also exports parse_ref_spec(). Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- remote.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index 711aa04ce..df91b2ff9 100644 --- a/remote.c +++ b/remote.c @@ -208,6 +208,7 @@ static void read_branches_file(struct remote *remote) } add_uri(remote, p); add_fetch_refspec(remote, branch); + remote->fetch_tags = 1; /* always auto-follow */ } static int handle_config(const char *key, const char *value) @@ -274,6 +275,9 @@ static int handle_config(const char *key, const char *value) remote->uploadpack = xstrdup(value); else error("more than one uploadpack given, using the first"); + } else if (!strcmp(subkey, ".tagopt")) { + if (!strcmp(value, "--no-tags")) + remote->fetch_tags = -1; } return 0; } @@ -296,7 +300,7 @@ static void read_config(void) git_config(handle_config); } -static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) +struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) { int i; struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); @@ -352,6 +356,10 @@ struct remote *remote_get(const char *name) add_uri(ret, name); if (!ret->uri) return NULL; + if (!strcmp(name, ".")) { + // we always fetch "refs/*:refs/*", which is trivial + add_fetch_refspec(ret, "refs/*:refs/*"); + } ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); return ret; @@ -454,6 +462,14 @@ struct ref *alloc_ref(unsigned namelen) return ret; } +static struct ref *copy_ref(struct ref *ref) +{ + struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1); + memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1); + ret->next = NULL; + return ret; +} + void free_refs(struct ref *ref) { struct ref *next; @@ -771,3 +787,110 @@ int branch_merges(struct branch *branch, const char *refname) } return 0; } + +static struct ref *get_expanded_map(struct ref *remote_refs, + const struct refspec *refspec) +{ + struct ref *ref; + struct ref *ret = NULL; + struct ref **tail = &ret; + + int remote_prefix_len = strlen(refspec->src); + int local_prefix_len = strlen(refspec->dst); + + for (ref = remote_refs; ref; ref = ref->next) { + if (strchr(ref->name, '^')) + continue; /* a dereference item */ + if (!prefixcmp(ref->name, refspec->src)) { + char *match; + struct ref *cpy = copy_ref(ref); + match = ref->name + remote_prefix_len; + + cpy->peer_ref = alloc_ref(local_prefix_len + + strlen(match) + 1); + sprintf(cpy->peer_ref->name, "%s%s", + refspec->dst, match); + if (refspec->force) + cpy->peer_ref->force = 1; + *tail = cpy; + tail = &cpy->next; + } + } + + return ret; +} + +static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name) +{ + struct ref *ref; + for (ref = refs; ref; ref = ref->next) { + if (ref_matches_abbrev(name, ref->name)) + return ref; + } + return NULL; +} + +struct ref *get_remote_ref(struct ref *remote_refs, const char *name) +{ + struct ref *ref = find_ref_by_name_abbrev(remote_refs, name); + + if (!ref) + die("Couldn't find remote ref %s\n", name); + + return copy_ref(ref); +} + +static struct ref *get_local_ref(const char *name) +{ + struct ref *ret; + if (!name) + return NULL; + + if (!prefixcmp(name, "refs/")) { + ret = alloc_ref(strlen(name) + 1); + strcpy(ret->name, name); + return ret; + } + + if (!prefixcmp(name, "heads/") || + !prefixcmp(name, "tags/") || + !prefixcmp(name, "remotes/")) { + ret = alloc_ref(strlen(name) + 6); + sprintf(ret->name, "refs/%s", name); + return ret; + } + + ret = alloc_ref(strlen(name) + 12); + sprintf(ret->name, "refs/heads/%s", name); + return ret; +} + +int get_fetch_map(struct ref *remote_refs, + const struct refspec *refspec, + struct ref ***tail) +{ + struct ref *ref_map, *rm; + + if (refspec->pattern) { + ref_map = get_expanded_map(remote_refs, refspec); + } else { + ref_map = get_remote_ref(remote_refs, + refspec->src[0] ? + refspec->src : "HEAD"); + + ref_map->peer_ref = get_local_ref(refspec->dst); + + if (refspec->force) + ref_map->peer_ref->force = 1; + } + + for (rm = ref_map; rm; rm = rm->next) { + if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5)) + die("* refusing to create funny ref '%s' locally", + rm->peer_ref->name); + } + + tail_link_ref(ref_map, tail); + + return 0; +} -- cgit v1.2.1 From ad23603c3af77b47f65382ea22b30d1ecccaab6f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 16 Sep 2007 02:32:11 -0400 Subject: Don't configure remote "." to fetch everything to itself When we are talking about a remote URI of "." we are really talking about *this* repository that we are fetching into or pushing out of. There are no matching tracking branches for this repository; we do not attempt to map a ref back to ourselves as this would either create an infinite cycle (for example "fetch = +refs/*:refs/mine/*") or it causes problems when we attempt to push back to ourselves. So we really cannot setup a remote like this: [remote "."] url = . fetch = +refs/*:refs/* In the case of `git push . B:T` to fast-forward branch T to B's current commit git-send-pack will update branch T to B, assuming that T is the remote tracking branch for B. This update is performed immediately before git-send-pack asks git-receive-pack to perform the same update, and git-receive-pack then fails because T is not where git-send-pack told it to expect T to be at. In the case of `git fetch .` we really should do the same thing as `git fetch $otherrepo`, that is load .git/FETCH_HEAD with the commit of HEAD, so that `git pull .` will report "Already up-to-date". We have always behaved like this before on this insane request and we should at least continue to behave the same way. With the above (bad) remote configuration we were instead getting fetch errors about funny refs, e.g. "refs/stash". Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- remote.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index df91b2ff9..73a34c9e3 100644 --- a/remote.c +++ b/remote.c @@ -356,10 +356,6 @@ struct remote *remote_get(const char *name) add_uri(ret, name); if (!ret->uri) return NULL; - if (!strcmp(name, ".")) { - // we always fetch "refs/*:refs/*", which is trivial - add_fetch_refspec(ret, "refs/*:refs/*"); - } ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); return ret; -- cgit v1.2.1 From 27e13374bf1864eb8aea44cca3afd81eedb007aa Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 18 Sep 2007 04:54:48 -0400 Subject: builtin-fetch: Don't segfault on "fetch +foo" If we are fetching something and were configured to do a forced fetch and have no local ref to store the fetched object into we cannot mark the local ref as having a forced update. Instead we should just silently discard the + request. Signed-off-by: Shawn O. Pearce --- remote.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index 73a34c9e3..af3c46bb3 100644 --- a/remote.c +++ b/remote.c @@ -875,8 +875,7 @@ int get_fetch_map(struct ref *remote_refs, refspec->src : "HEAD"); ref_map->peer_ref = get_local_ref(refspec->dst); - - if (refspec->force) + if (ref_map->peer_ref && refspec->force) ref_map->peer_ref->force = 1; } -- cgit v1.2.1 From 85682c1903a4ae776b0bf2d30d9ecd1e19689131 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 18 Sep 2007 04:54:53 -0400 Subject: Correct handling of branch.$name.merge in builtin-fetch My prior bug fix for git-push titled "Don't configure remote "." to fetch everything to itself" actually broke t5520 as we were unable to evaluate a branch configuration of: [branch "copy"] remote = . merge = refs/heads/master as remote "." did not have a "remote...fetch" configuration entry to offer up refs/heads/master as a possible candidate available to be fetched and merged. In shell script git-fetch and prior to the above mentioned commit this was hardcoded for a url of "." to be the set of local branches. Chasing down this bug led me to the conclusion that our prior behavior with regards to branch.$name.merge was incorrect. In the shell script based git-fetch implementation we only fetched and merged a branch if it appeared both in branch.$name.merge *and* in remote.$r.fetch, where $r = branch.$name.remote. In other words in the following config file: [remote "origin"] url = git://git.kernel.org/pub/scm/git/git.git fetch = refs/heads/master:refs/remotes/origin/master [branch "master"] remote = origin merge = refs/heads/master [branch "pu"] remote = origin merge = refs/heads/pu Attempting to run `git pull` while on branch "pu" would always give the user "Already up-to-date" as git-fetch did not fetch pu and thus did not mark it for merge in .git/FETCH_HEAD. The configured merge would always be ignored and the user would be left scratching her confused head wondering why merge did not work on "pu" but worked fine on "master". If we are using the "default fetch" specification for the current branch and the current branch has a branch.$name.merge configured we now union it with the list of refs in remote.$r.fetch. This way the above configuration does what the user expects it to do, which is to fetch only "master" by default but when on "pu" to fetch both "master" and "pu". This uncovered some breakage in the test suite where old-style Cogito branches (.git/branches/$r) did not fetch the branches listed in .git/config for merging and thus did not actually merge them if the user tried to use `git pull` on that branch. Junio and I discussed it on list and felt that the union approach here makes more sense to DWIM for the end-user than silently ignoring their configured request so the test vectors for t5515 have been updated to include for-merge lines in .git/FETCH_HEAD where they have been configured for-merge in .git/config. Since we are now performing a union of the fetch specification and the merge specification and we cannot allow a branch to be listed twice (otherwise it comes out twice in .git/FETCH_HEAD) we need to perform a double loop here over all of the branch.$name.merge lines and try to set their merge flag if we have already schedule that branch for fetching by remote.$r.fetch. If no match is found then we must add new specifications to fetch the branch but not store it as no local tracking branch has been designated. Signed-off-by: Shawn O. Pearce --- remote.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index af3c46bb3..31e2b70d3 100644 --- a/remote.c +++ b/remote.c @@ -772,16 +772,13 @@ int branch_has_merge_config(struct branch *branch) return branch && !!branch->merge; } -int branch_merges(struct branch *branch, const char *refname) +int branch_merge_matches(struct branch *branch, + int i, + const char *refname) { - int i; - if (!branch) + if (!branch || i < 0 || i >= branch->merge_nr) return 0; - for (i = 0; i < branch->merge_nr; i++) { - if (ref_matches_abbrev(branch->merge[i]->src, refname)) - return 1; - } - return 0; + return ref_matches_abbrev(branch->merge[i]->src, refname); } static struct ref *get_expanded_map(struct ref *remote_refs, -- cgit v1.2.1 From 28b91f8ad9e4791b5c35ca6bffbb78725b4e5bbf Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 19 Sep 2007 00:49:27 -0400 Subject: Rename remote.uri to remote.url within remote handling internals Anyplace we talk about the address of a remote repository we always refer to it as a URL, especially in the configuration file and .git/remotes where we call it "remote.$n.url" or start the first line with "URL:". Calling this value a uri within the internal C code just doesn't jive well with our commonly accepted terms. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- remote.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index 31e2b70d3..e3c3df556 100644 --- a/remote.c +++ b/remote.c @@ -32,13 +32,13 @@ static void add_fetch_refspec(struct remote *remote, const char *ref) remote->fetch_refspec_nr = nr; } -static void add_uri(struct remote *remote, const char *uri) +static void add_url(struct remote *remote, const char *url) { - int nr = remote->uri_nr + 1; - remote->uri = - xrealloc(remote->uri, nr * sizeof(char *)); - remote->uri[nr-1] = uri; - remote->uri_nr = nr; + int nr = remote->url_nr + 1; + remote->url = + xrealloc(remote->url, nr * sizeof(char *)); + remote->url[nr-1] = url; + remote->url_nr = nr; } static struct remote *make_remote(const char *name, int len) @@ -154,7 +154,7 @@ static void read_remotes_file(struct remote *remote) switch (value_list) { case 0: - add_uri(remote, xstrdup(s)); + add_url(remote, xstrdup(s)); break; case 1: add_push_refspec(remote, xstrdup(s)); @@ -206,7 +206,7 @@ static void read_branches_file(struct remote *remote) } else { branch = "refs/heads/master"; } - add_uri(remote, p); + add_url(remote, p); add_fetch_refspec(remote, branch); remote->fetch_tags = 1; /* always auto-follow */ } @@ -260,7 +260,7 @@ static int handle_config(const char *key, const char *value) return 0; /* ignore unknown booleans */ } if (!strcmp(subkey, ".url")) { - add_uri(remote, xstrdup(value)); + add_url(remote, xstrdup(value)); } else if (!strcmp(subkey, ".push")) { add_push_refspec(remote, xstrdup(value)); } else if (!strcmp(subkey, ".fetch")) { @@ -347,14 +347,14 @@ struct remote *remote_get(const char *name) name = default_remote_name; ret = make_remote(name, 0); if (name[0] != '/') { - if (!ret->uri) + if (!ret->url) read_remotes_file(ret); - if (!ret->uri) + if (!ret->url) read_branches_file(ret); } - if (!ret->uri) - add_uri(ret, name); - if (!ret->uri) + if (!ret->url) + add_url(ret, name); + if (!ret->url) return NULL; ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec); @@ -380,11 +380,11 @@ int for_each_remote(each_remote_fn fn, void *priv) return result; } -int remote_has_uri(struct remote *remote, const char *uri) +int remote_has_url(struct remote *remote, const char *url) { int i; - for (i = 0; i < remote->uri_nr; i++) { - if (!strcmp(remote->uri[i], uri)) + for (i = 0; i < remote->url_nr; i++) { + if (!strcmp(remote->url[i], url)) return 1; } return 0; -- cgit v1.2.1 From 009c5bcd24da3cd2670962e405585e31d662487d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 25 Sep 2007 00:13:14 -0400 Subject: Cleanup style nit of 'x == NULL' in remote.c Git style tends to prefer "!x" over "x == NULL". Make it so in these handful of locations that were not following along. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- remote.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index e3c3df556..ac354f379 100644 --- a/remote.c +++ b/remote.c @@ -416,7 +416,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) int i; if (find_src) { - if (refspec->dst == NULL) + if (!refspec->dst) return error("find_tracking: need either src or dst"); needle = refspec->dst; result = &refspec->src; @@ -613,7 +613,7 @@ static int match_explicit(struct ref *src, struct ref *dst, if (!matched_src) errs = 1; - if (dst_value == NULL) + if (!dst_value) dst_value = matched_src->name; switch (count_refspec_match(dst_value, dst, &matched_dst)) { @@ -633,7 +633,7 @@ static int match_explicit(struct ref *src, struct ref *dst, dst_value); break; } - if (errs || matched_dst == NULL) + if (errs || !matched_dst) return 1; if (matched_dst->peer_ref) { errs = 1; -- cgit v1.2.1 From 7dfee372b08f653c2709c90bea986e4ed608f410 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 25 Sep 2007 00:13:19 -0400 Subject: Cleanup unnecessary break in remote.c This simple change makes the body of "case 0" easier to read; no matter what the value of matched_src is we want to break out of the switch and not fall through. We only want to display an error if matched_src is NULL, as this indicates there is no local branch matching the input. Also modified the default case's error message so it uses one less line of text. Even at 8 column per tab indentation we still don't break 80 columns with this new formatting. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- remote.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index ac354f379..2166a2bf1 100644 --- a/remote.c +++ b/remote.c @@ -598,15 +598,12 @@ static int match_explicit(struct ref *src, struct ref *dst, * way to delete 'other' ref at the remote end. */ matched_src = try_explicit_object_name(rs->src); - if (matched_src) - break; - error("src refspec %s does not match any.", - rs->src); + if (!matched_src) + error("src refspec %s does not match any.", rs->src); break; default: matched_src = NULL; - error("src refspec %s matches more than one.", - rs->src); + error("src refspec %s matches more than one.", rs->src); break; } -- cgit v1.2.1 From 4491e62ae932d5774f628d1bd3be663c11058a73 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Tue, 25 Sep 2007 00:13:25 -0400 Subject: Prevent send-pack from segfaulting when a branch doesn't match If `git push url foo` can't find a local branch named foo we can't match it to any remote branch as the local branch is NULL and its name is probably at position 0x34 in memory. On most systems that isn't a valid address for git-send-pack's virtual address space and we segfault. If we can't find a source match and we have no destination we need to abort the match function early before we try to match the destination against the remote. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- remote.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index 2166a2bf1..e7d735b98 100644 --- a/remote.c +++ b/remote.c @@ -610,8 +610,11 @@ static int match_explicit(struct ref *src, struct ref *dst, if (!matched_src) errs = 1; - if (!dst_value) + if (!dst_value) { + if (!matched_src) + return errs; dst_value = matched_src->name; + } switch (count_refspec_match(dst_value, dst, &matched_dst)) { case 1: -- cgit v1.2.1 From 2467a4fa03ff849fcf2f6a93b89057aebd49c62b Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 8 Oct 2007 00:25:07 -0400 Subject: Remove duplicate ref matches in fetch If multiple refspecs matched the same ref, the update would be processed multiple times. Now having the same destination for the same source has no additional effect, and having the same destination for different sources is an error. Signed-off-by: Daniel Barkalow Signed-off-by: Lars Hjemli Signed-off-by: Shawn O. Pearce --- remote.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'remote.c') diff --git a/remote.c b/remote.c index e7d735b98..e2ca4d32b 100644 --- a/remote.c +++ b/remote.c @@ -380,6 +380,33 @@ int for_each_remote(each_remote_fn fn, void *priv) return result; } +void ref_remove_duplicates(struct ref *ref_map) +{ + struct ref **posn; + struct ref *next; + for (; ref_map; ref_map = ref_map->next) { + if (!ref_map->peer_ref) + continue; + posn = &ref_map->next; + while (*posn) { + if ((*posn)->peer_ref && + !strcmp((*posn)->peer_ref->name, + ref_map->peer_ref->name)) { + if (strcmp((*posn)->name, ref_map->name)) + die("%s tracks both %s and %s", + ref_map->peer_ref->name, + (*posn)->name, ref_map->name); + next = (*posn)->next; + free((*posn)->peer_ref); + free(*posn); + *posn = next; + } else { + posn = &(*posn)->next; + } + } + } +} + int remote_has_url(struct remote *remote, const char *url) { int i; -- cgit v1.2.1 From 8f70a7657a9b459d6a4a3bcb1628c0fa6a6c22e0 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Fri, 12 Oct 2007 22:40:04 +0200 Subject: Fix a crash in ls-remote when refspec expands into nothing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally-by: Väinö Järvelä Signed-off-by: Alex Riesen Signed-off-by: Lars Hjemli Signed-off-by: Shawn O. Pearce --- remote.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'remote.c') diff --git a/remote.c b/remote.c index e2ca4d32b..b20e2be43 100644 --- a/remote.c +++ b/remote.c @@ -909,7 +909,8 @@ int get_fetch_map(struct ref *remote_refs, rm->peer_ref->name); } - tail_link_ref(ref_map, tail); + if (ref_map) + tail_link_ref(ref_map, tail); return 0; } -- cgit v1.2.1