[RFC 09/11] remote prune: allow --prune=<pattern> options

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <mhagger@xxxxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]