git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / Atom feed
* [PATCH v2 0/7] remote rename/remove: improve handling of configuration values
@ 2020-01-24  9:25 Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 1/7] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types Bert Wesarg
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg

While fixing that 'git remote rename X Y' does not rename the values for
'branch.*.pushRemote', it opened the possibility to more improvements in
this area:

 - 'remote rename' did not accept single-letter abbreviations for
   'branch.*.rebase' like 'pull --rebase' does

 - minor clean-ups the config callback

 - patch 5 will be replaced by/rebased on Matthew's work in 'config: allow user to
   know scope of config options', once 'config_scope_name' is available

 - gently handling the rename of 'remote.pushDefault'

Changes since v1:
 * avoid mixed declarations and statements
 * 'git remote remove' learned similar treatment

Bert Wesarg (7):
  pull --rebase/remote rename: document and honor single-letter
    abbreviations rebase types
  remote: clean-up by returning early to avoid one indentation
  remote: clean-up config callback
  remote rename/remove: handle branch.<name>.pushRemote config values
  [RFC] config: make `scope_name` global as `config_scope_name`
  config: provide access to the current line number
  remote rename/remove: gently handle remote.pushDefault config

 Documentation/config/branch.txt |   7 +-
 Documentation/config/pull.txt   |   7 +-
 Makefile                        |   1 +
 builtin/pull.c                  |  29 +----
 builtin/remote.c                | 188 ++++++++++++++++++++++----------
 config.c                        |  24 ++++
 config.h                        |   2 +
 rebase.c                        |  35 ++++++
 rebase.h                        |  15 +++
 t/helper/test-config.c          |  18 +--
 t/t1308-config-set.sh           |  14 ++-
 t/t5505-remote.sh               |  88 ++++++++++++++-
 12 files changed, 322 insertions(+), 106 deletions(-)
 create mode 100644 rebase.c
 create mode 100644 rebase.h

-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/7] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 2/7] remote: clean-up by returning early to avoid one indentation Bert Wesarg
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Johannes Schindelin, Junio C Hamano

When 46af44b07d (pull --rebase=<type>: allow single-letter abbreviations
for the type, 2018-08-04) landed in Git, it had the side effect that
not only 'pull --rebase=<type>' accepted the single-letter abbreviations
but also the 'pull.rebase' and 'branch.<name>.rebase' configurations.

However, 'git remote rename' did not honor these single-letter
abbreviations when reading the 'branch.*.rebase' configurations.

We now document the single-letter abbreviations and both code places
share a common function to parse the values of 'git pull --rebase=*',
'pull.rebase', and 'branches.*.rebase'.

The only functional change is the handling of the `branch_info::rebase`
value. Before it was an unsigned enum, thus the truth value could be
checked with `branch_info::rebase != 0`. But `enum rebase_type` is
signed, thus the truth value must now be checked with
`branch_info::rebase >= REBASE_TRUE`

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>

