Allow "--prune=<pattern>" options to be provided to "git remote prune"
to specify which reference namespaces should be pruned.  "--prune"
without an argument and "--no-prune" are disallowed here as they make
no sense.

Signed-off-by: Michael Haggerty <mhag...@alum.mit.edu>
---
 Documentation/git-remote.txt |  5 +++-
 builtin/remote.c             | 67 +++++++++++++++++++++++++++++++-------------
 t/t5505-remote.sh            | 15 ++++++++++
 3 files changed, 66 insertions(+), 21 deletions(-)

diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 02e50a9..9cbc986 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -19,7 +19,7 @@ SYNOPSIS
 'git remote set-url --add' [--push] <name> <newurl>
 'git remote set-url --delete' [--push] <name> <url>
 'git remote' [-v | --verbose] 'show' [-n] <name>...
-'git remote prune' [-n | --dry-run] <name>...
+'git remote prune' [-n | --dry-run] [--prune=<pattern>] <name>...
 'git remote' [-v | --verbose] 'update' [-p | --no-prune | 
--prune[=<pattern>]...]
                                       [(<group> | <remote>)...]
 
@@ -157,6 +157,9 @@ These stale branches have already been removed from the 
remote repository
 referenced by <name>, but are still locally available in
 "remotes/<name>".
 +
+With `--prune=<pattern>`, only prune references whose names match
+pattern.  This option can be used multiple times.
++
 With `--dry-run` option, report what branches will be pruned, but do not
 actually prune them.
 
