diff --git a/Documentation/config.txt b/Documentation/config.txt index ab26963d61..a4058063ce 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2087,8 +2087,8 @@ remote..vcs:: remote..prune:: When set to true, fetching from this remote by default will also - remove any remote-tracking branches which no longer exist on the - remote (as if the `--prune` option was give on the command line). + remove any remote-tracking references that no longer exist on the + remote (as if the `--prune` option was given on the command line). Overrides `fetch.prune` settings, if any. remotes.:: diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 921f6be8d4..12b1d92a2f 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -41,8 +41,14 @@ ifndef::git-pull[] -p:: --prune:: - After fetching, remove any remote-tracking branches which - no longer exist on the remote. + After fetching, remove any remote-tracking references that no + longer exist on the remote. Tags are not subject to pruning + if they are fetched only because of the default tag + auto-following or due to a --tags option. However, if tags + are fetched due to an explicit refspec (either on the command + line or in the remote configuration, for example if the remote + was cloned with the --mirror option), then they are also + subject to pruning. endif::git-pull[] ifdef::git-pull[] @@ -61,9 +67,12 @@ endif::git-pull[] ifndef::git-pull[] -t:: --tags:: - Request that all tags be fetched from the remote in addition - to whatever else is being fetched. Its effect is similar to - that of the refspec `refs/tags/*:refs/tags/*`. + Fetch all tags from the remote (i.e., fetch remote tags + `refs/tags/*` into local tags with the same name), in addition + to whatever else would otherwise be fetched. Using this + option alone does not subject tags to pruning, even if --prune + is used (though tags may be pruned anyway if they are also the + destination of an explicit refspec; see '--prune'). --recurse-submodules[=yes|on-demand|no]:: This option controls if and under what conditions new commits of diff --git a/builtin/fetch.c b/builtin/fetch.c index 887fa3e581..1514b908d8 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -850,38 +850,17 @@ static int do_fetch(struct transport *transport, goto cleanup; } if (prune) { - struct refspec *prune_refspecs; - int prune_refspec_count; - + /* + * We only prune based on refspecs specified + * explicitly (via command line or configuration); we + * don't care whether --tags was specified. + */ if (ref_count) { - prune_refspecs = refs; - prune_refspec_count = ref_count; + prune_refs(refs, ref_count, ref_map); } else { - prune_refspecs = transport->remote->fetch; - prune_refspec_count = transport->remote->fetch_refspec_nr; - } - - if (tags == TAGS_SET) { - /* - * --tags was specified. Pretend that the user also - * gave us the canonical tags refspec - */ - const char *tags_str = "refs/tags/*:refs/tags/*"; - struct refspec *tags_refspec, *refspec; - - /* Copy the refspec and add the tags to it */ - refspec = xcalloc(prune_refspec_count + 1, sizeof(*refspec)); - tags_refspec = parse_fetch_refspec(1, &tags_str); - memcpy(refspec, prune_refspecs, prune_refspec_count * sizeof(*refspec)); - memcpy(&refspec[prune_refspec_count], tags_refspec, sizeof(*refspec)); - - prune_refs(refspec, prune_refspec_count + 1, ref_map); - - /* The rest of the strings belong to fetch_one */ - free_refspec(1, tags_refspec); - free(refspec); - } else { - prune_refs(prune_refspecs, prune_refspec_count, ref_map); + 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 02e5901ab1..5d4581dac8 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -113,7 +113,7 @@ test_expect_success 'fetch --prune with a namespace keeps other namespaces' ' git rev-parse origin/master ' -test_expect_success 'fetch --prune --tags prunes tags and branches' ' +test_expect_success 'fetch --prune --tags prunes branches but not tags' ' cd "$D" && git clone . prune-tags && cd prune-tags && @@ -125,10 +125,10 @@ test_expect_success 'fetch --prune --tags prunes tags and branches' ' git fetch --prune --tags origin && git rev-parse origin/master && test_must_fail git rev-parse origin/fake-remote && - test_must_fail git rev-parse sometag + git rev-parse sometag ' -test_expect_success 'fetch --prune --tags with branch does not delete other remote-tracking branches' ' +test_expect_success 'fetch --prune --tags with branch does not prune other things' ' cd "$D" && git clone . prune-tags-branch && cd prune-tags-branch && @@ -137,7 +137,7 @@ test_expect_success 'fetch --prune --tags with branch does not delete other remo git fetch --prune --tags origin master && git rev-parse origin/extrabranch && - test_must_fail git rev-parse sometag + git rev-parse sometag ' test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' ' @@ -151,7 +151,7 @@ test_expect_success 'fetch --prune --tags with refspec prunes based on refspec' git fetch --prune --tags origin refs/heads/foo/*:refs/remotes/origin/foo/* && test_must_fail git rev-parse refs/remotes/origin/foo/otherbranch && git rev-parse origin/extrabranch && - test_must_fail git rev-parse sometag + git rev-parse sometag ' test_expect_success 'fetch tags when there is no tags' '