---
Changes since v1:
 * Add comment that 'git remote rename' considers unknown `.rebase' values
   as false

Cc: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Cc: Junio C Hamano <gitster@pobox.com>
---
 Documentation/config/branch.txt |  7 ++++---
 Documentation/config/pull.txt   |  7 ++++---
 Makefile                        |  1 +
 builtin/pull.c                  | 29 ++++-----------------------
 builtin/remote.c                | 30 +++++++++++-----------------
 rebase.c                        | 35 +++++++++++++++++++++++++++++++++
 rebase.h                        | 15 ++++++++++++++
 7 files changed, 75 insertions(+), 49 deletions(-)
 create mode 100644 rebase.c
 create mode 100644 rebase.h

diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index a592d522a7..cc5f3249fc 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -81,15 +81,16 @@ branch.<name>.rebase::
 	"git pull" is run. See "pull.rebase" for doing this in a non
 	branch-specific manner.
 +
-When `merges`, pass the `--rebase-merges` option to 'git rebase'
+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'
 so that the local merge commits are included in the rebase (see
 linkgit:git-rebase[1] for details).
 +
-When `preserve` (deprecated in favor of `merges`), also pass
+When `preserve` (or just 'p', deprecated in favor of `merges`), also pass
 `--preserve-merges` along to 'git rebase' so that locally committed merge
 commits will not be flattened by running 'git pull'.
 +
-When the value is `interactive`, the rebase is run in interactive mode.
+When the value is `interactive` (or just 'i'), the rebase is run in interactive
+mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/Documentation/config/pull.txt b/Documentation/config/pull.txt
index b87cab31b3..5404830609 100644
--- a/Documentation/config/pull.txt
+++ b/Documentation/config/pull.txt
@@ -14,15 +14,16 @@ pull.rebase::
 	pull" is run. See "branch.<name>.rebase" for setting this on a
 	per-branch basis.
 +
-When `merges`, pass the `--rebase-merges` option to 'git rebase'
+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'
 so that the local merge commits are included in the rebase (see
 linkgit:git-rebase[1] for details).
 +
-When `preserve` (deprecated in favor of `merges`), also pass
+When `preserve` (or just 'p', deprecated in favor of `merges`), also pass
 `--preserve-merges` along to 'git rebase' so that locally committed merge
 commits will not be flattened by running 'git pull'.
 +
-When the value is `interactive`, the rebase is run in interactive mode.
+When the value is `interactive` (or just 'i'), the rebase is run in interactive
+mode.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
diff --git a/Makefile b/Makefile
index 09f98b777c..96ced97bff 100644
--- a/Makefile
+++ b/Makefile
@@ -954,6 +954,7 @@ LIB_OBJS += quote.o
 LIB_OBJS += range-diff.o
 LIB_OBJS += reachable.o
 LIB_OBJS += read-cache.o
+LIB_OBJS += rebase.o
 LIB_OBJS += rebase-interactive.o
 LIB_OBJS += reflog-walk.o
 LIB_OBJS += refs.o
diff --git a/builtin/pull.c b/builtin/pull.c
index d25ff13a60..888181c07c 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -15,6 +15,7 @@
 #include "sha1-array.h"
 #include "remote.h"
 #include "dir.h"
+#include "rebase.h"
 #include "refs.h"
 #include "refspec.h"
 #include "revision.h"
@@ -26,15 +27,6 @@
 #include "commit-reach.h"
 #include "sequencer.h"
 
-enum rebase_type {
-	REBASE_INVALID = -1,
-	REBASE_FALSE = 0,
-	REBASE_TRUE,
-	REBASE_PRESERVE,
-	REBASE_MERGES,
-	REBASE_INTERACTIVE
-};
-
 /**
  * Parses the value of --rebase. If value is a false value, returns
  * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
@@ -45,22 +37,9 @@ enum rebase_type {
 static enum rebase_type parse_config_rebase(const char *key, const char *value,
 		int fatal)
 {
-	int v = git_parse_maybe_bool(value);
-
-	if (!v)
-		return REBASE_FALSE;
-	else if (v > 0)
-		return REBASE_TRUE;
-	else if (!strcmp(value, "preserve") || !strcmp(value, "p"))
-		return REBASE_PRESERVE;
-	else if (!strcmp(value, "merges") || !strcmp(value, "m"))
-		return REBASE_MERGES;
-	else if (!strcmp(value, "interactive") || !strcmp(value, "i"))
-		return REBASE_INTERACTIVE;
-	/*
-	 * Please update _git_config() in git-completion.bash when you
-	 * add new rebase modes.
-	 */
+	enum rebase_type v = rebase_parse_value(value);
+	if (v != REBASE_INVALID)
+		return v;
 
 	if (fatal)
 		die(_("Invalid value for %s: %s"), key, value);
diff --git a/builtin/remote.c b/builtin/remote.c
index 96bbe828fe..6802765e73 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -6,6 +6,7 @@
 #include "string-list.h"
 #include "strbuf.h"
 #include "run-command.h"
+#include "rebase.h"
 #include "refs.h"
 #include "refspec.h"
 #include "object-store.h"
@@ -248,9 +249,7 @@ static int add(int argc, const char **argv)
 struct branch_info {
 	char *remote_name;
 	struct string_list merge;
-	enum {
-		NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES
-	} rebase;
+	enum rebase_type rebase;
 };
 
 static struct string_list branch_list = STRING_LIST_INIT_NODUP;
@@ -305,17 +304,12 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 				space = strchr(value, ' ');
 			}
 			string_list_append(&info->merge, xstrdup(value));
-		} else {
-			int v = git_parse_maybe_bool(value);
-			if (v >= 0)
-				info->rebase = v;
-			else if (!strcmp(value, "preserve"))
-				info->rebase = NORMAL_REBASE;
-			else if (!strcmp(value, "merges"))
-				info->rebase = REBASE_MERGES;
-			else if (!strcmp(value, "interactive"))
-				info->rebase = INTERACTIVE_REBASE;
-		}
+		} else
+			/*
+			 * Consider invalid values as false and check the
+			 * truth value with >= REBASE_TRUE.
+			 */
+			info->rebase = rebase_parse_value(value);
 	}
 	return 0;
 }
@@ -943,7 +937,7 @@ static int add_local_to_show_info(struct string_list_item *branch_item, void *cb
 		return 0;
 	if ((n = strlen(branch_item->string)) > show_info->width)
 		show_info->width = n;
-	if (branch_info->rebase)
+	if (branch_info->rebase >= REBASE_TRUE)
 		show_info->any_rebase = 1;
 
 	item = string_list_insert(show_info->list, branch_item->string);
@@ -960,16 +954,16 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)
 	int width = show_info->width + 4;
 	int i;
 
-	if (branch_info->rebase && branch_info->merge.nr > 1) {
+	if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
 		error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
 			item->string);
 		return 0;
 	}
 
 	printf("    %-*s ", show_info->width, item->string);
-	if (branch_info->rebase) {
+	if (branch_info->rebase >= REBASE_TRUE) {
 		const char *msg;
-		if (branch_info->rebase == INTERACTIVE_REBASE)
+		if (branch_info->rebase == REBASE_INTERACTIVE)
 			msg = _("rebases interactively onto remote %s");
 		else if (branch_info->rebase == REBASE_MERGES)
 			msg = _("rebases interactively (with merges) onto "
diff --git a/rebase.c b/rebase.c
new file mode 100644
index 0000000000..f8137d859b
--- /dev/null
+++ b/rebase.c
@@ -0,0 +1,35 @@
+#include "rebase.h"
+#include "config.h"
+
+/*
+ * Parses textual value for pull.rebase, branch.<name>.rebase, etc.
+ * Unrecognised value yields REBASE_INVALID, which traditionally is
+ * treated the same way as REBASE_FALSE.
+ *
+ * The callers that care if (any) rebase is requested should say
+ *   if (REBASE_TRUE <= rebase_parse_value(string))
+ *
+ * The callers that want to differenciate an unrecognised value and
+ * false can do so by treating _INVALID and _FALSE differently.
+ */
+enum rebase_type rebase_parse_value(const char *value)
+{
+	int v = git_parse_maybe_bool(value);
+
+	if (!v)
+		return REBASE_FALSE;
+	else if (v > 0)
+		return REBASE_TRUE;
+	else if (!strcmp(value, "preserve") || !strcmp(value, "p"))
+		return REBASE_PRESERVE;
+	else if (!strcmp(value, "merges") || !strcmp(value, "m"))
+		return REBASE_MERGES;
+	else if (!strcmp(value, "interactive") || !strcmp(value, "i"))
+		return REBASE_INTERACTIVE;
+	/*
+	 * Please update _git_config() in git-completion.bash when you
+	 * add new rebase modes.
+	 */
+
+	return REBASE_INVALID;
+}
diff --git a/rebase.h b/rebase.h
new file mode 100644
index 0000000000..cc723d4748
--- /dev/null
+++ b/rebase.h
@@ -0,0 +1,15 @@
+#ifndef REBASE_H
+#define REBASE_H
+
+enum rebase_type {
+	REBASE_INVALID = -1,
+	REBASE_FALSE = 0,
+	REBASE_TRUE,
+	REBASE_PRESERVE,
+	REBASE_MERGES,
+	REBASE_INTERACTIVE
+};
+
+enum rebase_type rebase_parse_value(const char *value);
+
+#endif /* REBASE */
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 2/7] remote: clean-up by returning early to avoid one indentation
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 1/7] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24  9:25 ` [PATCH 3/7] remote: clean-up config callback Bert Wesarg
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Junio C Hamano

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>

---
Changes since v1:
 * avoid mixed declarations and statements

