From 5caf19733713b3f04105d1949467014345e6a240 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Sat, 8 Oct 2011 00:51:06 +0200 Subject: fetch: free all the additional refspecs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- builtin/fetch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index e422ced929..605d1bfd66 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -918,7 +918,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv) 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; -- cgit 1.2.3-korg From ed43de6ec35dfd4c4bd33ae9b5f2ebe38282209f Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Sat, 15 Oct 2011 07:04:25 +0200 Subject: fetch: honor the user-provided refspecs when pruning refs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the user gave us refspecs on the command line, we should use those when deciding whether to prune a ref instead of relying on the refspecs in the config. Previously, running git fetch --prune origin refs/heads/master:refs/remotes/origin/master would delete every other ref under the origin namespace because we were using the refspec to filter the available refs but using the configured refspec to figure out if a ref had been deleted on the remote. This is clearly the wrong thing to do. Change prune_refs and get_stale_heads to simply accept a list of references and a list of refspecs. The caller of either function needs to decide what refspecs should be used to decide whether a ref is stale. Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- builtin/fetch.c | 12 ++++++++---- builtin/remote.c | 3 ++- remote.c | 35 +++++++++++++++++++++++------------ remote.h | 2 +- t/t5510-fetch.sh | 4 ++-- 5 files changed, 36 insertions(+), 20 deletions(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index 605d1bfd66..e295d97fdb 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -540,10 +540,10 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) 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"); @@ -734,8 +734,12 @@ static int do_fetch(struct transport *transport, free_refs(ref_map); return 1; } - if (prune) - prune_refs(transport, ref_map); + if (prune) { + 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 diff --git a/builtin/remote.c b/builtin/remote.c index f2a9c26dc3..de52367927 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -349,7 +349,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat else string_list_append(&states->tracked, abbrev_branch(ref->name)); } - stale_refs = get_stale_heads(states->remote, fetch_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)); diff --git a/remote.c b/remote.c index 823c82ab7e..6ececc4a77 100644 --- a/remote.c +++ b/remote.c @@ -1678,36 +1678,47 @@ struct ref *guess_remote_head(const struct ref *head, } 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 --git a/remote.h b/remote.h index 9a30a9dba6..f2541b5a29 100644 --- a/remote.h +++ b/remote.h @@ -164,6 +164,6 @@ struct ref *guess_remote_head(const struct ref *head, int all); /* Return refs which no longer exist on remote */ -struct ref *get_stale_heads(struct remote *remote, struct ref *fetch_map); +struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); #endif diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 8b5e92534b..581049bf94 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -86,7 +86,7 @@ test_expect_success 'fetch --prune on its own works as expected' ' test_must_fail git rev-parse origin/extrabranch ' -test_expect_failure 'fetch --prune with a branch name keeps branches' ' +test_expect_success 'fetch --prune with a branch name keeps branches' ' cd "$D" && git clone . prune-branch && cd prune-branch && @@ -96,7 +96,7 @@ test_expect_failure 'fetch --prune with a branch name keeps branches' ' git rev-parse origin/extrabranch ' -test_expect_failure 'fetch --prune with a namespace keeps other namespaces' ' +test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' cd "$D" && git clone . prune-namespace && cd prune-namespace && -- cgit 1.2.3-korg From e8c1e6c796c1b96b6b208bbd4bc8cfd9acb481b5 Mon Sep 17 00:00:00 2001 From: Carlos Martín Nieto Date: Sat, 15 Oct 2011 07:04:26 +0200 Subject: fetch: treat --tags like refs/tags/*:refs/tags/* when pruning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If --tags is specified, add that refspec to the list given to prune_refs so it knows to treat it as a filter on what refs to should consider for prunning. This way git fetch --prune --tags origin only prunes tags and doesn't delete the branch refs. Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- builtin/fetch.c | 23 +++++++++++++++++++++-- t/t5510-fetch.sh | 4 ++-- 2 files changed, 23 insertions(+), 4 deletions(-) (limited to 'builtin/fetch.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index e295d97fdb..9d481f8ca9 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -735,10 +735,29 @@ static int do_fetch(struct transport *transport, return 1; } if (prune) { - if (ref_count) + /* 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 + } else { prune_refs(transport->remote->fetch, transport->remote->fetch_refspec_nr, ref_map); + } } free_refs(ref_map); diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 581049bf94..e0af4c4e62 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -105,7 +105,7 @@ test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' git rev-parse origin/master ' -test_expect_failure 'fetch --prune --tags does not delete the remote-tracking branches' ' +test_expect_success 'fetch --prune --tags does not delete the remote-tracking branches' ' cd "$D" && git clone . prune-tags && cd prune-tags && @@ -116,7 +116,7 @@ test_expect_failure 'fetch --prune --tags does not delete the remote-tracking br test_must_fail git rev-parse somebranch ' -test_expect_failure 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' +test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && -- cgit 1.2.3-korg