diff --git a/builtin/remote.c b/builtin/remote.c
index 6aab923..e1d43e2 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = {
        N_("git remote remove <name>"),
        N_("git remote set-head <name> (-a | --auto | -d | --delete 
|<branch>)"),
        N_("git remote [-v | --verbose] show [-n] <name>"),
-       N_("git remote prune [-n | --dry-run] <name>"),
+       N_("git remote prune [-n | --dry-run] [--prune=<pattern>] <name>"),
        N_("git remote [-v | --verbose] update [-p | --prune[=<pattern>] | 
--no-prune] [(<group> | <remote>)...]"),
        N_("git remote set-branches [--add] <name> <branch>..."),
        N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
@@ -326,10 +326,12 @@ struct ref_states {
        int queried;
 };
 
-static int get_ref_states(const struct ref *remote_refs, struct ref_states 
*states)
+static int get_ref_states(const struct ref *remote_refs,
+                         struct ref_states *states,
+                         struct prune_option *prune_option)
 {
        struct ref *fetch_map = NULL, **tail = &fetch_map;
-       struct ref *ref, *stale_refs;
+       struct ref *ref;
        int i;
 
        for (i = 0; i < states->remote->fetch_refspec_nr; i++)
@@ -346,15 +348,20 @@ 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,
-                                    states->remote->fetch_refspec_nr,
-                                    fetch_map, NULL);
-       for (ref = stale_refs; ref; ref = ref->next) {
-               struct string_list_item *item =
-                       string_list_append(&states->stale, 
abbrev_branch(ref->name));
-               item->util = xstrdup(ref->name);
+       if (prune_option->prune) {
+               struct ref *stale_refs =
+                       get_stale_heads(states->remote->fetch,
+                                       states->remote->fetch_refspec_nr,
+                                       fetch_map,
+                                       &prune_option->prune_patterns);
+
+               for (ref = stale_refs; ref; ref = ref->next) {
+                       struct string_list_item *item =
+                               string_list_append(&states->stale, 
abbrev_branch(ref->name));
+                       item->util = xstrdup(ref->name);
+               }
+               free_refs(stale_refs);
        }
-       free_refs(stale_refs);
        free_refs(fetch_map);
 
        sort_string_list(&states->new);
@@ -878,8 +885,9 @@ static int append_ref_to_tracked_list(const char *refname,
 }
 
 static int get_remote_ref_states(const char *name,
-                                struct ref_states *states,
-                                int query)
+                                struct ref_states *states, int query,
+                                struct prune_option *prune_option,
+                                int default_prune)
 {
        struct transport *transport;
        const struct ref *remote_refs;
@@ -897,8 +905,19 @@ static int get_remote_ref_states(const char *name,
                transport_disconnect(transport);
 
                states->queried = 1;
-               if (query & GET_REF_STATES)
-                       get_ref_states(remote_refs, states);
+               if (query & GET_REF_STATES) {
+                       struct prune_option remote_prune_option =
+                               PRUNE_OPTION_INIT;
+
+                       remote_prune_option.prune = prune_option->prune;
+                       
string_list_append_list(&remote_prune_option.prune_patterns,
+                                               &prune_option->prune_patterns);
+                       prune_option_fill(states->remote,
+                                         &remote_prune_option,
+                                         default_prune);
+                       get_ref_states(remote_refs, states, 
&remote_prune_option);
+                       prune_option_clear(&remote_prune_option);
+               }
                if (query & GET_HEAD_NAMES)
                        get_head_names(remote_refs, states);
                if (query & GET_PUSH_REF_STATES)
@@ -1144,6 +1163,7 @@ static int show_all(void)
 static int show(int argc, const char **argv)
 {
        int no_query = 0, result = 0, query_flag = 0;
+       struct prune_option prune_option = PRUNE_OPTION_INIT;
        struct option options[] = {
                OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")),
                OPT_END()
@@ -1152,6 +1172,7 @@ static int show(int argc, const char **argv)
        struct string_list info_list = STRING_LIST_INIT_NODUP;
        struct show_info info;
 
+       prune_option.prune = 1;
        argc = parse_options(argc, argv, NULL, options, 
builtin_remote_show_usage,
                             0);
 
@@ -1170,7 +1191,7 @@ static int show(int argc, const char **argv)
                const char **url;
                int url_nr;
 
-               get_remote_ref_states(*argv, &states, query_flag);
+               get_remote_ref_states(*argv, &states, query_flag, 
&prune_option, 1);
 
                printf_ln(_("* remote %s"), *argv);
                printf_ln(_("  Fetch URL: %s"), states.remote->url_nr > 0 ?
@@ -1268,7 +1289,7 @@ static int set_head(int argc, const char **argv)
        } else if (opt_a && !opt_d && argc == 1) {
                struct ref_states states;
                memset(&states, 0, sizeof(states));
-               get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
+               get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES, NULL, 
0);
                if (!states.heads.nr)
                        result |= error(_("Cannot determine remote HEAD"));
                else if (states.heads.nr > 1) {
@@ -1303,7 +1324,8 @@ static int set_head(int argc, const char **argv)
        return result;
 }
 
-static int prune_remote(const char *remote, int dry_run)
+static int prune_remote(const char *remote, int dry_run,
+                       struct prune_option *prune_option)
 {
        int result = 0, i;
        struct ref_states states;
@@ -1312,7 +1334,7 @@ static int prune_remote(const char *remote, int dry_run)
                : _(" %s has become dangling!");
 
        memset(&states, 0, sizeof(states));
-       get_remote_ref_states(remote, &states, GET_REF_STATES);
+       get_remote_ref_states(remote, &states, GET_REF_STATES, prune_option, 1);
 
        if (states.stale.nr) {
                printf_ln(_("Pruning %s"), remote);
@@ -1344,11 +1366,16 @@ static int prune_remote(const char *remote, int dry_run)
 static int prune(int argc, const char **argv)
 {
        int dry_run = 0, result = 0;
+       struct prune_option prune_option = PRUNE_OPTION_INIT;
        struct option options[] = {
+               { OPTION_CALLBACK, 0, "prune", &prune_option, N_("pattern"),
+                 N_("prune only references whose names match pattern"),
+                 PARSE_OPT_NONEG, prune_option_parse },
                OPT__DRY_RUN(&dry_run, N_("dry run")),
                OPT_END()
        };
 
+       prune_option.prune = 1;
        argc = parse_options(argc, argv, NULL, options, 
builtin_remote_prune_usage,
                             0);
 
@@ -1356,7 +1383,7 @@ static int prune(int argc, const char **argv)
                usage_with_options(builtin_remote_prune_usage, options);
 
        for (; argc; argc--, argv++)
-               result |= prune_remote(*argv, dry_run);
+               result |= prune_remote(*argv, dry_run, &prune_option);
 
        return result;
 }
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 0dffe47..e156174 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -243,6 +243,21 @@ test_expect_success 'prune' '
        )
 '
 
+test_expect_success 'prune with --prune' '
+       git clone one prune-prune &&
+       (
+               cd prune-prune &&
+               git update-ref refs/remotes/origin/branch1 master &&
+               git update-ref refs/remotes/origin/branch2 master &&
+
+               test_must_fail git remote prune --prune origin &&
+               test_must_fail git remote prune --no-prune origin &&
+               git remote prune --prune="refs/remotes/*1" origin &&
+               test_must_fail git rev-parse origin/branch1 &&
+               git rev-parse origin/branch2
+       )
+'
+
 test_expect_success 'set-head --delete' '
        (
                cd test &&
-- 
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