Cc: Junio C Hamano <gitster@pobox.com>
---
 builtin/remote.c | 94 ++++++++++++++++++++++++------------------------
 1 file changed, 48 insertions(+), 46 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 6802765e73..4cf929bfc6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -263,54 +263,56 @@ static const char *abbrev_ref(const char *name, const char *prefix)
 
 static int config_read_branches(const char *key, const char *value, void *cb)
 {
-	if (starts_with(key, "branch.")) {
-		const char *orig_key = key;
-		char *name;
-		struct string_list_item *item;
-		struct branch_info *info;
-		enum { REMOTE, MERGE, REBASE } type;
-		size_t key_len;
-
-		key += 7;
-		if (strip_suffix(key, ".remote", &key_len)) {
-			name = xmemdupz(key, key_len);
-			type = REMOTE;
-		} else if (strip_suffix(key, ".merge", &key_len)) {
-			name = xmemdupz(key, key_len);
-			type = MERGE;
-		} else if (strip_suffix(key, ".rebase", &key_len)) {
-			name = xmemdupz(key, key_len);
-			type = REBASE;
-		} else
-			return 0;
+	const char *orig_key = key;
+	char *name;
+	struct string_list_item *item;
+	struct branch_info *info;
+	enum { REMOTE, MERGE, REBASE } type;
+	size_t key_len;
 
-		item = string_list_insert(&branch_list, name);
+	if (!starts_with(key, "branch."))
+		return 0;
+
+	key += 7;
+	if (strip_suffix(key, ".remote", &key_len)) {
+		name = xmemdupz(key, key_len);
+		type = REMOTE;
+	} else if (strip_suffix(key, ".merge", &key_len)) {
+		name = xmemdupz(key, key_len);
+		type = MERGE;
+	} else if (strip_suffix(key, ".rebase", &key_len)) {
+		name = xmemdupz(key, key_len);
+		type = REBASE;
+	} else
+		return 0;
+
+	item = string_list_insert(&branch_list, name);
+
+	if (!item->util)
+		item->util = xcalloc(1, sizeof(struct branch_info));
+	info = item->util;
+	if (type == REMOTE) {
+		if (info->remote_name)
+			warning(_("more than one %s"), orig_key);
+		info->remote_name = xstrdup(value);
+	} else if (type == MERGE) {
+		char *space = strchr(value, ' ');
+		value = abbrev_branch(value);
+		while (space) {
+			char *merge;
+			merge = xstrndup(value, space - value);
+			string_list_append(&info->merge, merge);
+			value = abbrev_branch(space + 1);
+			space = strchr(value, ' ');
+		}
+		string_list_append(&info->merge, xstrdup(value));
+	} else
+		/*
+		 * Consider invalid values as false and check the
+		 * truth value with >= REBASE_TRUE.
+		 */
+		info->rebase = rebase_parse_value(value);
 
-		if (!item->util)
-			item->util = xcalloc(1, sizeof(struct branch_info));
-		info = item->util;
-		if (type == REMOTE) {
-			if (info->remote_name)
-				warning(_("more than one %s"), orig_key);
-			info->remote_name = xstrdup(value);
-		} else if (type == MERGE) {
-			char *space = strchr(value, ' ');
-			value = abbrev_branch(value);
-			while (space) {
-				char *merge;
-				merge = xstrndup(value, space - value);
-				string_list_append(&info->merge, merge);
-				value = abbrev_branch(space + 1);
-				space = strchr(value, ' ');
-			}
-			string_list_append(&info->merge, xstrdup(value));
-		} else
-			/*
-			 * Consider invalid values as false and check the
-			 * truth value with >= REBASE_TRUE.
-			 */
-			info->rebase = rebase_parse_value(value);
-	}
 	return 0;
 }
 
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/7] remote: clean-up config callback
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 1/7] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 2/7] remote: clean-up by returning early to avoid one indentation Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24  9:25 ` [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values Bert Wesarg
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Junio C Hamano, Johannes Schindelin

Some minor clean-ups in function `config_read_branches`:

 * remove hardcoded length in `key += 7`
 * call `xmemdupz` only once
 * use a switch to handle the configuration type and add a `BUG()`

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>

---
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/remote.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 4cf929bfc6..9ee44c9f6c 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -273,29 +273,29 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 	if (!starts_with(key, "branch."))
 		return 0;
 
-	key += 7;
-	if (strip_suffix(key, ".remote", &key_len)) {
-		name = xmemdupz(key, key_len);
+	key += strlen("branch.");
+	if (strip_suffix(key, ".remote", &key_len))
 		type = REMOTE;
-	} else if (strip_suffix(key, ".merge", &key_len)) {
-		name = xmemdupz(key, key_len);
+	else if (strip_suffix(key, ".merge", &key_len))
 		type = MERGE;
-	} else if (strip_suffix(key, ".rebase", &key_len)) {
-		name = xmemdupz(key, key_len);
+	else if (strip_suffix(key, ".rebase", &key_len))
 		type = REBASE;
-	} else
+	else
 		return 0;
+	name = xmemdupz(key, key_len);
 
 	item = string_list_insert(&branch_list, name);
 
 	if (!item->util)
 		item->util = xcalloc(1, sizeof(struct branch_info));
 	info = item->util;
-	if (type == REMOTE) {
+	switch (type) {
+	case REMOTE:
 		if (info->remote_name)
 			warning(_("more than one %s"), orig_key);
 		info->remote_name = xstrdup(value);
-	} else if (type == MERGE) {
+		break;
+	case MERGE: {
 		char *space = strchr(value, ' ');
 		value = abbrev_branch(value);
 		while (space) {
@@ -306,12 +306,18 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			space = strchr(value, ' ');
 		}
 		string_list_append(&info->merge, xstrdup(value));
-	} else
+		break;
+	}
+	case REBASE:
 		/*
 		 * Consider invalid values as false and check the
 		 * truth value with >= REBASE_TRUE.
 		 */
 		info->rebase = rebase_parse_value(value);
+		break;
+	default:
+		BUG("unexpected type=%d", type);
+	}
 
 	return 0;
 }
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
                   ` (2 preceding siblings ...)
  2020-01-24  9:25 ` [PATCH 3/7] remote: clean-up config callback Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-25  0:46   ` Johannes Schindelin
  2020-01-24  9:25 ` [RFC PATCH 5/7] config: make `scope_name` global as `config_scope_name` Bert Wesarg
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Junio C Hamano, Johannes Schindelin

When renaming or removing a remote with

    git remote rename X Y
    git remote remove X

Git already renames/removes any config values from

    branch.<name>.remote = X

to

    branch.<name>.remote = Y

As branch.<name>.pushRemote also names a remote, it now also renames
or removes these config values from

    branch.<name>.pushRemote = X

to

    branch.<name>.pushRemote = Y

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>

---

Changes since v3:

 * handle also 'git remote remove'

Cc: Junio C Hamano <gitster@pobox.com>
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/remote.c  | 22 +++++++++++++++++++++-
 t/t5505-remote.sh | 16 +++++++++++++++-
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 9ee44c9f6c..a2379a14bf 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -250,6 +250,7 @@ struct branch_info {
 	char *remote_name;
 	struct string_list merge;
 	enum rebase_type rebase;
+	char *push_remote_name;
 };
 
 static struct string_list branch_list = STRING_LIST_INIT_NODUP;
@@ -267,7 +268,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 	char *name;
 	struct string_list_item *item;
 	struct branch_info *info;
-	enum { REMOTE, MERGE, REBASE } type;
+	enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
 	size_t key_len;
 
 	if (!starts_with(key, "branch."))
@@ -280,6 +281,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 		type = MERGE;
 	else if (strip_suffix(key, ".rebase", &key_len))
 		type = REBASE;
+	else if (strip_suffix(key, ".pushremote", &key_len))
+		type = PUSH_REMOTE;
 	else
 		return 0;
 	name = xmemdupz(key, key_len);
@@ -315,6 +318,11 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 		 */
 		info->rebase = rebase_parse_value(value);
 		break;
+	case PUSH_REMOTE:
+		if (info->push_remote_name)
+			warning(_("more than one %s"), orig_key);
+		info->push_remote_name = xstrdup(value);
+		break;
 	default:
 		BUG("unexpected type=%d", type);
 	}
@@ -682,6 +690,11 @@ static int mv(int argc, const char **argv)
 			strbuf_addf(&buf, "branch.%s.remote", item->string);
 			git_config_set(buf.buf, rename.new_name);
 		}
+		if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "branch.%s.pushremote", item->string);
+			git_config_set(buf.buf, rename.new_name);
+		}
 	}
 
 	if (!refspec_updated)
@@ -783,6 +796,13 @@ static int rm(int argc, const char **argv)
 					die(_("could not unset '%s'"), buf.buf);
 			}
 		}
+		if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "branch.%s.pushremote", item->string);
+			result = git_config_set_gently(buf.buf, NULL);
+			if (result && result != CONFIG_NOTHING_SET)
+				die(_("could not unset '%s'"), buf.buf);
+		}
 	}
 
 	/*
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 883b32efa0..082042b05a 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -737,12 +737,14 @@ test_expect_success 'rename a remote' '
 	git clone one four &&
 	(
 		cd four &&
+		git config branch.master.pushRemote origin &&
 		git remote rename origin upstream &&
 		test -z "$(git for-each-ref refs/remotes/origin)" &&
 		test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
 		test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
 		test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
-		test "$(git config branch.master.remote)" = "upstream"
+		test "$(git config branch.master.remote)" = "upstream" &&
+		test "$(git config branch.master.pushRemote)" = "upstream"
 	)
 '
 
@@ -784,6 +786,18 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '
 	git -C four.four remote rename origin upstream
 '
 
+test_expect_success 'remove a remote' '
+	git clone one four.five &&
+	(
+		cd four.five &&
+		git config branch.master.pushRemote origin &&
+		git remote remove origin &&
+		test -z "$(git for-each-ref refs/remotes/origin)" &&
+		test_must_fail git config branch.master.remote &&
+		test_must_fail git config branch.master.pushRemote
+	)
+'
+
 cat >remotes_origin <<EOF
 URL: $(pwd)/one
 Push: refs/heads/master:refs/heads/upstream
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [RFC PATCH 5/7] config: make `scope_name` global as `config_scope_name`
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
                   ` (3 preceding siblings ...)
  2020-01-24  9:25 ` [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24  9:25 ` [PATCH 6/7] config: provide access to the current line number Bert Wesarg
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Matthew Rogers

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
---
Will be replaced by Matthew Rogers.

