{"thread":{"id":"52701","subject":"[PATCH v3 0/7] remote rename/remove: improve handling of configuration values","startedAt":"2020-01-27T07:04:37Z","lastAt":"2020-01-29T09:16:33Z","messageCount":10,"participants":["Bert Wesarg","Junio C Hamano"],"isPatch":true,"patchVersion":3,"patchTotal":7},"messages":[{"id":"390537","messageId":"cover.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":null,"subject":"[PATCH v3 0/7] remote rename/remove: improve handling of configuration values","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:26Z","receivedAt":"2020-01-27T07:04:37Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"While fixing that 'git remote rename X Y' does not rename the values for\n'branch.*.pushRemote', it opened the possibility to more improvements in\nthis area:\n\n - 'remote rename' did not accept single-letter abbreviations for\n   'branch.*.rebase' like 'pull --rebase' does\n\n - minor clean-ups the config callback\n\n - patch 5 will be replaced by/rebased on Matthew's work in 'config: allow user to\n   know scope of config options', once 'config_scope_name' is available\n\n - gently handling the rename of 'remote.pushDefault'\n\nChanges since v3:\n * rebasd onto mr/show-config-scope (feaf5eea41)\n\nChanges since v1:\n * avoid mixed declarations and statements\n * 'git remote remove' learned similar treatment\n\nBert Wesarg (6):\n  pull --rebase/remote rename: document and honor single-letter\n    abbreviations rebase types\n  remote: clean-up by returning early to avoid one indentation\n  remote: clean-up config callback\n  remote rename/remove: handle branch.<name>.pushRemote config values\n  config: provide access to the current line number\n  remote rename/remove: gently handle remote.pushDefault config\n\n Documentation/config/branch.txt |   7 +-\n Documentation/config/pull.txt   |   7 +-\n Makefile                        |   1 +\n builtin/pull.c                  |  29 +----\n builtin/remote.c                | 188 ++++++++++++++++++++++----------\n config.c                        |   8 ++\n config.h                        |   1 +\n rebase.c                        |  35 ++++++\n rebase.h                        |  15 +++\n t/helper/test-config.c          |   1 +\n t/t1308-config-set.sh           |  14 ++-\n t/t5505-remote.sh               |  88 ++++++++++++++-\n 12 files changed, 304 insertions(+), 90 deletions(-)\n create mode 100644 rebase.c\n create mode 100644 rebase.h\n\n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390538","messageId":"aab595b55abedb9cc519a587dfd75477a8afd363.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH v2 2/6] remote: clean-up by returning early to avoid one indentation","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:28Z","receivedAt":"2020-01-27T07:04:40Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n\n---\nCc: Junio C Hamano <gitster@pobox.com>\n\nChanges since v1:\n * avoid mixed declarations and code statements\n---\n builtin/remote.c | 94 ++++++++++++++++++++++++------------------------\n 1 file changed, 48 insertions(+), 46 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 6802765e73..4cf929bfc6 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -263,54 +263,56 @@ static const char *abbrev_ref(const char *name, const char *prefix)\n \n static int config_read_branches(const char *key, const char *value, void *cb)\n {\n-\tif (starts_with(key, \"branch.\")) {\n-\t\tconst char *orig_key = key;\n-\t\tchar *name;\n-\t\tstruct string_list_item *item;\n-\t\tstruct branch_info *info;\n-\t\tenum { REMOTE, MERGE, REBASE } type;\n-\t\tsize_t key_len;\n-\n-\t\tkey += 7;\n-\t\tif (strip_suffix(key, \".remote\", &key_len)) {\n-\t\t\tname = xmemdupz(key, key_len);\n-\t\t\ttype = REMOTE;\n-\t\t} else if (strip_suffix(key, \".merge\", &key_len)) {\n-\t\t\tname = xmemdupz(key, key_len);\n-\t\t\ttype = MERGE;\n-\t\t} else if (strip_suffix(key, \".rebase\", &key_len)) {\n-\t\t\tname = xmemdupz(key, key_len);\n-\t\t\ttype = REBASE;\n-\t\t} else\n-\t\t\treturn 0;\n+\tconst char *orig_key = key;\n+\tchar *name;\n+\tstruct string_list_item *item;\n+\tstruct branch_info *info;\n+\tenum { REMOTE, MERGE, REBASE } type;\n+\tsize_t key_len;\n \n-\t\titem = string_list_insert(&branch_list, name);\n+\tif (!starts_with(key, \"branch.\"))\n+\t\treturn 0;\n+\n+\tkey += 7;\n+\tif (strip_suffix(key, \".remote\", &key_len)) {\n+\t\tname = xmemdupz(key, key_len);\n+\t\ttype = REMOTE;\n+\t} else if (strip_suffix(key, \".merge\", &key_len)) {\n+\t\tname = xmemdupz(key, key_len);\n+\t\ttype = MERGE;\n+\t} else if (strip_suffix(key, \".rebase\", &key_len)) {\n+\t\tname = xmemdupz(key, key_len);\n+\t\ttype = REBASE;\n+\t} else\n+\t\treturn 0;\n+\n+\titem = string_list_insert(&branch_list, name);\n+\n+\tif (!item->util)\n+\t\titem->util = xcalloc(1, sizeof(struct branch_info));\n+\tinfo = item->util;\n+\tif (type == REMOTE) {\n+\t\tif (info->remote_name)\n+\t\t\twarning(_(\"more than one %s\"), orig_key);\n+\t\tinfo->remote_name = xstrdup(value);\n+\t} else if (type == MERGE) {\n+\t\tchar *space = strchr(value, ' ');\n+\t\tvalue = abbrev_branch(value);\n+\t\twhile (space) {\n+\t\t\tchar *merge;\n+\t\t\tmerge = xstrndup(value, space - value);\n+\t\t\tstring_list_append(&info->merge, merge);\n+\t\t\tvalue = abbrev_branch(space + 1);\n+\t\t\tspace = strchr(value, ' ');\n+\t\t}\n+\t\tstring_list_append(&info->merge, xstrdup(value));\n+\t} else\n+\t\t/*\n+\t\t * Consider invalid values as false and check the\n+\t\t * truth value with >= REBASE_TRUE.\n+\t\t */\n+\t\tinfo->rebase = rebase_parse_value(value);\n \n-\t\tif (!item->util)\n-\t\t\titem->util = xcalloc(1, sizeof(struct branch_info));\n-\t\tinfo = item->util;\n-\t\tif (type == REMOTE) {\n-\t\t\tif (info->remote_name)\n-\t\t\t\twarning(_(\"more than one %s\"), orig_key);\n-\t\t\tinfo->remote_name = xstrdup(value);\n-\t\t} else if (type == MERGE) {\n-\t\t\tchar *space = strchr(value, ' ');\n-\t\t\tvalue = abbrev_branch(value);\n-\t\t\twhile (space) {\n-\t\t\t\tchar *merge;\n-\t\t\t\tmerge = xstrndup(value, space - value);\n-\t\t\t\tstring_list_append(&info->merge, merge);\n-\t\t\t\tvalue = abbrev_branch(space + 1);\n-\t\t\t\tspace = strchr(value, ' ');\n-\t\t\t}\n-\t\t\tstring_list_append(&info->merge, xstrdup(value));\n-\t\t} else\n-\t\t\t/*\n-\t\t\t * Consider invalid values as false and check the\n-\t\t\t * truth value with >= REBASE_TRUE.\n-\t\t\t */\n-\t\t\tinfo->rebase = rebase_parse_value(value);\n-\t}\n \treturn 0;\n }\n \n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390539","messageId":"1bf42c00536b47d1e120fff9a7dc026c445ae3a9.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH 1/6] pull --rebase/remote rename: document and honor single-letter abbreviations rebase types","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:27Z","receivedAt":"2020-01-27T07:04:40Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"When 46af44b07d (pull --rebase=<type>: allow single-letter abbreviations\nfor the type, 2018-08-04) landed in Git, it had the side effect that\nnot only 'pull --rebase=<type>' accepted the single-letter abbreviations\nbut also the 'pull.rebase' and 'branch.<name>.rebase' configurations.\n\nHowever, 'git remote rename' did not honor these single-letter\nabbreviations when reading the 'branch.*.rebase' configurations.\n\nWe now document the single-letter abbreviations and both code places\nshare a common function to parse the values of 'git pull --rebase=*',\n'pull.rebase', and 'branches.*.rebase'.\n\nThe only functional change is the handling of the `branch_info::rebase`\nvalue. Before it was an unsigned enum, thus the truth value could be\nchecked with `branch_info::rebase != 0`. But `enum rebase_type` is\nsigned, thus the truth value must now be checked with\n`branch_info::rebase >= REBASE_TRUE`\n\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n\n---\nCc: Johannes Schindelin <Johannes.Schindelin@gmx.de>\nCc: Junio C Hamano <gitster@pobox.com>\n\nchanges since v1:\n * Add comment that 'git remote rename' considers unknown `.rebase' values\n   as false\n---\n Documentation/config/branch.txt |  7 ++++---\n Documentation/config/pull.txt   |  7 ++++---\n Makefile                        |  1 +\n builtin/pull.c                  | 29 ++++-----------------------\n builtin/remote.c                | 30 +++++++++++-----------------\n rebase.c                        | 35 +++++++++++++++++++++++++++++++++\n rebase.h                        | 15 ++++++++++++++\n 7 files changed, 75 insertions(+), 49 deletions(-)\n create mode 100644 rebase.c\n create mode 100644 rebase.h\n\ndiff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt\nindex a592d522a7..cc5f3249fc 100644\n--- a/Documentation/config/branch.txt\n+++ b/Documentation/config/branch.txt\n@@ -81,15 +81,16 @@ branch.<name>.rebase::\n \t\"git pull\" is run. See \"pull.rebase\" for doing this in a non\n \tbranch-specific manner.\n +\n-When `merges`, pass the `--rebase-merges` option to 'git rebase'\n+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n so that the local merge commits are included in the rebase (see\n linkgit:git-rebase[1] for details).\n +\n-When `preserve` (deprecated in favor of `merges`), also pass\n+When `preserve` (or just 'p', deprecated in favor of `merges`), also pass\n `--preserve-merges` along to 'git rebase' so that locally committed merge\n commits will not be flattened by running 'git pull'.\n +\n-When the value is `interactive`, the rebase is run in interactive mode.\n+When the value is `interactive` (or just 'i'), the rebase is run in interactive\n+mode.\n +\n *NOTE*: this is a possibly dangerous operation; do *not* use\n it unless you understand the implications (see linkgit:git-rebase[1]\ndiff --git a/Documentation/config/pull.txt b/Documentation/config/pull.txt\nindex b87cab31b3..5404830609 100644\n--- a/Documentation/config/pull.txt\n+++ b/Documentation/config/pull.txt\n@@ -14,15 +14,16 @@ pull.rebase::\n \tpull\" is run. See \"branch.<name>.rebase\" for setting this on a\n \tper-branch basis.\n +\n-When `merges`, pass the `--rebase-merges` option to 'git rebase'\n+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'\n so that the local merge commits are included in the rebase (see\n linkgit:git-rebase[1] for details).\n +\n-When `preserve` (deprecated in favor of `merges`), also pass\n+When `preserve` (or just 'p', deprecated in favor of `merges`), also pass\n `--preserve-merges` along to 'git rebase' so that locally committed merge\n commits will not be flattened by running 'git pull'.\n +\n-When the value is `interactive`, the rebase is run in interactive mode.\n+When the value is `interactive` (or just 'i'), the rebase is run in interactive\n+mode.\n +\n *NOTE*: this is a possibly dangerous operation; do *not* use\n it unless you understand the implications (see linkgit:git-rebase[1]\ndiff --git a/Makefile b/Makefile\nindex 09f98b777c..96ced97bff 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -954,6 +954,7 @@ LIB_OBJS += quote.o\n LIB_OBJS += range-diff.o\n LIB_OBJS += reachable.o\n LIB_OBJS += read-cache.o\n+LIB_OBJS += rebase.o\n LIB_OBJS += rebase-interactive.o\n LIB_OBJS += reflog-walk.o\n LIB_OBJS += refs.o\ndiff --git a/builtin/pull.c b/builtin/pull.c\nindex d25ff13a60..888181c07c 100644\n--- a/builtin/pull.c\n+++ b/builtin/pull.c\n@@ -15,6 +15,7 @@\n #include \"sha1-array.h\"\n #include \"remote.h\"\n #include \"dir.h\"\n+#include \"rebase.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"revision.h\"\n@@ -26,15 +27,6 @@\n #include \"commit-reach.h\"\n #include \"sequencer.h\"\n \n-enum rebase_type {\n-\tREBASE_INVALID = -1,\n-\tREBASE_FALSE = 0,\n-\tREBASE_TRUE,\n-\tREBASE_PRESERVE,\n-\tREBASE_MERGES,\n-\tREBASE_INTERACTIVE\n-};\n-\n /**\n  * Parses the value of --rebase. If value is a false value, returns\n  * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is\n@@ -45,22 +37,9 @@ enum rebase_type {\n static enum rebase_type parse_config_rebase(const char *key, const char *value,\n \t\tint fatal)\n {\n-\tint v = git_parse_maybe_bool(value);\n-\n-\tif (!v)\n-\t\treturn REBASE_FALSE;\n-\telse if (v > 0)\n-\t\treturn REBASE_TRUE;\n-\telse if (!strcmp(value, \"preserve\") || !strcmp(value, \"p\"))\n-\t\treturn REBASE_PRESERVE;\n-\telse if (!strcmp(value, \"merges\") || !strcmp(value, \"m\"))\n-\t\treturn REBASE_MERGES;\n-\telse if (!strcmp(value, \"interactive\") || !strcmp(value, \"i\"))\n-\t\treturn REBASE_INTERACTIVE;\n-\t/*\n-\t * Please update _git_config() in git-completion.bash when you\n-\t * add new rebase modes.\n-\t */\n+\tenum rebase_type v = rebase_parse_value(value);\n+\tif (v != REBASE_INVALID)\n+\t\treturn v;\n \n \tif (fatal)\n \t\tdie(_(\"Invalid value for %s: %s\"), key, value);\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 96bbe828fe..6802765e73 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -6,6 +6,7 @@\n #include \"string-list.h\"\n #include \"strbuf.h\"\n #include \"run-command.h\"\n+#include \"rebase.h\"\n #include \"refs.h\"\n #include \"refspec.h\"\n #include \"object-store.h\"\n@@ -248,9 +249,7 @@ static int add(int argc, const char **argv)\n struct branch_info {\n \tchar *remote_name;\n \tstruct string_list merge;\n-\tenum {\n-\t\tNO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE, REBASE_MERGES\n-\t} rebase;\n+\tenum rebase_type rebase;\n };\n \n static struct string_list branch_list = STRING_LIST_INIT_NODUP;\n@@ -305,17 +304,12 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t\t\tspace = strchr(value, ' ');\n \t\t\t}\n \t\t\tstring_list_append(&info->merge, xstrdup(value));\n-\t\t} else {\n-\t\t\tint v = git_parse_maybe_bool(value);\n-\t\t\tif (v >= 0)\n-\t\t\t\tinfo->rebase = v;\n-\t\t\telse if (!strcmp(value, \"preserve\"))\n-\t\t\t\tinfo->rebase = NORMAL_REBASE;\n-\t\t\telse if (!strcmp(value, \"merges\"))\n-\t\t\t\tinfo->rebase = REBASE_MERGES;\n-\t\t\telse if (!strcmp(value, \"interactive\"))\n-\t\t\t\tinfo->rebase = INTERACTIVE_REBASE;\n-\t\t}\n+\t\t} else\n+\t\t\t/*\n+\t\t\t * Consider invalid values as false and check the\n+\t\t\t * truth value with >= REBASE_TRUE.\n+\t\t\t */\n+\t\t\tinfo->rebase = rebase_parse_value(value);\n \t}\n \treturn 0;\n }\n@@ -943,7 +937,7 @@ static int add_local_to_show_info(struct string_list_item *branch_item, void *cb\n \t\treturn 0;\n \tif ((n = strlen(branch_item->string)) > show_info->width)\n \t\tshow_info->width = n;\n-\tif (branch_info->rebase)\n+\tif (branch_info->rebase >= REBASE_TRUE)\n \t\tshow_info->any_rebase = 1;\n \n \titem = string_list_insert(show_info->list, branch_item->string);\n@@ -960,16 +954,16 @@ static int show_local_info_item(struct string_list_item *item, void *cb_data)\n \tint width = show_info->width + 4;\n \tint i;\n \n-\tif (branch_info->rebase && branch_info->merge.nr > 1) {\n+\tif (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {\n \t\terror(_(\"invalid branch.%s.merge; cannot rebase onto > 1 branch\"),\n \t\t\titem->string);\n \t\treturn 0;\n \t}\n \n \tprintf(\"    %-*s \", show_info->width, item->string);\n-\tif (branch_info->rebase) {\n+\tif (branch_info->rebase >= REBASE_TRUE) {\n \t\tconst char *msg;\n-\t\tif (branch_info->rebase == INTERACTIVE_REBASE)\n+\t\tif (branch_info->rebase == REBASE_INTERACTIVE)\n \t\t\tmsg = _(\"rebases interactively onto remote %s\");\n \t\telse if (branch_info->rebase == REBASE_MERGES)\n \t\t\tmsg = _(\"rebases interactively (with merges) onto \"\ndiff --git a/rebase.c b/rebase.c\nnew file mode 100644\nindex 0000000000..f8137d859b\n--- /dev/null\n+++ b/rebase.c\n@@ -0,0 +1,35 @@\n+#include \"rebase.h\"\n+#include \"config.h\"\n+\n+/*\n+ * Parses textual value for pull.rebase, branch.<name>.rebase, etc.\n+ * Unrecognised value yields REBASE_INVALID, which traditionally is\n+ * treated the same way as REBASE_FALSE.\n+ *\n+ * The callers that care if (any) rebase is requested should say\n+ *   if (REBASE_TRUE <= rebase_parse_value(string))\n+ *\n+ * The callers that want to differenciate an unrecognised value and\n+ * false can do so by treating _INVALID and _FALSE differently.\n+ */\n+enum rebase_type rebase_parse_value(const char *value)\n+{\n+\tint v = git_parse_maybe_bool(value);\n+\n+\tif (!v)\n+\t\treturn REBASE_FALSE;\n+\telse if (v > 0)\n+\t\treturn REBASE_TRUE;\n+\telse if (!strcmp(value, \"preserve\") || !strcmp(value, \"p\"))\n+\t\treturn REBASE_PRESERVE;\n+\telse if (!strcmp(value, \"merges\") || !strcmp(value, \"m\"))\n+\t\treturn REBASE_MERGES;\n+\telse if (!strcmp(value, \"interactive\") || !strcmp(value, \"i\"))\n+\t\treturn REBASE_INTERACTIVE;\n+\t/*\n+\t * Please update _git_config() in git-completion.bash when you\n+\t * add new rebase modes.\n+\t */\n+\n+\treturn REBASE_INVALID;\n+}\ndiff --git a/rebase.h b/rebase.h\nnew file mode 100644\nindex 0000000000..cc723d4748\n--- /dev/null\n+++ b/rebase.h\n@@ -0,0 +1,15 @@\n+#ifndef REBASE_H\n+#define REBASE_H\n+\n+enum rebase_type {\n+\tREBASE_INVALID = -1,\n+\tREBASE_FALSE = 0,\n+\tREBASE_TRUE,\n+\tREBASE_PRESERVE,\n+\tREBASE_MERGES,\n+\tREBASE_INTERACTIVE\n+};\n+\n+enum rebase_type rebase_parse_value(const char *value);\n+\n+#endif /* REBASE */\n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390540","messageId":"e2c36ae2cd5770031160e0736072ee3d8d1577c9.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH 3/6] remote: clean-up config callback","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:29Z","receivedAt":"2020-01-27T07:04:42Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"Some minor clean-ups in function `config_read_branches`:\n\n * remove hardcoded length in `key += 7`\n * call `xmemdupz` only once\n * use a switch to handle the configuration type and add a `BUG()`\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n\n---\nCc: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/remote.c | 28 +++++++++++++++++-----------\n 1 file changed, 17 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 4cf929bfc6..9ee44c9f6c 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -273,29 +273,29 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \tif (!starts_with(key, \"branch.\"))\n \t\treturn 0;\n \n-\tkey += 7;\n-\tif (strip_suffix(key, \".remote\", &key_len)) {\n-\t\tname = xmemdupz(key, key_len);\n+\tkey += strlen(\"branch.\");\n+\tif (strip_suffix(key, \".remote\", &key_len))\n \t\ttype = REMOTE;\n-\t} else if (strip_suffix(key, \".merge\", &key_len)) {\n-\t\tname = xmemdupz(key, key_len);\n+\telse if (strip_suffix(key, \".merge\", &key_len))\n \t\ttype = MERGE;\n-\t} else if (strip_suffix(key, \".rebase\", &key_len)) {\n-\t\tname = xmemdupz(key, key_len);\n+\telse if (strip_suffix(key, \".rebase\", &key_len))\n \t\ttype = REBASE;\n-\t} else\n+\telse\n \t\treturn 0;\n+\tname = xmemdupz(key, key_len);\n \n \titem = string_list_insert(&branch_list, name);\n \n \tif (!item->util)\n \t\titem->util = xcalloc(1, sizeof(struct branch_info));\n \tinfo = item->util;\n-\tif (type == REMOTE) {\n+\tswitch (type) {\n+\tcase REMOTE:\n \t\tif (info->remote_name)\n \t\t\twarning(_(\"more than one %s\"), orig_key);\n \t\tinfo->remote_name = xstrdup(value);\n-\t} else if (type == MERGE) {\n+\t\tbreak;\n+\tcase MERGE: {\n \t\tchar *space = strchr(value, ' ');\n \t\tvalue = abbrev_branch(value);\n \t\twhile (space) {\n@@ -306,12 +306,18 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t\tspace = strchr(value, ' ');\n \t\t}\n \t\tstring_list_append(&info->merge, xstrdup(value));\n-\t} else\n+\t\tbreak;\n+\t}\n+\tcase REBASE:\n \t\t/*\n \t\t * Consider invalid values as false and check the\n \t\t * truth value with >= REBASE_TRUE.\n \t\t */\n \t\tinfo->rebase = rebase_parse_value(value);\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unexpected type=%d\", type);\n+\t}\n \n \treturn 0;\n }\n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390541","messageId":"d4b981673d64a958a1298ce87219a0f65605c4d1.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH 5/6] config: provide access to the current line number","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:31Z","receivedAt":"2020-01-27T07:04:44Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"Users are nowadays trained to see message from CLI tools in the form\n\n    <file>:<lno>: …\n\nTo be able to give such messages when notifying the user about\nconfigurations in any config file, it is currently only possible to get\nthe file name (if the value originates from a file to begin with) via\n`current_config_name()`. Now it is also possible to query the current line\nnumber for the configuration.\n\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n---\n config.c               |  8 ++++++++\n config.h               |  1 +\n t/helper/test-config.c |  1 +\n t/t1308-config-set.sh  | 14 ++++++++++++--\n 4 files changed, 22 insertions(+), 2 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 18a6bdd9ff..222e49a7c8 100644\n--- a/config.c\n+++ b/config.c\n@@ -3338,6 +3338,14 @@ enum config_scope current_config_scope(void)\n \t\treturn current_parsing_scope;\n }\n \n+int current_config_line(void)\n+{\n+\tif (current_config_kvi)\n+\t\treturn current_config_kvi->linenr;\n+\telse\n+\t\treturn cf->linenr;\n+}\n+\n int lookup_config(const char **mapping, int nr_mapping, const char *var)\n {\n \tint i;\ndiff --git a/config.h b/config.h\nindex fe0addb0dc..9b3773f778 100644\n--- a/config.h\n+++ b/config.h\n@@ -309,6 +309,7 @@ int git_config_parse_parameter(const char *, config_fn_t fn, void *data);\n enum config_scope current_config_scope(void);\n const char *current_config_origin_type(void);\n const char *current_config_name(void);\n+int current_config_line(void);\n \n /**\n  * Include Directives\ndiff --git a/t/helper/test-config.c b/t/helper/test-config.c\nindex 1e3bc7c8f4..234c722b48 100644\n--- a/t/helper/test-config.c\n+++ b/t/helper/test-config.c\n@@ -48,6 +48,7 @@ static int iterate_cb(const char *var, const char *value, void *data)\n \tprintf(\"value=%s\\n\", value ? value : \"(null)\");\n \tprintf(\"origin=%s\\n\", current_config_origin_type());\n \tprintf(\"name=%s\\n\", current_config_name());\n+\tprintf(\"lno=%d\\n\", current_config_line());\n \tprintf(\"scope=%s\\n\", config_scope_name(current_config_scope()));\n \n \treturn 0;\ndiff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh\nindex fba0abe429..3a527e3a84 100755\n--- a/t/t1308-config-set.sh\n+++ b/t/t1308-config-set.sh\n@@ -238,8 +238,8 @@ test_expect_success 'error on modifying repo config without repo' '\n \n cmdline_config=\"'foo.bar=from-cmdline'\"\n test_expect_success 'iteration shows correct origins' '\n-\techo \"[foo]bar = from-repo\" >.git/config &&\n-\techo \"[foo]bar = from-home\" >.gitconfig &&\n+\tprintf \"[ignore]\\n\\tthis = please\\n[foo]bar = from-repo\\n\" >.git/config &&\n+\tprintf \"[foo]\\n\\tbar = from-home\\n\" >.gitconfig &&\n \tif test_have_prereq MINGW\n \tthen\n \t\t# Use Windows path (i.e. *not* $HOME)\n@@ -253,18 +253,28 @@ test_expect_success 'iteration shows correct origins' '\n \tvalue=from-home\n \torigin=file\n \tname=$HOME_GITCONFIG\n+\tlno=2\n \tscope=global\n \n+\tkey=ignore.this\n+\tvalue=please\n+\torigin=file\n+\tname=.git/config\n+\tlno=2\n+\tscope=local\n+\n \tkey=foo.bar\n \tvalue=from-repo\n \torigin=file\n \tname=.git/config\n+\tlno=3\n \tscope=local\n \n \tkey=foo.bar\n \tvalue=from-cmdline\n \torigin=command line\n \tname=\n+\tlno=-1\n \tscope=command\n \tEOF\n \tGIT_CONFIG_PARAMETERS=$cmdline_config test-tool config iterate >actual &&\n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390542","messageId":"9e1883c14e8ada27394d83b164d9dab5d8a9c61f.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH v4 4/6] remote rename/remove: handle branch.<name>.pushRemote config values","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:30Z","receivedAt":"2020-01-27T07:04:44Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"When renaming or removing a remote with\n\n    git remote rename X Y\n    git remote remove X\n\nGit already renames/removes any config values from\n\n    branch.<name>.remote = X\n\nto\n\n    branch.<name>.remote = Y\n\nAs branch.<name>.pushRemote also names a remote, it now also renames\nor removes these config values from\n\n    branch.<name>.pushRemote = X\n\nto\n\n    branch.<name>.pushRemote = Y\n\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n\n---\n\nChanges since v3:\n\n * handle also 'git remote remove'\n\nCc: Junio C Hamano <gitster@pobox.com>\nCc: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/remote.c  | 22 +++++++++++++++++++++-\n t/t5505-remote.sh | 16 +++++++++++++++-\n 2 files changed, 36 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex 9ee44c9f6c..a2379a14bf 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -250,6 +250,7 @@ struct branch_info {\n \tchar *remote_name;\n \tstruct string_list merge;\n \tenum rebase_type rebase;\n+\tchar *push_remote_name;\n };\n \n static struct string_list branch_list = STRING_LIST_INIT_NODUP;\n@@ -267,7 +268,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \tchar *name;\n \tstruct string_list_item *item;\n \tstruct branch_info *info;\n-\tenum { REMOTE, MERGE, REBASE } type;\n+\tenum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;\n \tsize_t key_len;\n \n \tif (!starts_with(key, \"branch.\"))\n@@ -280,6 +281,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\ttype = MERGE;\n \telse if (strip_suffix(key, \".rebase\", &key_len))\n \t\ttype = REBASE;\n+\telse if (strip_suffix(key, \".pushremote\", &key_len))\n+\t\ttype = PUSH_REMOTE;\n \telse\n \t\treturn 0;\n \tname = xmemdupz(key, key_len);\n@@ -315,6 +318,11 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t */\n \t\tinfo->rebase = rebase_parse_value(value);\n \t\tbreak;\n+\tcase PUSH_REMOTE:\n+\t\tif (info->push_remote_name)\n+\t\t\twarning(_(\"more than one %s\"), orig_key);\n+\t\tinfo->push_remote_name = xstrdup(value);\n+\t\tbreak;\n \tdefault:\n \t\tBUG(\"unexpected type=%d\", type);\n \t}\n@@ -682,6 +690,11 @@ static int mv(int argc, const char **argv)\n \t\t\tstrbuf_addf(&buf, \"branch.%s.remote\", item->string);\n \t\t\tgit_config_set(buf.buf, rename.new_name);\n \t\t}\n+\t\tif (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_addf(&buf, \"branch.%s.pushremote\", item->string);\n+\t\t\tgit_config_set(buf.buf, rename.new_name);\n+\t\t}\n \t}\n \n \tif (!refspec_updated)\n@@ -783,6 +796,13 @@ static int rm(int argc, const char **argv)\n \t\t\t\t\tdie(_(\"could not unset '%s'\"), buf.buf);\n \t\t\t}\n \t\t}\n+\t\tif (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {\n+\t\t\tstrbuf_reset(&buf);\n+\t\t\tstrbuf_addf(&buf, \"branch.%s.pushremote\", item->string);\n+\t\t\tresult = git_config_set_gently(buf.buf, NULL);\n+\t\t\tif (result && result != CONFIG_NOTHING_SET)\n+\t\t\t\tdie(_(\"could not unset '%s'\"), buf.buf);\n+\t\t}\n \t}\n \n \t/*\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 883b32efa0..082042b05a 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -737,12 +737,14 @@ test_expect_success 'rename a remote' '\n \tgit clone one four &&\n \t(\n \t\tcd four &&\n+\t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n \t\ttest \"$(git symbolic-ref refs/remotes/upstream/HEAD)\" = \"refs/remotes/upstream/master\" &&\n \t\ttest \"$(git rev-parse upstream/master)\" = \"$(git rev-parse master)\" &&\n \t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\" &&\n-\t\ttest \"$(git config branch.master.remote)\" = \"upstream\"\n+\t\ttest \"$(git config branch.master.remote)\" = \"upstream\" &&\n+\t\ttest \"$(git config branch.master.pushRemote)\" = \"upstream\"\n \t)\n '\n \n@@ -784,6 +786,18 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n \tgit -C four.four remote rename origin upstream\n '\n \n+test_expect_success 'remove a remote' '\n+\tgit clone one four.five &&\n+\t(\n+\t\tcd four.five &&\n+\t\tgit config branch.master.pushRemote origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n+\t\ttest_must_fail git config branch.master.remote &&\n+\t\ttest_must_fail git config branch.master.pushRemote\n+\t)\n+'\n+\n cat >remotes_origin <<EOF\n URL: $(pwd)/one\n Push: refs/heads/master:refs/heads/upstream\n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390543","messageId":"029dd071038db1daf590d5224076c089cfd060bc.1580108477.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"cover.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH v2 6/6] remote rename/remove: gently handle remote.pushDefault config","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T07:04:32Z","receivedAt":"2020-01-27T07:04:46Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"When renaming a remote with\n\n    git remote rename X Y\n    git remote remove X\n\nGit already renames or removes any branch.<name>.remote and\nbranch.<name>.pushRemote configurations if their value is X.\n\nHowever remote.pushDefault needs a more gentle approach, as this may be\nset in a non-repo configuration file. In such a case only a warning is\nprinted, such as:\n\nwarning: The global configuration remote.pushDefault in:\n\t$HOME/.gitconfig:35\nnow names the non-existent remote origin\n\nIt is changed to remote.pushDefault = Y or removed when set in a repo\nconfiguration though.\n\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n---\n\nMatthew, you are in Cc because of your current work 'config: allow user to\nknow scope of config options'. I think I'm correct to assuming an ordering\nof the enum config_scope.\n\nChanges since v1:\n * handle also 'git remote remove'\n\nCc: Junio C Hamano <gitster@pobox.com>\nCc: Johannes Schindelin <johannes.schindelin@gmx.de>\nCc: Matthew Rogers <mattr94@gmail.com>\n---\n builtin/remote.c  | 54 +++++++++++++++++++++++++++++++++\n t/t5505-remote.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++--\n 2 files changed, 128 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex a2379a14bf..7404e50c13 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -615,6 +615,55 @@ static int migrate_file(struct remote *remote)\n \treturn 0;\n }\n \n+struct push_default_info\n+{\n+\tconst char *old_name;\n+\tenum config_scope scope;\n+\tstruct strbuf origin;\n+\tint linenr;\n+};\n+\n+static int config_read_push_default(const char *key, const char *value,\n+\tvoid *cb)\n+{\n+\tstruct push_default_info* info = cb;\n+\tif (strcmp(key, \"remote.pushdefault\") || strcmp(value, info->old_name))\n+\t\treturn 0;\n+\n+\tinfo->scope = current_config_scope();\n+\tstrbuf_reset(&info->origin);\n+\tstrbuf_addstr(&info->origin, current_config_name());\n+\tinfo->linenr = current_config_line();\n+\n+\treturn 0;\n+}\n+\n+static void handle_push_default(const char* old_name, const char* new_name)\n+{\n+\tstruct push_default_info push_default = {\n+\t\told_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };\n+\tgit_config(config_read_push_default, &push_default);\n+\tif (push_default.scope >= CONFIG_SCOPE_CMDLINE)\n+\t\t; /* pass */\n+\telse if (push_default.scope >= CONFIG_SCOPE_REPO) {\n+\t\tint result = git_config_set_gently(\"remote.pushDefault\",\n+\t\t\t\t\t\t   new_name);\n+\t\tif (new_name && result && result != CONFIG_NOTHING_SET)\n+\t\t\tdie(_(\"could not set '%s'\"), \"remote.pushDefault\");\n+\t\telse if (!new_name && result && result != CONFIG_NOTHING_SET)\n+\t\t\tdie(_(\"could not unset '%s'\"), \"remote.pushDefault\");\n+\t} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {\n+\t\t/* warn */\n+\t\twarning(_(\"The %s configuration remote.pushDefault in:\\n\"\n+\t\t\t  \"\\t%s:%d\\n\"\n+\t\t\t  \"now names the non-existent remote '%s'\"),\n+\t\t\tconfig_scope_name(push_default.scope),\n+\t\t\tpush_default.origin.buf, push_default.linenr,\n+\t\t\told_name);\n+\t}\n+}\n+\n+\n static int mv(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -750,6 +799,9 @@ static int mv(int argc, const char **argv)\n \t\t\tdie(_(\"creating '%s' failed\"), buf.buf);\n \t}\n \tstring_list_clear(&remote_branches, 1);\n+\n+\thandle_push_default(rename.old_name, rename.new_name);\n+\n \treturn 0;\n }\n \n@@ -835,6 +887,8 @@ static int rm(int argc, const char **argv)\n \t\tstrbuf_addf(&buf, \"remote.%s\", remote->name);\n \t\tif (git_config_rename_section(buf.buf, NULL) < 1)\n \t\t\treturn error(_(\"Could not remove config section '%s'\"), buf.buf);\n+\n+\t\thandle_push_default(remote->name, NULL);\n \t}\n \n \treturn result;\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 082042b05a..bbff8c5770 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -737,6 +737,7 @@ test_expect_success 'rename a remote' '\n \tgit clone one four &&\n \t(\n \t\tcd four &&\n+\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n@@ -744,7 +745,42 @@ test_expect_success 'rename a remote' '\n \t\ttest \"$(git rev-parse upstream/master)\" = \"$(git rev-parse master)\" &&\n \t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\" &&\n \t\ttest \"$(git config branch.master.remote)\" = \"upstream\" &&\n-\t\ttest \"$(git config branch.master.pushRemote)\" = \"upstream\"\n+\t\ttest \"$(git config branch.master.pushRemote)\" = \"upstream\" &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault' '\n+\tgit clone one four.1 &&\n+\t(\n+\t\tcd four.1 &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n+\tgit clone one four.2 &&\n+\t(\n+\t\tcd four.2 &&\n+\t\ttest_config_global remote.pushDefault other &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n+\tgit clone one four.3 &&\n+\t(\n+\t\tcd four.3 &&\n+\t\ttest_config_global remote.pushDefault origin &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n \t)\n '\n \n@@ -790,11 +826,47 @@ test_expect_success 'remove a remote' '\n \tgit clone one four.five &&\n \t(\n \t\tcd four.five &&\n+\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote remove origin &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n \t\ttest_must_fail git config branch.master.remote &&\n-\t\ttest_must_fail git config branch.master.pushRemote\n+\t\ttest_must_fail git config branch.master.pushRemote &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault' '\n+\tgit clone one four.five.1 &&\n+\t(\n+\t\tcd four.five.1 &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n+\tgit clone one four.five.2 &&\n+\t(\n+\t\tcd four.five.2 &&\n+\t\ttest_config_global remote.pushDefault other &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n+\tgit clone one four.five.3 &&\n+\t(\n+\t\tcd four.five.3 &&\n+\t\ttest_config_global remote.pushDefault origin &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n \t)\n '\n \n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390544","messageId":"965b587f5834c88532476b56da95ead605d16000.1580110970.git.bert.wesarg@googlemail.com","threadId":"52701","inReplyTo":"029dd071038db1daf590d5224076c089cfd060bc.1580108477.git.bert.wesarg@googlemail.com","subject":"[PATCH v3 6/6] remote rename/remove: gently handle remote.pushDefault config","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-27T08:15:54Z","receivedAt":"2020-01-27T08:16:00Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"When renaming a remote with\n\n    git remote rename X Y\n    git remote remove X\n\nGit already renames or removes any branch.<name>.remote and\nbranch.<name>.pushRemote configurations if their value is X.\n\nHowever remote.pushDefault needs a more gentle approach, as this may be\nset in a non-repo configuration file. In such a case only a warning is\nprinted, such as:\n\nwarning: The global configuration remote.pushDefault in:\n\t$HOME/.gitconfig:35\nnow names the non-existent remote origin\n\nIt is changed to remote.pushDefault = Y or removed when set in a repo\nconfiguration though.\n\nSigned-off-by: Bert Wesarg <bert.wesarg@googlemail.com>\n---\n\nSorry, <029dd071038db1daf590d5224076c089cfd060bc.1580108477.git.bert.wesarg@googlemail.com>\nmissed the ammend to let it work with mr/show-config-scope. Please drop that in\nfavor of this one.\n\nChanges since v1:\n * handle also 'git remote remove'\n\nCc: Junio C Hamano <gitster@pobox.com>\nCc: Johannes Schindelin <johannes.schindelin@gmx.de>\nCc: Matthew Rogers <mattr94@gmail.com>\n---\n builtin/remote.c  | 54 +++++++++++++++++++++++++++++++++\n t/t5505-remote.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++--\n 2 files changed, 128 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex a2379a14bf..5af06b74a7 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -615,6 +615,55 @@ static int migrate_file(struct remote *remote)\n \treturn 0;\n }\n \n+struct push_default_info\n+{\n+\tconst char *old_name;\n+\tenum config_scope scope;\n+\tstruct strbuf origin;\n+\tint linenr;\n+};\n+\n+static int config_read_push_default(const char *key, const char *value,\n+\tvoid *cb)\n+{\n+\tstruct push_default_info* info = cb;\n+\tif (strcmp(key, \"remote.pushdefault\") || strcmp(value, info->old_name))\n+\t\treturn 0;\n+\n+\tinfo->scope = current_config_scope();\n+\tstrbuf_reset(&info->origin);\n+\tstrbuf_addstr(&info->origin, current_config_name());\n+\tinfo->linenr = current_config_line();\n+\n+\treturn 0;\n+}\n+\n+static void handle_push_default(const char* old_name, const char* new_name)\n+{\n+\tstruct push_default_info push_default = {\n+\t\told_name, CONFIG_SCOPE_UNKNOWN, STRBUF_INIT, -1 };\n+\tgit_config(config_read_push_default, &push_default);\n+\tif (push_default.scope >= CONFIG_SCOPE_COMMAND)\n+\t\t; /* pass */\n+\telse if (push_default.scope >= CONFIG_SCOPE_LOCAL) {\n+\t\tint result = git_config_set_gently(\"remote.pushDefault\",\n+\t\t\t\t\t\t   new_name);\n+\t\tif (new_name && result && result != CONFIG_NOTHING_SET)\n+\t\t\tdie(_(\"could not set '%s'\"), \"remote.pushDefault\");\n+\t\telse if (!new_name && result && result != CONFIG_NOTHING_SET)\n+\t\t\tdie(_(\"could not unset '%s'\"), \"remote.pushDefault\");\n+\t} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {\n+\t\t/* warn */\n+\t\twarning(_(\"The %s configuration remote.pushDefault in:\\n\"\n+\t\t\t  \"\\t%s:%d\\n\"\n+\t\t\t  \"now names the non-existent remote '%s'\"),\n+\t\t\tconfig_scope_name(push_default.scope),\n+\t\t\tpush_default.origin.buf, push_default.linenr,\n+\t\t\told_name);\n+\t}\n+}\n+\n+\n static int mv(int argc, const char **argv)\n {\n \tstruct option options[] = {\n@@ -750,6 +799,9 @@ static int mv(int argc, const char **argv)\n \t\t\tdie(_(\"creating '%s' failed\"), buf.buf);\n \t}\n \tstring_list_clear(&remote_branches, 1);\n+\n+\thandle_push_default(rename.old_name, rename.new_name);\n+\n \treturn 0;\n }\n \n@@ -835,6 +887,8 @@ static int rm(int argc, const char **argv)\n \t\tstrbuf_addf(&buf, \"remote.%s\", remote->name);\n \t\tif (git_config_rename_section(buf.buf, NULL) < 1)\n \t\t\treturn error(_(\"Could not remove config section '%s'\"), buf.buf);\n+\n+\t\thandle_push_default(remote->name, NULL);\n \t}\n \n \treturn result;\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 082042b05a..bbff8c5770 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -737,6 +737,7 @@ test_expect_success 'rename a remote' '\n \tgit clone one four &&\n \t(\n \t\tcd four &&\n+\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n@@ -744,7 +745,42 @@ test_expect_success 'rename a remote' '\n \t\ttest \"$(git rev-parse upstream/master)\" = \"$(git rev-parse master)\" &&\n \t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\" &&\n \t\ttest \"$(git config branch.master.remote)\" = \"upstream\" &&\n-\t\ttest \"$(git config branch.master.pushRemote)\" = \"upstream\"\n+\t\ttest \"$(git config branch.master.pushRemote)\" = \"upstream\" &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault' '\n+\tgit clone one four.1 &&\n+\t(\n+\t\tcd four.1 &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n+\tgit clone one four.2 &&\n+\t(\n+\t\tcd four.2 &&\n+\t\ttest_config_global remote.pushDefault other &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n+\t)\n+'\n+\n+test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n+\tgit clone one four.3 &&\n+\t(\n+\t\tcd four.3 &&\n+\t\ttest_config_global remote.pushDefault origin &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote rename origin upstream &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n+\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n \t)\n '\n \n@@ -790,11 +826,47 @@ test_expect_success 'remove a remote' '\n \tgit clone one four.five &&\n \t(\n \t\tcd four.five &&\n+\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote remove origin &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n \t\ttest_must_fail git config branch.master.remote &&\n-\t\ttest_must_fail git config branch.master.pushRemote\n+\t\ttest_must_fail git config branch.master.pushRemote &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault' '\n+\tgit clone one four.five.1 &&\n+\t(\n+\t\tcd four.five.1 &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n+\tgit clone one four.five.2 &&\n+\t(\n+\t\tcd four.five.2 &&\n+\t\ttest_config_global remote.pushDefault other &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n+\t)\n+'\n+\n+test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n+\tgit clone one four.five.3 &&\n+\t(\n+\t\tcd four.five.3 &&\n+\t\ttest_config_global remote.pushDefault origin &&\n+\t\tgit config remote.pushDefault origin &&\n+\t\tgit remote remove origin &&\n+\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n+\t\ttest_must_fail git config --local remote.pushDefault\n \t)\n '\n \n-- \n2.24.1.497.g9abd7b20b4.dirty\n\n"},{"id":"390701","messageId":"xmqqv9ou6983.fsf@gitster-ct.c.googlers.com","threadId":"52701","inReplyTo":"965b587f5834c88532476b56da95ead605d16000.1580110970.git.bert.wesarg@googlemail.com","subject":"Re: [PATCH v3 6/6] remote rename/remove: gently handle remote.pushDefault config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-01-29T06:57:16Z","receivedAt":"2020-01-29T06:57:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bert Wesarg <bert.wesarg@googlemail.com> writes:\n\n> diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\n> index 082042b05a..bbff8c5770 100755\n> --- a/t/t5505-remote.sh\n> +++ b/t/t5505-remote.sh\n> @@ -737,6 +737,7 @@ test_expect_success 'rename a remote' '\n>  \tgit clone one four &&\n>  \t(\n>  \t\tcd four &&\n> +\t\ttest_config_global remote.pushDefault origin &&\n>  \t\tgit config branch.master.pushRemote origin &&\n>  \t\tgit remote rename origin upstream &&\n>  \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n\nYou cannot use test_config and test_config_global inside a subshell,\nas they rely on test_when_finished to rewind their effect, which\ncannot be used inside a subshell.  As you are doing \"global\" config,\nthere is no reason to make \"git config --global\" call in a particular\nrepository anyway, so just do this upfront as the first thing in the\ntest sequence.  There are a few others in this file.\n\nTentatively I applied the following fix-up on top of the series to\nunblock tonight's integration cycle.\n\nThanks.\n\n t/t5505-remote.sh | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex bbff8c5770..dda81b7d07 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -734,10 +734,10 @@ test_expect_success 'reject adding remote with an invalid name' '\n # the last two ones check if the config is updated.\n \n test_expect_success 'rename a remote' '\n+\ttest_config_global remote.pushDefault origin &&\n \tgit clone one four &&\n \t(\n \t\tcd four &&\n-\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n@@ -761,10 +761,10 @@ test_expect_success 'rename a remote renames repo remote.pushDefault' '\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n+\ttest_config_global remote.pushDefault other &&\n \tgit clone one four.2 &&\n \t(\n \t\tcd four.2 &&\n-\t\ttest_config_global remote.pushDefault other &&\n \t\tgit config remote.pushDefault origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n@@ -773,10 +773,10 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but ignores\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n+\ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.3 &&\n \t(\n \t\tcd four.3 &&\n-\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config remote.pushDefault origin &&\n \t\tgit remote rename origin upstream &&\n \t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n@@ -823,10 +823,10 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n '\n \n test_expect_success 'remove a remote' '\n+\ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.five &&\n \t(\n \t\tcd four.five &&\n-\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config branch.master.pushRemote origin &&\n \t\tgit remote remove origin &&\n \t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n@@ -847,10 +847,10 @@ test_expect_success 'remove a remote removes repo remote.pushDefault' '\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n+\ttest_config_global remote.pushDefault other &&\n \tgit clone one four.five.2 &&\n \t(\n \t\tcd four.five.2 &&\n-\t\ttest_config_global remote.pushDefault other &&\n \t\tgit config remote.pushDefault origin &&\n \t\tgit remote remove origin &&\n \t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n@@ -859,10 +859,10 @@ test_expect_success 'remove a remote removes repo remote.pushDefault but ignores\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n+\ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.five.3 &&\n \t(\n \t\tcd four.five.3 &&\n-\t\ttest_config_global remote.pushDefault origin &&\n \t\tgit config remote.pushDefault origin &&\n \t\tgit remote remove origin &&\n \t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n"},{"id":"390705","messageId":"CAKPyHN0V6m4fP=0Yktgr+m+dPq3r2HrWC-ddTKJ6y3TVF4GSMQ@mail.gmail.com","threadId":"52701","inReplyTo":"xmqqv9ou6983.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 6/6] remote rename/remove: gently handle remote.pushDefault config","fromName":"Bert Wesarg","fromEmail":"bert.wesarg@googlemail.com","sentAt":"2020-01-29T09:16:19Z","receivedAt":"2020-01-29T09:16:33Z","isPatch":true,"sender":{"key":"bert.wesarg@googlemail.com","avatar":"https://avatars.githubusercontent.com/u/111934?v=4"},"body":"On Wed, Jan 29, 2020 at 7:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Bert Wesarg <bert.wesarg@googlemail.com> writes:\n>\n> > diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\n> > index 082042b05a..bbff8c5770 100755\n> > --- a/t/t5505-remote.sh\n> > +++ b/t/t5505-remote.sh\n> > @@ -737,6 +737,7 @@ test_expect_success 'rename a remote' '\n> >       git clone one four &&\n> >       (\n> >               cd four &&\n> > +             test_config_global remote.pushDefault origin &&\n> >               git config branch.master.pushRemote origin &&\n> >               git remote rename origin upstream &&\n> >               test -z \"$(git for-each-ref refs/remotes/origin)\" &&\n>\n> You cannot use test_config and test_config_global inside a subshell,\n> as they rely on test_when_finished to rewind their effect, which\n> cannot be used inside a subshell.  As you are doing \"global\" config,\n> there is no reason to make \"git config --global\" call in a particular\n> repository anyway, so just do this upfront as the first thing in the\n> test sequence.  There are a few others in this file.\n>\n> Tentatively I applied the following fix-up on top of the series to\n> unblock tonight's integration cycle.\n>\n> Thanks.\n\nThanks. Will squash them and re-roll.\n\nBert\n\n>\n>  t/t5505-remote.sh | 12 ++++++------\n>  1 file changed, 6 insertions(+), 6 deletions(-)\n>\n> diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\n> index bbff8c5770..dda81b7d07 100755\n> --- a/t/t5505-remote.sh\n> +++ b/t/t5505-remote.sh\n> @@ -734,10 +734,10 @@ test_expect_success 'reject adding remote with an invalid name' '\n>  # the last two ones check if the config is updated.\n>\n>  test_expect_success 'rename a remote' '\n> +       test_config_global remote.pushDefault origin &&\n>         git clone one four &&\n>         (\n>                 cd four &&\n> -               test_config_global remote.pushDefault origin &&\n>                 git config branch.master.pushRemote origin &&\n>                 git remote rename origin upstream &&\n>                 test -z \"$(git for-each-ref refs/remotes/origin)\" &&\n> @@ -761,10 +761,10 @@ test_expect_success 'rename a remote renames repo remote.pushDefault' '\n>  '\n>\n>  test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n> +       test_config_global remote.pushDefault other &&\n>         git clone one four.2 &&\n>         (\n>                 cd four.2 &&\n> -               test_config_global remote.pushDefault other &&\n>                 git config remote.pushDefault origin &&\n>                 git remote rename origin upstream &&\n>                 test \"$(git config --global remote.pushDefault)\" = \"other\" &&\n> @@ -773,10 +773,10 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but ignores\n>  '\n>\n>  test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n> +       test_config_global remote.pushDefault origin &&\n>         git clone one four.3 &&\n>         (\n>                 cd four.3 &&\n> -               test_config_global remote.pushDefault origin &&\n>                 git config remote.pushDefault origin &&\n>                 git remote rename origin upstream &&\n>                 test \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n> @@ -823,10 +823,10 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n>  '\n>\n>  test_expect_success 'remove a remote' '\n> +       test_config_global remote.pushDefault origin &&\n>         git clone one four.five &&\n>         (\n>                 cd four.five &&\n> -               test_config_global remote.pushDefault origin &&\n>                 git config branch.master.pushRemote origin &&\n>                 git remote remove origin &&\n>                 test -z \"$(git for-each-ref refs/remotes/origin)\" &&\n> @@ -847,10 +847,10 @@ test_expect_success 'remove a remote removes repo remote.pushDefault' '\n>  '\n>\n>  test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n> +       test_config_global remote.pushDefault other &&\n>         git clone one four.five.2 &&\n>         (\n>                 cd four.five.2 &&\n> -               test_config_global remote.pushDefault other &&\n>                 git config remote.pushDefault origin &&\n>                 git remote remove origin &&\n>                 test \"$(git config --global remote.pushDefault)\" = \"other\" &&\n> @@ -859,10 +859,10 @@ test_expect_success 'remove a remote removes repo remote.pushDefault but ignores\n>  '\n>\n>  test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n> +       test_config_global remote.pushDefault origin &&\n>         git clone one four.five.3 &&\n>         (\n>                 cd four.five.3 &&\n> -               test_config_global remote.pushDefault origin &&\n>                 git config remote.pushDefault origin &&\n>                 git remote remove origin &&\n>                 test \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n"}]}