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 <mhag...@alum.mit.edu>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to