Cc: Matthew Rogers <mattr94@gmail.com>
---
 config.c               | 16 ++++++++++++++++
 config.h               |  1 +
 t/helper/test-config.c | 17 +----------------
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/config.c b/config.c
index d75f88ca0c..4c461bb7a3 100644
--- a/config.c
+++ b/config.c
@@ -3317,6 +3317,22 @@ enum config_scope current_config_scope(void)
 		return current_parsing_scope;
 }
 
+const char *config_scope_name(enum config_scope scope)
+{
+	switch (scope) {
+	case CONFIG_SCOPE_SYSTEM:
+		return "system";
+	case CONFIG_SCOPE_GLOBAL:
+		return "global";
+	case CONFIG_SCOPE_REPO:
+		return "repo";
+	case CONFIG_SCOPE_CMDLINE:
+		return "cmdline";
+	default:
+		return "unknown";
+	}
+}
+
 int lookup_config(const char **mapping, int nr_mapping, const char *var)
 {
 	int i;
diff --git a/config.h b/config.h
index 91fd4c5e96..c063f33ff6 100644
--- a/config.h
+++ b/config.h
@@ -301,6 +301,7 @@ enum config_scope {
 	CONFIG_SCOPE_REPO,
 	CONFIG_SCOPE_CMDLINE,
 };
+const char *config_scope_name(enum config_scope scope);
 
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 214003d5b2..1e3bc7c8f4 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -37,21 +37,6 @@
  *
  */
 
-static const char *scope_name(enum config_scope scope)
-{
-	switch (scope) {
-	case CONFIG_SCOPE_SYSTEM:
-		return "system";
-	case CONFIG_SCOPE_GLOBAL:
-		return "global";
-	case CONFIG_SCOPE_REPO:
-		return "repo";
-	case CONFIG_SCOPE_CMDLINE:
-		return "cmdline";
-	default:
-		return "unknown";
-	}
-}
 static int iterate_cb(const char *var, const char *value, void *data)
 {
 	static int nr;
@@ -63,7 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
-	printf("scope=%s\n", scope_name(current_config_scope()));
+	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
 	return 0;
 }
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 6/7] config: provide access to the current line number
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
                   ` (4 preceding siblings ...)
  2020-01-24  9:25 ` [RFC PATCH 5/7] config: make `scope_name` global as `config_scope_name` Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24  9:25 ` [PATCH v2 7/7] remote rename/remove: gently handle remote.pushDefault config Bert Wesarg
  2020-01-24 21:00 ` [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Junio C Hamano
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg

Users are nowadays trained to see message from CLI tools in the form

    <file>:<lno>: …

To be able to give such messages when notifying the user about
configurations in any config file, it is currently only possible to get
the file name (if the value originates from a file to begin with) via
`current_config_name()`. Now it is also possible to query the current line
number for the configuration.

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
---
 config.c               |  8 ++++++++
 config.h               |  1 +
 t/helper/test-config.c |  1 +
 t/t1308-config-set.sh  | 14 ++++++++++++--
 4 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/config.c b/config.c
index 4c461bb7a3..5d1d6b5871 100644
--- a/config.c
+++ b/config.c
@@ -3333,6 +3333,14 @@ const char *config_scope_name(enum config_scope scope)
 	}
 }
 
+int current_config_line(void)
+{
+	if (current_config_kvi)
+		return current_config_kvi->linenr;
+	else
+		return cf->linenr;
+}
+
 int lookup_config(const char **mapping, int nr_mapping, const char *var)
 {
 	int i;
diff --git a/config.h b/config.h
index c063f33ff6..371f7f2dd0 100644
--- a/config.h
+++ b/config.h
@@ -306,6 +306,7 @@ const char *config_scope_name(enum config_scope scope);
 enum config_scope current_config_scope(void);
 const char *current_config_origin_type(void);
 const char *current_config_name(void);
+int current_config_line(void);
 
 /**
  * Include Directives
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index 1e3bc7c8f4..234c722b48 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -48,6 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)
 	printf("value=%s\n", value ? value : "(null)");
 	printf("origin=%s\n", current_config_origin_type());
 	printf("name=%s\n", current_config_name());
+	printf("lno=%d\n", current_config_line());
 	printf("scope=%s\n", config_scope_name(current_config_scope()));
 
 	return 0;
diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh
index 7b4e1a63eb..9e36e7a590 100755
--- a/t/t1308-config-set.sh
+++ b/t/t1308-config-set.sh
@@ -238,8 +238,8 @@ test_expect_success 'error on modifying repo config without repo' '
 
 cmdline_config="'foo.bar=from-cmdline'"
 test_expect_success 'iteration shows correct origins' '
-	echo "[foo]bar = from-repo" >.git/config &&
-	echo "[foo]bar = from-home" >.gitconfig &&
+	printf "[ignore]\n\tthis = please\n[foo]bar = from-repo\n" >.git/config &&
+	printf "[foo]\n\tbar = from-home\n" >.gitconfig &&
 	if test_have_prereq MINGW
 	then
 		# Use Windows path (i.e. *not* $HOME)
@@ -253,18 +253,28 @@ test_expect_success 'iteration shows correct origins' '
 	value=from-home
 	origin=file
 	name=$HOME_GITCONFIG
+	lno=2
 	scope=global
 
+	key=ignore.this
+	value=please
+	origin=file
+	name=.git/config
+	lno=2
+	scope=repo
+
 	key=foo.bar
 	value=from-repo
 	origin=file
 	name=.git/config
+	lno=3
 	scope=repo
 
 	key=foo.bar
 	value=from-cmdline
 	origin=command line
 	name=
+	lno=-1
 	scope=cmdline
 	EOF
 	GIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 7/7] remote rename/remove: gently handle remote.pushDefault config
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
                   ` (5 preceding siblings ...)
  2020-01-24  9:25 ` [PATCH 6/7] config: provide access to the current line number Bert Wesarg
@ 2020-01-24  9:25 ` Bert Wesarg
  2020-01-24 21:00 ` [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Junio C Hamano
  7 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-24  9:25 UTC (permalink / raw)
  To: git; +Cc: Bert Wesarg, Junio C Hamano, Johannes Schindelin, Matthew Rogers

When renaming a remote with

    git remote rename X Y
    git remote remove X

Git already renames or removes any branch.<name>.remote and
branch.<name>.pushRemote configurations if their value is X.

However remote.pushDefault needs a more gentle approach, as this may be
set in a non-repo configuration file. In such a case only a warning is
printed, such as:

warning: The global configuration remote.pushDefault in:
	$HOME/.gitconfig:35
now names the non-existent remote origin

It is changed to remote.pushDefault = Y or removed when set in a repo
configuration though.

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
---

Matthew, you are in Cc because of your current work 'config: allow user to
know scope of config options'. I think I'm correct to assuming an ordering
of the enum config_scope.

Changes since v1:
 * handle also 'git remote remove'

Cc: Junio C Hamano <gitster@pobox.com>
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>
Cc: Matthew Rogers <mattr94@gmail.com>
---
 builtin/remote.c  | 54 +++++++++++++++++++++++++++++++++
 t/t5505-remote.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index a2379a14bf..7404e50c13 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -615,6 +615,55 @@ static int migrate_file(struct remote *remote)
 	return 0;
 }
 
+struct push_default_info
+{
+	const char *old_name;
+	enum config_scope scope;
+	struct strbuf origin;
+	int linenr;
+};
+
+static int config_read_push_default(const char *key, const char *value,
+	void *cb)
+{
+	struct push_default_info* info = cb;
+	if (strcmp(key, "remote.pushdefault") || strcmp(value, info->old_name))
+		return 0;
+
+	info->scope = current_config_scope();
+	strbuf_reset(&info->origin);
+	strbuf_addstr(&info->origin, current_config_name());
+	info->linenr = current_config_line();
+
+	return 0;
+}
+
+static void handle_push_default(const char* old_name, const char* new_name)
+{
+	struct push_default_info push_default = {
+		old_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };
+	git_config(config_read_push_default, &push_default);
+	if (push_default.scope >= CONFIG_SCOPE_CMDLINE)
+		; /* pass */
+	else if (push_default.scope >= CONFIG_SCOPE_REPO) {
+		int result = git_config_set_gently("remote.pushDefault",
+						   new_name);
+		if (new_name && result && result != CONFIG_NOTHING_SET)
+			die(_("could not set '%s'"), "remote.pushDefault");
+		else if (!new_name && result && result != CONFIG_NOTHING_SET)
+			die(_("could not unset '%s'"), "remote.pushDefault");
+	} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {
+		/* warn */
+		warning(_("The %s configuration remote.pushDefault in:\n"
+			  "\t%s:%d\n"
+			  "now names the non-existent remote '%s'"),
+			config_scope_name(push_default.scope),
+			push_default.origin.buf, push_default.linenr,
+			old_name);
+	}
+}
+
+
 static int mv(int argc, const char **argv)
 {
 	struct option options[] = {
@@ -750,6 +799,9 @@ static int mv(int argc, const char **argv)
 			die(_("creating '%s' failed"), buf.buf);
 	}
 	string_list_clear(&remote_branches, 1);
+
+	handle_push_default(rename.old_name, rename.new_name);
+
 	return 0;
 }
 
