Add two new configuration settings, fetch.pruneRef remote.<name>.pruneRef via which prune patterns (i.e., the equivalent of --prune=<pattern>) can be configured globally or for particular remotes. The default remains the same, namely "*". Signed-off-by: Michael Haggerty <mhagger@xxxxxxxxxxxx> --- Documentation/config.txt | 28 ++++++++++++++----- Documentation/fetch-options.txt | 7 +++++ Documentation/git-remote.txt | 13 +++++---- remote.c | 47 +++++++++++++++++++++----------- remote.h | 1 + t/t5505-remote.sh | 60 +++++++++++++++++++++++++++++++++++++++++ t/t5510-fetch.sh | 13 +++++++++ 7 files changed, 143 insertions(+), 26 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index a405806..5a2118e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1069,6 +1069,14 @@ fetch.prune:: If true, fetch will automatically behave as if the `--prune` option was given on the command line. See also `remote.<name>.prune`. +fetch.pruneRef:: + Glob pattern matching the names of local references that are + subject to pruning when "git fetch --prune" or "git remote + prune" is run for this remote. See the `--prune=<pattern>` + option to the linkgit:git-fetch[1] command for more + information. This setting may be overridden for particular + remotes via remote.<name>.pruneRef. + format.attach:: Enable multipart/mixed attachments as the default for 'format-patch'. The value can also be a double quoted string @@ -2047,6 +2055,20 @@ remote.<name>.fetch:: The default set of "refspec" for linkgit:git-fetch[1]. See linkgit:git-fetch[1]. +remote.<name>.prune:: + When set to true, fetching from this remote by default will + also remove any remote-tracking references that no longer + exist on the remote (as if the `--prune` option were given on + the command line). Overrides `fetch.prune` settings, if any. + See also `remote.<name>.pruneRef`. + +remote.<name>.pruneRef:: + Glob pattern matching the names of local references that are + subject to pruning when "git fetch --prune" or "git remote + prune" is run for this remote. See the `--prune=<pattern>` + option to the linkgit:git-fetch[1] command for more + information. This option overrides `fetch.pruneRef`. + remote.<name>.push:: The default set of "refspec" for linkgit:git-push[1]. See linkgit:git-push[1]. @@ -2085,12 +2107,6 @@ remote.<name>.vcs:: Setting this to a value <vcs> will cause Git to interact with the remote with the git-remote-<vcs> helper. -remote.<name>.prune:: - When set to true, fetching from this remote by default will also - 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.<group>:: The list of remotes which are fetched by "git remote update <group>". See linkgit:git-remote[1]. diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 61d3f75..fa2cfdb 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -41,6 +41,7 @@ ifndef::git-pull[] -p:: --prune[=<pattern>]:: +--no-prune:: 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 @@ -53,6 +54,12 @@ ifndef::git-pull[] If pattern is specified, then it should be a glob pattern, and pruning is further restricted to references whose names match the pattern. This option can be specified multiple times. ++ +The default for `--prune`/`--no-prune` is taken from the configuration +settings remote.<name>.prune or fetch.prune, or false if neither of +these is set. The default pattern is taken from +remote.<name>.pruneRef or fetch.pruneRef, or "*" if neither of these +is set. endif::git-pull[] ifndef::git-pull[] diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index dd48474..4e1f8b2 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -151,17 +151,20 @@ With `--prune`, display stale remote-tracking branches that no longer exist on the remote (this is the default). With `--prune=<pattern>`, only report stale references whose names match <pattern> (this option can be used multiple times). With `--no-prune`, do not report stale -remote-tracking references at all. +remote-tracking references at all. See linkgit:git-fetch[1] for more +information about how pruning patterns can be configured. + With `-n` option, the remote heads are not queried first with `git ls-remote <name>`; cached information is used instead. 'prune':: -Deletes all stale remote-tracking branches under <name>. -These stale branches have already been removed from the remote repository -referenced by <name>, but are still locally available in -"remotes/<name>". +Delete all stale remote-tracking branches for the specified remote(s). +Stale remote-tracking branches are those that have already been +deleted from the remote repository referenced by <name>, but are still +present in the local repository (typically under +"refs/remotes/<name>"). See linkgit:git-fetch[1] for more information +about pruning and how it can be configured. + With `--prune=<pattern>`, only prune references whose names match pattern. This option can be used multiple times. diff --git a/remote.c b/remote.c index 89c9eaa..cc7f8d6 100644 --- a/remote.c +++ b/remote.c @@ -79,44 +79,58 @@ int prune_option_parse(const struct option *opt, const char *arg, int unset) static int git_fetch_config(const char *k, const char *v, void *cb) { - int *fetch_prune_config = cb; + struct prune_option *prune_option = cb; if (!strcmp(k, "fetch.prune")) { - *fetch_prune_config = git_config_bool(k, v); + prune_option->prune = git_config_bool(k, v); + return 0; + } else if (!strcmp(k, "fetch.pruneref")) { + string_list_append(&prune_option->prune_patterns, v); return 0; } return 0; } +static struct prune_option global_prune_option = PRUNE_OPTION_INIT; +static int global_prune_option_read = 0; + void prune_option_fill(struct remote *remote, struct prune_option *prune_option, int default_prune) { + if (!global_prune_option_read) { + git_config(git_fetch_config, &global_prune_option); + global_prune_option_read = 1; + } + if (prune_option->prune < 0) { /* * The user specified neither --prune nor --no-prune; * use the configured value of remote.<name>.prune or * fetch.prune: */ - if (remote->prune >= 0) { + if (remote->prune >= 0) prune_option->prune = remote->prune; - } else { - int fetch_prune_config = -1; - - git_config(git_fetch_config, &fetch_prune_config); - - if (fetch_prune_config >= 0) - prune_option->prune = fetch_prune_config; - else - prune_option->prune = default_prune; - } + else if (global_prune_option.prune >= 0) + prune_option->prune = global_prune_option.prune; + else + prune_option->prune = default_prune; } if (prune_option->prune && !prune_option->prune_patterns.nr) { /* * We want to prune, but no pruning patterns were - * specified on the command line. Default to "*". + * specified on the command line. Use the value from + * remote.<name>.pruneRef or fetch.pruneRef if + * available; otherwise, default to "*". */ - string_list_append(&prune_option->prune_patterns, "*"); + if (remote->prune_patterns.nr) + string_list_append_list(&prune_option->prune_patterns, + &remote->prune_patterns); + else if (global_prune_option.prune_patterns.nr) + string_list_append_list(&prune_option->prune_patterns, + &global_prune_option.prune_patterns); + else + string_list_append(&prune_option->prune_patterns, "*"); } } @@ -234,6 +248,7 @@ static struct remote *make_remote(const char *name, int len) ret = xcalloc(1, sizeof(struct remote)); ret->prune = -1; /* unspecified */ + ret->prune_patterns.strdup_strings = 1; ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); remotes[remotes_nr++] = ret; if (len) @@ -492,6 +507,8 @@ static int handle_config(const char *key, const char *value, void *cb) remote->skip_default_update = git_config_bool(key, value); else if (!strcmp(subkey, ".prune")) remote->prune = git_config_bool(key, value); + else if (!strcmp(subkey, ".pruneref")) + string_list_append(&remote->prune_patterns, value); else if (!strcmp(subkey, ".url")) { const char *v; if (git_config_string(&v, key, value)) diff --git a/remote.h b/remote.h index a484290..503c5c8 100644 --- a/remote.h +++ b/remote.h @@ -44,6 +44,7 @@ struct remote { int skip_default_update; int mirror; int prune; + struct string_list prune_patterns; const char *receivepack; const char *uploadpack; diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index e156174..e6e0abe 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -258,6 +258,36 @@ test_expect_success 'prune with --prune' ' ) ' +test_expect_success 'prune with remote pruneRef config' ' + git clone one prune-remote-config && + ( + cd prune-remote-config && + # This first setting should not matter: + git config fetch.pruneRef "*" && + git config remote.origin.pruneRef "refs/remotes/*1" && + git update-ref refs/remotes/origin/branch1 master && + git update-ref refs/remotes/origin/branch2 master && + + git remote prune origin && + test_must_fail git rev-parse origin/branch1 && + git rev-parse origin/branch2 + ) +' + +test_expect_success 'prune with global pruneRef config' ' + git clone one prune-global-config && + ( + cd prune-global-config && + git config fetch.pruneRef "refs/remotes/*1" && + git update-ref refs/remotes/origin/branch1 master && + git update-ref refs/remotes/origin/branch2 master && + + git remote prune origin && + test_must_fail git rev-parse origin/branch1 && + git rev-parse origin/branch2 + ) +' + test_expect_success 'set-head --delete' ' ( cd test && @@ -642,6 +672,36 @@ test_expect_success 'update --prune with argument' ' ) ' +test_expect_success 'update --prune with remote pruneRef config' ' + git clone one update-prune-remote-config && + ( + cd update-prune-remote-config && + # This first setting should not matter: + git config fetch.pruneRef "*" && + git config remote.origin.pruneRef "refs/remotes/*1" && + git update-ref refs/remotes/origin/branch1 master && + git update-ref refs/remotes/origin/branch2 master && + + git remote update --prune origin && + test_must_fail git rev-parse origin/branch1 && + git rev-parse origin/branch2 + ) +' + +test_expect_success 'update --prune with global pruneRef config' ' + git clone one update-prune-global-config && + ( + cd update-prune-global-config && + git config fetch.pruneRef "refs/remotes/*1" && + git update-ref refs/remotes/origin/branch1 master && + git update-ref refs/remotes/origin/branch2 master && + + git remote update --prune origin && + test_must_fail git rev-parse origin/branch1 && + git rev-parse origin/branch2 + ) +' + cat >one/expect <<-\EOF apis/master apis/side diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 42eb21f..c82b929 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -94,6 +94,19 @@ test_expect_success 'fetch --prune on its own works as expected' ' test_must_fail git rev-parse origin/extrabranch ' +test_expect_success 'fetch with pruneRef config' ' + cd "$D" && + git clone . prune-config && + cd prune-config && + git config remote.origin.pruneRef "refs/remotes/*1" && + git update-ref refs/remotes/origin/branch1 master && + git update-ref refs/remotes/origin/branch2 master && + + git fetch --prune origin && + test_must_fail git rev-parse origin/branch1 && + git rev-parse origin/branch2 +' + test_expect_success 'fetch --prune with arguments' ' cd "$D" && git clone . prune-args && -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html