[RFC 11/11] remote: allow prune patterns to be configured

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

 



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




[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]