@@ -835,6 +887,8 @@ static int rm(int argc, const char **argv)
 		strbuf_addf(&buf, "remote.%s", remote->name);
 		if (git_config_rename_section(buf.buf, NULL) < 1)
 			return error(_("Could not remove config section '%s'"), buf.buf);
+
+		handle_push_default(remote->name, NULL);
 	}
 
 	return result;
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 082042b05a..bbff8c5770 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -737,6 +737,7 @@ test_expect_success 'rename a remote' '
 	git clone one four &&
 	(
 		cd four &&
+		test_config_global remote.pushDefault origin &&
 		git config branch.master.pushRemote origin &&
 		git remote rename origin upstream &&
 		test -z "$(git for-each-ref refs/remotes/origin)" &&
@@ -744,7 +745,42 @@ test_expect_success 'rename a remote' '
 		test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
 		test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
 		test "$(git config branch.master.remote)" = "upstream" &&
-		test "$(git config branch.master.pushRemote)" = "upstream"
+		test "$(git config branch.master.pushRemote)" = "upstream" &&
+		test "$(git config --global remote.pushDefault)" = "origin"
+	)
+'
+
+test_expect_success 'rename a remote renames repo remote.pushDefault' '
+	git clone one four.1 &&
+	(
+		cd four.1 &&
+		git config remote.pushDefault origin &&
+		git remote rename origin upstream &&
+		test "$(git config --local remote.pushDefault)" = "upstream"
+	)
+'
+
+test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '
+	git clone one four.2 &&
+	(
+		cd four.2 &&
+		test_config_global remote.pushDefault other &&
+		git config remote.pushDefault origin &&
+		git remote rename origin upstream &&
+		test "$(git config --global remote.pushDefault)" = "other" &&
+		test "$(git config --local remote.pushDefault)" = "upstream"
+	)
+'
+
+test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '
+	git clone one four.3 &&
+	(
+		cd four.3 &&
+		test_config_global remote.pushDefault origin &&
+		git config remote.pushDefault origin &&
+		git remote rename origin upstream &&
+		test "$(git config --global remote.pushDefault)" = "origin" &&
+		test "$(git config --local remote.pushDefault)" = "upstream"
 	)
 '
 
@@ -790,11 +826,47 @@ test_expect_success 'remove a remote' '
 	git clone one four.five &&
 	(
 		cd four.five &&
+		test_config_global remote.pushDefault origin &&
 		git config branch.master.pushRemote origin &&
 		git remote remove origin &&
 		test -z "$(git for-each-ref refs/remotes/origin)" &&
 		test_must_fail git config branch.master.remote &&
-		test_must_fail git config branch.master.pushRemote
+		test_must_fail git config branch.master.pushRemote &&
+		test "$(git config --global remote.pushDefault)" = "origin"
+	)
+'
+
+test_expect_success 'remove a remote removes repo remote.pushDefault' '
+	git clone one four.five.1 &&
+	(
+		cd four.five.1 &&
+		git config remote.pushDefault origin &&
+		git remote remove origin &&
+		test_must_fail git config --local remote.pushDefault
+	)
+'
+
+test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '
+	git clone one four.five.2 &&
+	(
+		cd four.five.2 &&
+		test_config_global remote.pushDefault other &&
+		git config remote.pushDefault origin &&
+		git remote remove origin &&
+		test "$(git config --global remote.pushDefault)" = "other" &&
+		test_must_fail git config --local remote.pushDefault
+	)
+'
+
+test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '
+	git clone one four.five.3 &&
+	(
+		cd four.five.3 &&
+		test_config_global remote.pushDefault origin &&
+		git config remote.pushDefault origin &&
+		git remote remove origin &&
+		test "$(git config --global remote.pushDefault)" = "origin" &&
+		test_must_fail git config --local remote.pushDefault
 	)
 '
 
-- 
2.24.1.497.g9abd7b20b4.dirty


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/7] remote rename/remove: improve handling of configuration values
  2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
                   ` (6 preceding siblings ...)
  2020-01-24  9:25 ` [PATCH v2 7/7] remote rename/remove: gently handle remote.pushDefault config Bert Wesarg
@ 2020-01-24 21:00 ` Junio C Hamano
  2020-01-25  0:39   ` Matt Rogers
  7 siblings, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2020-01-24 21:00 UTC (permalink / raw)
  To: Bert Wesarg; +Cc: git

All steps looked quite sensibly done.

>  - patch 5 will be replaced by/rebased on Matthew's work in 'config: allow user to
>    know scope of config options', once 'config_scope_name' is available

I expect that Matthew's topic would become solid enough after one
more reroll to name the function back to config_scope_name(); after
that, let's drop the step and instead fork this topic off of Matthew's
topic to queue the remaining patches on top.

Thanks.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/7] remote rename/remove: improve handling of configuration values
  2020-01-24 21:00 ` [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Junio C Hamano
@ 2020-01-25  0:39   ` Matt Rogers
  2020-01-27  6:50     ` Bert Wesarg
  0 siblings, 1 reply; 14+ messages in thread
From: Matt Rogers @ 2020-01-25  0:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Bert Wesarg, git

Yeah, I just resubmitted so you should be good to go

On Fri, Jan 24, 2020 at 4:10 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> All steps looked quite sensibly done.
>
> >  - patch 5 will be replaced by/rebased on Matthew's work in 'config: allow user to
> >    know scope of config options', once 'config_scope_name' is available
>
> I expect that Matthew's topic would become solid enough after one
> more reroll to name the function back to config_scope_name(); after
> that, let's drop the step and instead fork this topic off of Matthew's
> topic to queue the remaining patches on top.
>
> Thanks.



-- 
Matthew Rogers

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values
  2020-01-24  9:25 ` [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values Bert Wesarg
@ 2020-01-25  0:46   ` Johannes Schindelin
  2020-01-25  7:29     ` Bert Wesarg
  0 siblings, 1 reply; 14+ messages in thread
From: Johannes Schindelin @ 2020-01-25  0:46 UTC (permalink / raw)
  To: Bert Wesarg; +Cc: git, Junio C Hamano

Hi Bert,

On Fri, 24 Jan 2020, Bert Wesarg wrote:

> When renaming or removing a remote with
>
>     git remote rename X Y
>     git remote remove X
>
> Git already renames/removes any config values from
>
>     branch.<name>.remote = X
>
> to
>
>     branch.<name>.remote = Y
>
> As branch.<name>.pushRemote also names a remote, it now also renames
> or removes these config values from
>
>     branch.<name>.pushRemote = X
>
> to
>
>     branch.<name>.pushRemote = Y
>
> Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
>
> ---

This commit seems to cause a failure in t5505:
https://dev.azure.com/gitgitgadget/git/_build/results?buildId=27833&view=ms.vss-test-web.build-test-results-tab

Here is the excerpt of the log:

-- snip --
[...]
expecting success of 5505.15 'show':
	(
		cd test &&
		git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
		git fetch &&
		git checkout -b ahead origin/master &&
		echo 1 >>file &&
		test_tick &&
		git commit -m update file &&
		git checkout master &&
		git branch --track octopus origin/master &&
		git branch --track rebase origin/master &&
		git branch -d -r origin/master &&
		git config --add remote.two.url ../two &&
		git config --add remote.two.pushurl ../three &&
		git config branch.rebase.rebase true &&
		git config branch.octopus.merge "topic-a topic-b topic-c" &&
		(
			cd ../one &&
			echo 1 >file &&
			test_tick &&
			git commit -m update file
		) &&
		git config --add remote.origin.push : &&
		git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
		git config --add remote.origin.push +refs/tags/lastbackup &&
		git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
		git config --add remote.two.push refs/heads/master:refs/heads/another &&
		git remote show origin two >output &&
		git branch -d rebase octopus &&
		test_i18ncmp expect output
	)

+ cd test
+ git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream
+ git fetch
From /home/virtualbox/git/t/trash directory.t5505-remote/one
 * [new branch]      master     -> upstream
+ git checkout -b ahead origin/master
Switched to a new branch 'ahead'
Branch 'ahead' set up to track remote branch 'master' from 'origin'.
+ echo 1
+ test_tick
+ test -z
+ test_tick=1112911993
+ GIT_COMMITTER_DATE=1112911993 -0700
+ GIT_AUTHOR_DATE=1112911993 -0700
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+ git commit -m update file
[ahead 847549e] update
 Author: A U Thor <author@example.com>
 1 file changed, 1 insertion(+)
+ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
+ git branch --track octopus origin/master
Branch 'octopus' set up to track remote branch 'master' from 'origin'.
+ git branch --track rebase origin/master
Branch 'rebase' set up to track remote branch 'master' from 'origin'.
+ git branch -d -r origin/master
Deleted remote-tracking branch origin/master (was 9d34b14).
+ git config --add remote.two.url ../two
+ git config --add remote.two.pushurl ../three
+ git config branch.rebase.rebase true
+ git config branch.octopus.merge topic-a topic-b topic-c
+ cd ../one
+ echo 1
+ test_tick
+ test -z set
+ test_tick=1112912053
+ GIT_COMMITTER_DATE=1112912053 -0700
+ GIT_AUTHOR_DATE=1112912053 -0700
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+ git commit -m update file
[master 6329a3c] update
 Author: A U Thor <author@example.com>
 1 file changed, 1 insertion(+)
+ git config --add remote.origin.push :
+ git config --add remote.origin.push refs/heads/master:refs/heads/upstream
+ git config --add remote.origin.push +refs/tags/lastbackup
+ git config --add remote.two.push +refs/heads/ahead:refs/heads/master
+ git config --add remote.two.push refs/heads/master:refs/heads/another
+ git remote show origin two
error: src refspec refs/tags/lastbackup does not match any
+ git branch -d rebase octopus
Deleted branch rebase (was 9d34b14).
Deleted branch octopus (was 9d34b14).
+ test_i18ncmp expect output
+ test_have_prereq C_LOCALE_OUTPUT
+ save_IFS=

+ IFS=,
+ set -- C_LOCALE_OUTPUT
+ IFS=

+ total_prereq=0
+ ok_prereq=0
+ missing_prereq=
+ negative_prereq=
+ total_prereq=1
+ satisfied_this_prereq=t
+ ok_prereq=1
+ test 1 = 1
+ test_cmp expect output
+ diff -u expect output
--- expect	2020-01-25 00:44:41.496720000 +0000
+++ output	2020-01-25 00:44:43.513861900 +0000
@@ -5,13 +5,6 @@
   Remote branches:
     master new (next fetch will store in remotes/origin)
     side   tracked
-  Local branches configured for 'git pull':
-    ahead    merges with remote master
-    master   merges with remote master
-    octopus  merges with remote topic-a
-                and with remote topic-b
-                and with remote topic-c
-    rebase  rebases onto remote master
   Local refs configured for 'git push':
     master pushes to master   (local out of date)
     master pushes to upstream (create)
error: last command exited with $?=1
not ok 15 - show
#
#		(
#			cd test &&
#			git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
#			git fetch &&
#			git checkout -b ahead origin/master &&
#			echo 1 >>file &&
#			test_tick &&
#			git commit -m update file &&
#			git checkout master &&
#			git branch --track octopus origin/master &&
#			git branch --track rebase origin/master &&
#			git branch -d -r origin/master &&
#			git config --add remote.two.url ../two &&
#			git config --add remote.two.pushurl ../three &&
#			git config branch.rebase.rebase true &&
#			git config branch.octopus.merge "topic-a topic-b topic-c" &&
#			(
#				cd ../one &&
#				echo 1 >file &&
#				test_tick &&
#				git commit -m update file
#			) &&
#			git config --add remote.origin.push : &&
#			git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
#			git config --add remote.origin.push +refs/tags/lastbackup &&
#			git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
#			git config --add remote.two.push refs/heads/master:refs/heads/another &&
#			git remote show origin two >output &&
#			git branch -d rebase octopus &&
#			test_i18ncmp expect output
#		)
#
-- snap --

Could you have a look to see whether the code or the test need to be
adjusted?

Thanks,
Dscho

>
> Changes since v3:
>
>  * handle also 'git remote remove'
>
> Cc: Junio C Hamano <gitster@pobox.com>
> Cc: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/remote.c  | 22 +++++++++++++++++++++-
>  t/t5505-remote.sh | 16 +++++++++++++++-
>  2 files changed, 36 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/remote.c b/builtin/remote.c
> index 9ee44c9f6c..a2379a14bf 100644
> --- a/builtin/remote.c
> +++ b/builtin/remote.c
> @@ -250,6 +250,7 @@ struct branch_info {
>  	char *remote_name;
>  	struct string_list merge;
>  	enum rebase_type rebase;
> +	char *push_remote_name;
>  };
>
>  static struct string_list branch_list = STRING_LIST_INIT_NODUP;
> @@ -267,7 +268,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)
>  	char *name;
>  	struct string_list_item *item;
>  	struct branch_info *info;
> -	enum { REMOTE, MERGE, REBASE } type;
> +	enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
>  	size_t key_len;
>
>  	if (!starts_with(key, "branch."))
> @@ -280,6 +281,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
>  		type = MERGE;
>  	else if (strip_suffix(key, ".rebase", &key_len))
>  		type = REBASE;
> +	else if (strip_suffix(key, ".pushremote", &key_len))
> +		type = PUSH_REMOTE;
>  	else
>  		return 0;
>  	name = xmemdupz(key, key_len);
> @@ -315,6 +318,11 @@ static int config_read_branches(const char *key, const char *value, void *cb)
>  		 */
>  		info->rebase = rebase_parse_value(value);
>  		break;
> +	case PUSH_REMOTE:
> +		if (info->push_remote_name)
> +			warning(_("more than one %s"), orig_key);
> +		info->push_remote_name = xstrdup(value);
> +		break;
>  	default:
>  		BUG("unexpected type=%d", type);
>  	}
> @@ -682,6 +690,11 @@ static int mv(int argc, const char **argv)
>  			strbuf_addf(&buf, "branch.%s.remote", item->string);
>  			git_config_set(buf.buf, rename.new_name);
>  		}
> +		if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
> +			strbuf_reset(&buf);
> +			strbuf_addf(&buf, "branch.%s.pushremote", item->string);
> +			git_config_set(buf.buf, rename.new_name);
> +		}
>  	}
>
>  	if (!refspec_updated)
> @@ -783,6 +796,13 @@ static int rm(int argc, const char **argv)
>  					die(_("could not unset '%s'"), buf.buf);
>  			}
>  		}
> +		if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
> +			strbuf_reset(&buf);
> +			strbuf_addf(&buf, "branch.%s.pushremote", item->string);
> +			result = git_config_set_gently(buf.buf, NULL);
> +			if (result && result != CONFIG_NOTHING_SET)
> +				die(_("could not unset '%s'"), buf.buf);
> +		}
>  	}
>
>  	/*
> diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
> index 883b32efa0..082042b05a 100755
> --- a/t/t5505-remote.sh
> +++ b/t/t5505-remote.sh
> @@ -737,12 +737,14 @@ test_expect_success 'rename a remote' '
>  	git clone one four &&
>  	(
>  		cd four &&
> +		git config branch.master.pushRemote origin &&
>  		git remote rename origin upstream &&
>  		test -z "$(git for-each-ref refs/remotes/origin)" &&
>  		test "$(git symbolic-ref refs/remotes/upstream/HEAD)" = "refs/remotes/upstream/master" &&
>  		test "$(git rev-parse upstream/master)" = "$(git rev-parse master)" &&
>  		test "$(git config remote.upstream.fetch)" = "+refs/heads/*:refs/remotes/upstream/*" &&
> -		test "$(git config branch.master.remote)" = "upstream"
> +		test "$(git config branch.master.remote)" = "upstream" &&
> +		test "$(git config branch.master.pushRemote)" = "upstream"
>  	)
>  '
>
> @@ -784,6 +786,18 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '
>  	git -C four.four remote rename origin upstream
>  '
>
> +test_expect_success 'remove a remote' '
> +	git clone one four.five &&
> +	(
> +		cd four.five &&
> +		git config branch.master.pushRemote origin &&
> +		git remote remove origin &&
> +		test -z "$(git for-each-ref refs/remotes/origin)" &&
> +		test_must_fail git config branch.master.remote &&
> +		test_must_fail git config branch.master.pushRemote
> +	)
> +'
> +
>  cat >remotes_origin <<EOF
>  URL: $(pwd)/one
>  Push: refs/heads/master:refs/heads/upstream
> --
> 2.24.1.497.g9abd7b20b4.dirty
>
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values
  2020-01-25  0:46   ` Johannes Schindelin
@ 2020-01-25  7:29     ` Bert Wesarg
  2020-01-26  9:30       ` Johannes Schindelin
  0 siblings, 1 reply; 14+ messages in thread
From: Bert Wesarg @ 2020-01-25  7:29 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Junio C Hamano

Dear Dscho,

On 25.01.20 01:46, Johannes Schindelin wrote:
> Hi Bert,
> 
> On Fri, 24 Jan 2020, Bert Wesarg wrote:
> 
>> When renaming or removing a remote with
>>
>>      git remote rename X Y
>>      git remote remove X
>>
>> Git already renames/removes any config values from
>>
>>      branch.<name>.remote = X
>>
>> to
>>
>>      branch.<name>.remote = Y
>>
>> As branch.<name>.pushRemote also names a remote, it now also renames
>> or removes these config values from
>>
>>      branch.<name>.pushRemote = X
>>
>> to
>>
>>      branch.<name>.pushRemote = Y
>>
>> Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
>>
>> ---
> 
> This commit seems to cause a failure in t5505:
> https://dev.azure.com/gitgitgadget/git/_build/results?buildId=27833&view=ms.vss-test-web.build-test-results-tab
> 
> Here is the excerpt of the log:
> 
> -- snip --
> [...]
> expecting success of 5505.15 'show':
> 	(
> 		cd test &&
> 		git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
> 		git fetch &&
> 		git checkout -b ahead origin/master &&
> 		echo 1 >>file &&
> 		test_tick &&
> 		git commit -m update file &&
> 		git checkout master &&
> 		git branch --track octopus origin/master &&
> 		git branch --track rebase origin/master &&
> 		git branch -d -r origin/master &&
> 		git config --add remote.two.url ../two &&
> 		git config --add remote.two.pushurl ../three &&
> 		git config branch.rebase.rebase true &&
> 		git config branch.octopus.merge "topic-a topic-b topic-c" &&
> 		(
> 			cd ../one &&
> 			echo 1 >file &&
> 			test_tick &&
> 			git commit -m update file
> 		) &&
> 		git config --add remote.origin.push : &&
> 		git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
> 		git config --add remote.origin.push +refs/tags/lastbackup &&
> 		git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
> 		git config --add remote.two.push refs/heads/master:refs/heads/another &&
> 		git remote show origin two >output &&
> 		git branch -d rebase octopus &&
> 		test_i18ncmp expect output
> 	)
> 
> + cd test
> + git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream
> + git fetch
>  From /home/virtualbox/git/t/trash directory.t5505-remote/one
>   * [new branch]      master     -> upstream
> + git checkout -b ahead origin/master
> Switched to a new branch 'ahead'
> Branch 'ahead' set up to track remote branch 'master' from 'origin'.
> + echo 1
> + test_tick
> + test -z
> + test_tick=1112911993
> + GIT_COMMITTER_DATE=1112911993 -0700
> + GIT_AUTHOR_DATE=1112911993 -0700
> + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
> + git commit -m update file
> [ahead 847549e] update
>   Author: A U Thor <author@example.com>
>   1 file changed, 1 insertion(+)
> + git checkout master
> Switched to branch 'master'
> Your branch is up to date with 'origin/master'.
> + git branch --track octopus origin/master
> Branch 'octopus' set up to track remote branch 'master' from 'origin'.
> + git branch --track rebase origin/master
> Branch 'rebase' set up to track remote branch 'master' from 'origin'.
> + git branch -d -r origin/master
> Deleted remote-tracking branch origin/master (was 9d34b14).
> + git config --add remote.two.url ../two
> + git config --add remote.two.pushurl ../three
> + git config branch.rebase.rebase true
> + git config branch.octopus.merge topic-a topic-b topic-c
> + cd ../one
> + echo 1
> + test_tick
> + test -z set
> + test_tick=1112912053
> + GIT_COMMITTER_DATE=1112912053 -0700
> + GIT_AUTHOR_DATE=1112912053 -0700
> + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
> + git commit -m update file
> [master 6329a3c] update
>   Author: A U Thor <author@example.com>
>   1 file changed, 1 insertion(+)
> + git config --add remote.origin.push :
> + git config --add remote.origin.push refs/heads/master:refs/heads/upstream
> + git config --add remote.origin.push +refs/tags/lastbackup
> + git config --add remote.two.push +refs/heads/ahead:refs/heads/master
> + git config --add remote.two.push refs/heads/master:refs/heads/another
> + git remote show origin two
> error: src refspec refs/tags/lastbackup does not match any
> + git branch -d rebase octopus
> Deleted branch rebase (was 9d34b14).
> Deleted branch octopus (was 9d34b14).
> + test_i18ncmp expect output
> + test_have_prereq C_LOCALE_OUTPUT
> + save_IFS=
> 
> + IFS=,
> + set -- C_LOCALE_OUTPUT
> + IFS=
> 
> + total_prereq=0
> + ok_prereq=0
> + missing_prereq=
> + negative_prereq=
> + total_prereq=1
> + satisfied_this_prereq=t
> + ok_prereq=1
> + test 1 = 1
> + test_cmp expect output
> + diff -u expect output
> --- expect	2020-01-25 00:44:41.496720000 +0000
> +++ output	2020-01-25 00:44:43.513861900 +0000
> @@ -5,13 +5,6 @@
>     Remote branches:
>       master new (next fetch will store in remotes/origin)
>       side   tracked
> -  Local branches configured for 'git pull':
> -    ahead    merges with remote master
> -    master   merges with remote master
> -    octopus  merges with remote topic-a
> -                and with remote topic-b
> -                and with remote topic-c
> -    rebase  rebases onto remote master
>     Local refs configured for 'git push':
>       master pushes to master   (local out of date)
>       master pushes to upstream (create)
> error: last command exited with $?=1
> not ok 15 - show
> #
> #		(
> #			cd test &&
> #			git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&
> #			git fetch &&
> #			git checkout -b ahead origin/master &&
> #			echo 1 >>file &&
> #			test_tick &&
> #			git commit -m update file &&
> #			git checkout master &&
> #			git branch --track octopus origin/master &&
> #			git branch --track rebase origin/master &&
> #			git branch -d -r origin/master &&
> #			git config --add remote.two.url ../two &&
> #			git config --add remote.two.pushurl ../three &&
> #			git config branch.rebase.rebase true &&
> #			git config branch.octopus.merge "topic-a topic-b topic-c" &&
> #			(
> #				cd ../one &&
> #				echo 1 >file &&
> #				test_tick &&
> #				git commit -m update file
> #			) &&
> #			git config --add remote.origin.push : &&
> #			git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&
> #			git config --add remote.origin.push +refs/tags/lastbackup &&
> #			git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&
> #			git config --add remote.two.push refs/heads/master:refs/heads/another &&
> #			git remote show origin two >output &&
> #			git branch -d rebase octopus &&
> #			test_i18ncmp expect output
> #		)
> #
> -- snap --
> 
> Could you have a look to see whether the code or the test need to be
> adjusted?

please ensure that you have v4 of this patch. What you see was a bug in v3.

Thanks.

Bert

> 
> Thanks,
> Dscho
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values
  2020-01-25  7:29     ` Bert Wesarg
@ 2020-01-26  9:30       ` Johannes Schindelin
  0 siblings, 0 replies; 14+ messages in thread
From: Johannes Schindelin @ 2020-01-26  9:30 UTC (permalink / raw)
  To: Bert Wesarg; +Cc: git, Junio C Hamano

Hi Bert,

On Sat, 25 Jan 2020, Bert Wesarg wrote:

> On 25.01.20 01:46, Johannes Schindelin wrote:
> > Hi Bert,
> >
> > On Fri, 24 Jan 2020, Bert Wesarg wrote:
> >
> > > When renaming or removing a remote with
> > >
> > >      git remote rename X Y
> > >      git remote remove X
> > >
> > > Git already renames/removes any config values from
> > >
> > >      branch.<name>.remote = X
> > >
> > > to
> > >
> > >      branch.<name>.remote = Y
> > >
> > > As branch.<name>.pushRemote also names a remote, it now also renames
> > > or removes these config values from
> > >
> > >      branch.<name>.pushRemote = X
> > >
> > > to
> > >
> > >      branch.<name>.pushRemote = Y
> > >
> > > Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
> > >
> > > ---
> >
> > This commit seems to cause a failure in t5505:
> > https://dev.azure.com/gitgitgadget/git/_build/results?buildId=27833&view=ms.vss-test-web.build-test-results-tab
> >
> > Here is the excerpt of the log:
> >
> > [...]
> >
> > Could you have a look to see whether the code or the test need to be
> > adjusted?
>
> please ensure that you have v4 of this patch. What you see was a bug in v3.

I was talking about the current state of what was merged into `pu`:
https://github.com/gitgitgadget/git/commit/6f032056fd7534b8efd712994c02531d83ada957
(note the red X indicating the build failure).

If you already fixed this, and Junio merely has to pick it up, all the
better.

Thanks,
Dscho

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 0/7] remote rename/remove: improve handling of configuration values
  2020-01-25  0:39   ` Matt Rogers
@ 2020-01-27  6:50     ` Bert Wesarg
  0 siblings, 0 replies; 14+ messages in thread
From: Bert Wesarg @ 2020-01-27  6:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List, Matt Rogers

Junio,

On Sat, Jan 25, 2020 at 1:39 AM Matt Rogers <mattr94@gmail.com> wrote:
>
> Yeah, I just resubmitted so you should be good to go

I can resend the rebased topic at any time. And as I don't see that
you picked up by latest re-roll (cover in
cover.1579857394.git.bert.wesarg@googlemail.com) in into
bw/remote-rename-update-config yet, I think it makes sense to do this
now.

Best,
Bert

>
> On Fri, Jan 24, 2020 at 4:10 PM Junio C Hamano <gitster@pobox.com> wrote:
> >
> > All steps looked quite sensibly done.
> >
> > >  - patch 5 will be replaced by/rebased on Matthew's work in 'config: allow user to
> > >    know scope of config options', once 'config_scope_name' is available
> >
> > I expect that Matthew's topic would become solid enough after one
> > more reroll to name the function back to config_scope_name(); after
> > that, let's drop the step and instead fork this topic off of Matthew's
> > topic to queue the remaining patches on top.
> >
> > Thanks.
>
>
>
> --
> Matthew Rogers

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, back to index

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-24  9:25 [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Bert Wesarg
2020-01-24  9:25 ` [PATCH v2 1/7] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types Bert Wesarg
2020-01-24  9:25 ` [PATCH v2 2/7] remote: clean-up by returning early to avoid one indentation Bert Wesarg
2020-01-24  9:25 ` [PATCH 3/7] remote: clean-up config callback Bert Wesarg
2020-01-24  9:25 ` [PATCH v4 4/7] remote rename/remove: handle branch.<name>.pushRemote config values Bert Wesarg
2020-01-25  0:46   ` Johannes Schindelin
2020-01-25  7:29     ` Bert Wesarg
2020-01-26  9:30       ` Johannes Schindelin
2020-01-24  9:25 ` [RFC PATCH 5/7] config: make `scope_name` global as `config_scope_name` Bert Wesarg
2020-01-24  9:25 ` [PATCH 6/7] config: provide access to the current line number Bert Wesarg
2020-01-24  9:25 ` [PATCH v2 7/7] remote rename/remove: gently handle remote.pushDefault config Bert Wesarg
2020-01-24 21:00 ` [PATCH v2 0/7] remote rename/remove: improve handling of configuration values Junio C Hamano
2020-01-25  0:39   ` Matt Rogers
2020-01-27  6:50     ` Bert Wesarg

git@vger.kernel.org list mirror (unofficial, one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Example config snippet for mirrors

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git