{"thread":{"id":"51869","subject":"[PATCH] submodule: teach set-url subcommand","startedAt":"2019-09-17T20:03:44Z","lastAt":"2019-11-02T04:25:18Z","messageCount":7,"participants":["Denton Liu","Danh Doan","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"382519","messageId":"3c7a496209d2d8d2162ef3ea7565eef0b0ca0576.1568750590.git.liu.denton@gmail.com","threadId":"51869","inReplyTo":null,"subject":"[PATCH] submodule: teach set-url subcommand","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2019-09-17T20:03:38Z","receivedAt":"2019-09-17T20:03:44Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Currently, in the event that a submodule's upstream URL changes, users\nhave to manually alter the URL in the .gitmodules file then run\n`git submodule sync`. Let's make that process easier.\n\nTeach submodule the set-url subcommand which will automatically change\nthe `submodule.$name.url` property in the .gitmodules file and then run\n`git submodule sync` to complete the process.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\n Documentation/git-submodule.txt        |  6 +++\n contrib/completion/git-completion.bash |  2 +-\n git-submodule.sh                       | 52 +++++++++++++++++++++++++-\n t/t7420-submodule-set-url.sh           | 51 +++++++++++++++++++++++++\n 4 files changed, 109 insertions(+), 2 deletions(-)\n create mode 100755 t/t7420-submodule-set-url.sh\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 0ed5c24dc1..8eac3c350c 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -16,6 +16,7 @@ SYNOPSIS\n 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)\n 'git submodule' [--quiet] update [<options>] [--] [<path>...]\n 'git submodule' [--quiet] set-branch [<options>] [--] <path>\n+'git submodule' [--quiet] set-url [<options>] [--] <path> <newurl>\n 'git submodule' [--quiet] summary [<options>] [--] [<path>...]\n 'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n@@ -179,6 +180,11 @@ set-branch ((-d|--default)|(-b|--branch <branch>)) [--] <path>::\n \t`--default` option removes the submodule.<name>.branch configuration\n \tkey, which causes the tracking branch to default to 'master'.\n \n+set-url [--] <path> <newurl>::\n+\tSets the URL of the specified submodule to <newurl>. Then, it will\n+\tautomatically synchronize the submodule's new remote URL\n+\tconfiguration.\n+\n summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::\n \tShow commit summary between the given commit (defaults to HEAD) and\n \tworking tree/index. For a submodule in question, a series of commits\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex e087c4bf00..bec31a7fc3 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2666,7 +2666,7 @@ _git_submodule ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal subcommands=\"add status init deinit update set-branch summary foreach sync absorbgitdirs\"\n+\tlocal subcommands=\"add status init deinit update set-branch set-url summary foreach sync absorbgitdirs\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n \t\tcase \"$cur\" in\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c7f58c5756..f7374ddbd6 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -12,6 +12,7 @@ USAGE=\"[--quiet] [--cached]\n    or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)\n    or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>\n+   or: $dashless [--quiet] set-url [--] <path> <newurl>\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n    or: $dashless [--quiet] foreach [--recursive] <command>\n    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]\n@@ -760,6 +761,55 @@ cmd_set_branch() {\n \tfi\n }\n \n+#\n+# Configures a submodule's remote url\n+#\n+# $@ = requested path, requested url\n+#\n+cmd_set_url() {\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-q|--quiet)\n+\t\t\tGIT_QUIET=1\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tusage\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tif test $# -ne 2\n+\tthen\n+\t\tusage\n+\tfi\n+\n+\t# we can't use `git submodule--helper name` here because internally, it\n+\t# hashes the path so a trailing slash could lead to an unintentional no match\n+\tname=\"$(git submodule--helper list \"$1\" | cut -f2)\"\n+\tif test -z \"$name\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\turl=\"$2\"\n+\tif test -z \"$url\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\tgit submodule--helper config submodule.\"$name\".url \"$url\"\n+\tgit submodule--helper sync ${GIT_QUIET:+--quiet} \"$name\"\n+}\n+\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1059,7 +1109,7 @@ cmd_absorbgitdirs()\n while test $# != 0 && test -z \"$command\"\n do\n \tcase \"$1\" in\n-\tadd | foreach | init | deinit | update | set-branch | status | summary | sync | absorbgitdirs)\n+\tadd | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs)\n \t\tcommand=$1\n \t\t;;\n \t-q|--quiet)\ndiff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh\nnew file mode 100755\nindex 0000000000..60adc5db28\n--- /dev/null\n+++ b/t/t7420-submodule-set-url.sh\n@@ -0,0 +1,51 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2019 Denton Liu\n+#\n+\n+test_description='Test submodules set-url subcommand\n+\n+This test verifies that the set-url subcommand of git-submodule is working\n+as expected.\n+'\n+\n+TEST_NO_CREATE_REPO=1\n+. ./test-lib.sh\n+\n+test_expect_success 'submodule config cache setup' '\n+\tmkdir submodule &&\n+\t(cd submodule &&\n+\t\tgit init &&\n+\t\techo a >file &&\n+\t\tgit add file &&\n+\t\tgit commit -ma\n+\t) &&\n+\tmkdir super &&\n+\t(cd super &&\n+\t\tgit init &&\n+\t\tgit submodule add ../submodule &&\n+\t\tgit commit -m \"add submodule\"\n+\t)\n+'\n+\n+test_expect_success 'test submodule set-url' '\n+\t# add a commit and move the submodule (change the url)\n+\t(cd submodule &&\n+\t\techo b >>file &&\n+\t\tgit add file &&\n+\t\tgit commit -mb\n+\t) &&\n+\tmv submodule newsubmodule &&\n+\n+\tgit -C newsubmodule show >expect &&\n+\t(cd super &&\n+\t\ttest_must_fail git submodule update --remote &&\n+\t\tgit submodule set-url submodule ../newsubmodule &&\n+\t\tgrep \"url = \\.\\./newsubmodule\" .gitmodules &&\n+\t\tgit submodule update --remote &&\n+\t\tgit -C submodule show >../actual\n+\t) &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.23.0\n\n"},{"id":"385050","messageId":"d8841c6009c91ac921d30b35ed9a441c87b332e2.1572337964.git.liu.denton@gmail.com","threadId":"51869","inReplyTo":"3c7a496209d2d8d2162ef3ea7565eef0b0ca0576.1568750590.git.liu.denton@gmail.com","subject":"[PATCH v2] submodule: teach set-url subcommand","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2019-10-29T08:34:19Z","receivedAt":"2019-10-29T08:34:25Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Currently, in the event that a submodule's upstream URL changes, users\nhave to manually alter the URL in the .gitmodules file then run\n`git submodule sync`. Let's make that process easier.\n\nTeach submodule the set-url subcommand which will automatically change\nthe `submodule.$name.url` property in the .gitmodules file and then run\n`git submodule sync` to complete the process.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nRange-diff against v1:\n1:  3c7a496209 ! 1:  d8841c6009 submodule: teach set-url subcommand\n    @@ Documentation/git-submodule.txt: SYNOPSIS\n      'git submodule' [--quiet] summary [<options>] [--] [<path>...]\n      'git submodule' [--quiet] foreach [--recursive] <command>\n      'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n    -@@ Documentation/git-submodule.txt: set-branch ((-d|--default)|(-b|--branch <branch>)) [--] <path>::\n    +@@ Documentation/git-submodule.txt: set-branch (-d|--default) [--] <path>::\n      \t`--default` option removes the submodule.<name>.branch configuration\n      \tkey, which causes the tracking branch to default to 'master'.\n      \n    @@ t/t7420-submodule-set-url.sh (new)\n     +\n     +test_expect_success 'submodule config cache setup' '\n     +\tmkdir submodule &&\n    -+\t(cd submodule &&\n    ++\t(\n    ++\t\tcd submodule &&\n     +\t\tgit init &&\n     +\t\techo a >file &&\n     +\t\tgit add file &&\n     +\t\tgit commit -ma\n     +\t) &&\n     +\tmkdir super &&\n    -+\t(cd super &&\n    ++\t(\n    ++\t\tcd super &&\n     +\t\tgit init &&\n     +\t\tgit submodule add ../submodule &&\n     +\t\tgit commit -m \"add submodule\"\n    @@ t/t7420-submodule-set-url.sh (new)\n     +\n     +test_expect_success 'test submodule set-url' '\n     +\t# add a commit and move the submodule (change the url)\n    -+\t(cd submodule &&\n    ++\t(\n    ++\t\tcd submodule &&\n     +\t\techo b >>file &&\n     +\t\tgit add file &&\n     +\t\tgit commit -mb\n    @@ t/t7420-submodule-set-url.sh (new)\n     +\tmv submodule newsubmodule &&\n     +\n     +\tgit -C newsubmodule show >expect &&\n    -+\t(cd super &&\n    ++\t(\n    ++\t\tcd super &&\n     +\t\ttest_must_fail git submodule update --remote &&\n     +\t\tgit submodule set-url submodule ../newsubmodule &&\n     +\t\tgrep \"url = \\.\\./newsubmodule\" .gitmodules &&\n    -+\t\tgit submodule update --remote &&\n    -+\t\tgit -C submodule show >../actual\n    ++\t\tgit submodule update --remote\n     +\t) &&\n    ++\tgit -C super/submodule show >actual &&\n     +\ttest_cmp expect actual\n     +'\n     +\n\n Documentation/git-submodule.txt        |  6 +++\n contrib/completion/git-completion.bash |  2 +-\n git-submodule.sh                       | 52 +++++++++++++++++++++++-\n t/t7420-submodule-set-url.sh           | 55 ++++++++++++++++++++++++++\n 4 files changed, 113 insertions(+), 2 deletions(-)\n create mode 100755 t/t7420-submodule-set-url.sh\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 1f46380af2..f1c4689f24 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -16,6 +16,7 @@ SYNOPSIS\n 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)\n 'git submodule' [--quiet] update [<options>] [--] [<path>...]\n 'git submodule' [--quiet] set-branch [<options>] [--] <path>\n+'git submodule' [--quiet] set-url [<options>] [--] <path> <newurl>\n 'git submodule' [--quiet] summary [<options>] [--] [<path>...]\n 'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n@@ -180,6 +181,11 @@ set-branch (-d|--default) [--] <path>::\n \t`--default` option removes the submodule.<name>.branch configuration\n \tkey, which causes the tracking branch to default to 'master'.\n \n+set-url [--] <path> <newurl>::\n+\tSets the URL of the specified submodule to <newurl>. Then, it will\n+\tautomatically synchronize the submodule's new remote URL\n+\tconfiguration.\n+\n summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::\n \tShow commit summary between the given commit (defaults to HEAD) and\n \tworking tree/index. For a submodule in question, a series of commits\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 00fbe6c03d..88c7446414 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2779,7 +2779,7 @@ _git_submodule ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal subcommands=\"add status init deinit update set-branch summary foreach sync absorbgitdirs\"\n+\tlocal subcommands=\"add status init deinit update set-branch set-url summary foreach sync absorbgitdirs\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n \t\tcase \"$cur\" in\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c7f58c5756..f7374ddbd6 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -12,6 +12,7 @@ USAGE=\"[--quiet] [--cached]\n    or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)\n    or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>\n+   or: $dashless [--quiet] set-url [--] <path> <newurl>\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n    or: $dashless [--quiet] foreach [--recursive] <command>\n    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]\n@@ -760,6 +761,55 @@ cmd_set_branch() {\n \tfi\n }\n \n+#\n+# Configures a submodule's remote url\n+#\n+# $@ = requested path, requested url\n+#\n+cmd_set_url() {\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-q|--quiet)\n+\t\t\tGIT_QUIET=1\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tusage\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tif test $# -ne 2\n+\tthen\n+\t\tusage\n+\tfi\n+\n+\t# we can't use `git submodule--helper name` here because internally, it\n+\t# hashes the path so a trailing slash could lead to an unintentional no match\n+\tname=\"$(git submodule--helper list \"$1\" | cut -f2)\"\n+\tif test -z \"$name\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\turl=\"$2\"\n+\tif test -z \"$url\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\tgit submodule--helper config submodule.\"$name\".url \"$url\"\n+\tgit submodule--helper sync ${GIT_QUIET:+--quiet} \"$name\"\n+}\n+\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1059,7 +1109,7 @@ cmd_absorbgitdirs()\n while test $# != 0 && test -z \"$command\"\n do\n \tcase \"$1\" in\n-\tadd | foreach | init | deinit | update | set-branch | status | summary | sync | absorbgitdirs)\n+\tadd | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs)\n \t\tcommand=$1\n \t\t;;\n \t-q|--quiet)\ndiff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh\nnew file mode 100755\nindex 0000000000..9bc941ced3\n--- /dev/null\n+++ b/t/t7420-submodule-set-url.sh\n@@ -0,0 +1,55 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2019 Denton Liu\n+#\n+\n+test_description='Test submodules set-url subcommand\n+\n+This test verifies that the set-url subcommand of git-submodule is working\n+as expected.\n+'\n+\n+TEST_NO_CREATE_REPO=1\n+. ./test-lib.sh\n+\n+test_expect_success 'submodule config cache setup' '\n+\tmkdir submodule &&\n+\t(\n+\t\tcd submodule &&\n+\t\tgit init &&\n+\t\techo a >file &&\n+\t\tgit add file &&\n+\t\tgit commit -ma\n+\t) &&\n+\tmkdir super &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add ../submodule &&\n+\t\tgit commit -m \"add submodule\"\n+\t)\n+'\n+\n+test_expect_success 'test submodule set-url' '\n+\t# add a commit and move the submodule (change the url)\n+\t(\n+\t\tcd submodule &&\n+\t\techo b >>file &&\n+\t\tgit add file &&\n+\t\tgit commit -mb\n+\t) &&\n+\tmv submodule newsubmodule &&\n+\n+\tgit -C newsubmodule show >expect &&\n+\t(\n+\t\tcd super &&\n+\t\ttest_must_fail git submodule update --remote &&\n+\t\tgit submodule set-url submodule ../newsubmodule &&\n+\t\tgrep \"url = \\.\\./newsubmodule\" .gitmodules &&\n+\t\tgit submodule update --remote\n+\t) &&\n+\tgit -C super/submodule show >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.24.0.rc0.197.g0926ab8072\n\n"},{"id":"385052","messageId":"20191029091538.GB17223@danh.dev","threadId":"51869","inReplyTo":"d8841c6009c91ac921d30b35ed9a441c87b332e2.1572337964.git.liu.denton@gmail.com","subject":"Re: [PATCH v2] submodule: teach set-url subcommand","fromName":"Danh Doan","fromEmail":"congdanhqx@gmail.com","sentAt":"2019-10-29T09:15:38Z","receivedAt":"2019-10-29T09:15:43Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2019-10-29 01:34:19 -0700, Denton Liu wrote:\n> diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\n> index 1f46380af2..f1c4689f24 100644\n> --- a/Documentation/git-submodule.txt\n> +++ b/Documentation/git-submodule.txt\n> @@ -16,6 +16,7 @@ SYNOPSIS\n>  'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)\n>  'git submodule' [--quiet] update [<options>] [--] [<path>...]\n>  'git submodule' [--quiet] set-branch [<options>] [--] <path>\n> +'git submodule' [--quiet] set-url [<options>] [--] <path> <newurl>\n\nI skimmed over this patch and found no options.\n[<options>] should be removed\n\n> @@ -180,6 +181,11 @@ set-branch (-d|--default) [--] <path>::\n>  \t`--default` option removes the submodule.<name>.branch configuration\n>  \tkey, which causes the tracking branch to default to 'master'.\n>  \n> +set-url [--] <path> <newurl>::\n> +\tSets the URL of the specified submodule to <newurl>. Then, it will\n> +\tautomatically synchronize the submodule's new remote URL\n> +\tconfiguration.\n> +\n>  summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::\n>  \tShow commit summary between the given commit (defaults to HEAD) and\n>  \tworking tree/index. For a submodule in question, a series of commits\n> diff --git a/git-submodule.sh b/git-submodule.sh\n> index c7f58c5756..f7374ddbd6 100755\n> --- a/git-submodule.sh\n> +++ b/git-submodule.sh\n> @@ -12,6 +12,7 @@ USAGE=\"[--quiet] [--cached]\n>     or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)\n>     or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]\n>     or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>\n> +   or: $dashless [--quiet] set-url [--] <path> <newurl>\n>     or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n>     or: $dashless [--quiet] foreach [--recursive] <command>\n>     or: $dashless [--quiet] sync [--recursive] [--] [<path>...]\n> diff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh\n> new file mode 100755\n> index 0000000000..9bc941ced3\n> --- /dev/null\n> +++ b/t/t7420-submodule-set-url.sh\n> +\t\tgrep \"url = \\.\\./newsubmodule\" .gitmodules &&\n\ngrep -F \"url = ../newsubmodule\"\nwill be easier to read.\n\n-- \nDanh\n"},{"id":"385093","messageId":"f5f44812af2b43fe3f7ea837f8b07c4747eedcc0.1572368447.git.liu.denton@gmail.com","threadId":"51869","inReplyTo":"d8841c6009c91ac921d30b35ed9a441c87b332e2.1572337964.git.liu.denton@gmail.com","subject":"[PATCH v3] submodule: teach set-url subcommand","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2019-10-29T17:01:52Z","receivedAt":"2019-10-29T17:01:59Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Currently, in the event that a submodule's upstream URL changes, users\nhave to manually alter the URL in the .gitmodules file then run\n`git submodule sync`. Let's make that process easier.\n\nTeach submodule the set-url subcommand which will automatically change\nthe `submodule.$name.url` property in the .gitmodules file and then run\n`git submodule sync` to complete the process.\n\nSigned-off-by: Denton Liu <liu.denton@gmail.com>\n---\nThanks for the review, Danh. I've taken all of your suggestions.\n\nRange-diff against v2:\n1:  d8841c6009 ! 1:  f5f44812af submodule: teach set-url subcommand\n    @@ Documentation/git-submodule.txt: SYNOPSIS\n      'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)\n      'git submodule' [--quiet] update [<options>] [--] [<path>...]\n      'git submodule' [--quiet] set-branch [<options>] [--] <path>\n    -+'git submodule' [--quiet] set-url [<options>] [--] <path> <newurl>\n    ++'git submodule' [--quiet] set-url [--] <path> <newurl>\n      'git submodule' [--quiet] summary [<options>] [--] [<path>...]\n      'git submodule' [--quiet] foreach [--recursive] <command>\n      'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n    @@ t/t7420-submodule-set-url.sh (new)\n     +\t\tcd super &&\n     +\t\ttest_must_fail git submodule update --remote &&\n     +\t\tgit submodule set-url submodule ../newsubmodule &&\n    -+\t\tgrep \"url = \\.\\./newsubmodule\" .gitmodules &&\n    ++\t\tgrep -F \"url = ../newsubmodule\" .gitmodules &&\n     +\t\tgit submodule update --remote\n     +\t) &&\n     +\tgit -C super/submodule show >actual &&\n\n Documentation/git-submodule.txt        |  6 +++\n contrib/completion/git-completion.bash |  2 +-\n git-submodule.sh                       | 52 +++++++++++++++++++++++-\n t/t7420-submodule-set-url.sh           | 55 ++++++++++++++++++++++++++\n 4 files changed, 113 insertions(+), 2 deletions(-)\n create mode 100755 t/t7420-submodule-set-url.sh\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 1f46380af2..285486d0a8 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -16,6 +16,7 @@ SYNOPSIS\n 'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)\n 'git submodule' [--quiet] update [<options>] [--] [<path>...]\n 'git submodule' [--quiet] set-branch [<options>] [--] <path>\n+'git submodule' [--quiet] set-url [--] <path> <newurl>\n 'git submodule' [--quiet] summary [<options>] [--] [<path>...]\n 'git submodule' [--quiet] foreach [--recursive] <command>\n 'git submodule' [--quiet] sync [--recursive] [--] [<path>...]\n@@ -180,6 +181,11 @@ set-branch (-d|--default) [--] <path>::\n \t`--default` option removes the submodule.<name>.branch configuration\n \tkey, which causes the tracking branch to default to 'master'.\n \n+set-url [--] <path> <newurl>::\n+\tSets the URL of the specified submodule to <newurl>. Then, it will\n+\tautomatically synchronize the submodule's new remote URL\n+\tconfiguration.\n+\n summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::\n \tShow commit summary between the given commit (defaults to HEAD) and\n \tworking tree/index. For a submodule in question, a series of commits\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 00fbe6c03d..88c7446414 100644\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -2779,7 +2779,7 @@ _git_submodule ()\n {\n \t__git_has_doubledash && return\n \n-\tlocal subcommands=\"add status init deinit update set-branch summary foreach sync absorbgitdirs\"\n+\tlocal subcommands=\"add status init deinit update set-branch set-url summary foreach sync absorbgitdirs\"\n \tlocal subcommand=\"$(__git_find_on_cmdline \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n \t\tcase \"$cur\" in\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c7f58c5756..f7374ddbd6 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -12,6 +12,7 @@ USAGE=\"[--quiet] [--cached]\n    or: $dashless [--quiet] deinit [-f|--force] (--all| [--] <path>...)\n    or: $dashless [--quiet] update [--init] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--] [<path>...]\n    or: $dashless [--quiet] set-branch (--default|--branch <branch>) [--] <path>\n+   or: $dashless [--quiet] set-url [--] <path> <newurl>\n    or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]\n    or: $dashless [--quiet] foreach [--recursive] <command>\n    or: $dashless [--quiet] sync [--recursive] [--] [<path>...]\n@@ -760,6 +761,55 @@ cmd_set_branch() {\n \tfi\n }\n \n+#\n+# Configures a submodule's remote url\n+#\n+# $@ = requested path, requested url\n+#\n+cmd_set_url() {\n+\twhile test $# -ne 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-q|--quiet)\n+\t\t\tGIT_QUIET=1\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tusage\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\n+\tif test $# -ne 2\n+\tthen\n+\t\tusage\n+\tfi\n+\n+\t# we can't use `git submodule--helper name` here because internally, it\n+\t# hashes the path so a trailing slash could lead to an unintentional no match\n+\tname=\"$(git submodule--helper list \"$1\" | cut -f2)\"\n+\tif test -z \"$name\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\turl=\"$2\"\n+\tif test -z \"$url\"\n+\tthen\n+\t\texit 1\n+\tfi\n+\n+\tgit submodule--helper config submodule.\"$name\".url \"$url\"\n+\tgit submodule--helper sync ${GIT_QUIET:+--quiet} \"$name\"\n+}\n+\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1059,7 +1109,7 @@ cmd_absorbgitdirs()\n while test $# != 0 && test -z \"$command\"\n do\n \tcase \"$1\" in\n-\tadd | foreach | init | deinit | update | set-branch | status | summary | sync | absorbgitdirs)\n+\tadd | foreach | init | deinit | update | set-branch | set-url | status | summary | sync | absorbgitdirs)\n \t\tcommand=$1\n \t\t;;\n \t-q|--quiet)\ndiff --git a/t/t7420-submodule-set-url.sh b/t/t7420-submodule-set-url.sh\nnew file mode 100755\nindex 0000000000..ef0cb6e8e1\n--- /dev/null\n+++ b/t/t7420-submodule-set-url.sh\n@@ -0,0 +1,55 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2019 Denton Liu\n+#\n+\n+test_description='Test submodules set-url subcommand\n+\n+This test verifies that the set-url subcommand of git-submodule is working\n+as expected.\n+'\n+\n+TEST_NO_CREATE_REPO=1\n+. ./test-lib.sh\n+\n+test_expect_success 'submodule config cache setup' '\n+\tmkdir submodule &&\n+\t(\n+\t\tcd submodule &&\n+\t\tgit init &&\n+\t\techo a >file &&\n+\t\tgit add file &&\n+\t\tgit commit -ma\n+\t) &&\n+\tmkdir super &&\n+\t(\n+\t\tcd super &&\n+\t\tgit init &&\n+\t\tgit submodule add ../submodule &&\n+\t\tgit commit -m \"add submodule\"\n+\t)\n+'\n+\n+test_expect_success 'test submodule set-url' '\n+\t# add a commit and move the submodule (change the url)\n+\t(\n+\t\tcd submodule &&\n+\t\techo b >>file &&\n+\t\tgit add file &&\n+\t\tgit commit -mb\n+\t) &&\n+\tmv submodule newsubmodule &&\n+\n+\tgit -C newsubmodule show >expect &&\n+\t(\n+\t\tcd super &&\n+\t\ttest_must_fail git submodule update --remote &&\n+\t\tgit submodule set-url submodule ../newsubmodule &&\n+\t\tgrep -F \"url = ../newsubmodule\" .gitmodules &&\n+\t\tgit submodule update --remote\n+\t) &&\n+\tgit -C super/submodule show >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_done\n-- \n2.24.0.rc0.197.g0926ab8072\n\n"},{"id":"385136","messageId":"xmqqtv7q3hhp.fsf@gitster-ct.c.googlers.com","threadId":"51869","inReplyTo":"f5f44812af2b43fe3f7ea837f8b07c4747eedcc0.1572368447.git.liu.denton@gmail.com","subject":"Re: [PATCH v3] submodule: teach set-url subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-10-30T05:54:58Z","receivedAt":"2019-10-30T05:55:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> Currently, in the event that a submodule's upstream URL changes, users\n> have to manually alter the URL in the .gitmodules file then run\n> `git submodule sync`. Let's make that process easier.\n\nRight now, submodule.<name>.url might be the only thing that gets\nsynched down to .git/config of the submodule; we may not learn any\nmore things that needs \"edit in .gitmodules and then run sync\".  Can\nwe sately say that \"sync\" is now obsolete and what it has been used\nfor can now be done with \"set-url\"?  In other words, does \"set-url\"\nmakes \"sync\" unnecessary and deprecated?\n\nOr is it expected that we would learn more things end users can edit\nin .gitmodules and run sync to propagate necessary pieces of\ninformation down?  If so, do we want to add an extra command like\nset-url for each of these new things, or do we tell users \"if you\nare editing url, use set-url, otherwise edit .gitmodules and run\nsync\"?  If the former, that would make the set of subcommands quite\nnoisy, and if the latter, the users need to learn two things,\ni.e. it is not making it easier but harder to learn the system.\n\nThere is nothing _wrong_ to introduce the new subcommand per-se, but\ngiven that the URL should not change that often, and due to above\nconcerns, I am not sure if I want to back this change.\n"},{"id":"385166","messageId":"20191030175817.GA5120@generichostname","threadId":"51869","inReplyTo":"xmqqtv7q3hhp.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3] submodule: teach set-url subcommand","fromName":"Denton Liu","fromEmail":"liu.denton@gmail.com","sentAt":"2019-10-30T17:58:17Z","receivedAt":"2019-10-30T17:58:23Z","isPatch":true,"sender":{"key":"liu.denton@gmail.com","avatar":"https://avatars.githubusercontent.com/u/9620836?v=4"},"body":"Hi Junio,\n\nOn Wed, Oct 30, 2019 at 02:54:58PM +0900, Junio C Hamano wrote:\n> Denton Liu <liu.denton@gmail.com> writes:\n> \n> > Currently, in the event that a submodule's upstream URL changes, users\n> > have to manually alter the URL in the .gitmodules file then run\n> > `git submodule sync`. Let's make that process easier.\n> \n> Right now, submodule.<name>.url might be the only thing that gets\n> synched down to .git/config of the submodule; we may not learn any\n> more things that needs \"edit in .gitmodules and then run sync\".  Can\n> we sately say that \"sync\" is now obsolete and what it has been used\n> for can now be done with \"set-url\"?  In other words, does \"set-url\"\n> makes \"sync\" unnecessary and deprecated?\n\n\"sync\" isn't deprecated quite yet. If upstream edits the .gitmodules and\nwe pull in the change, then we still need to run \"sync\" to update our\n.git/config.\n\n> \n> Or is it expected that we would learn more things end users can edit\n> in .gitmodules and run sync to propagate necessary pieces of\n> information down?  If so, do we want to add an extra command like\n> set-url for each of these new things, or do we tell users \"if you\n> are editing url, use set-url, otherwise edit .gitmodules and run\n> sync\"?  If the former, that would make the set of subcommands quite\n> noisy, and if the latter, the users need to learn two things,\n> i.e. it is not making it easier but harder to learn the system.\n\nI was running under the assumption that we weren't planning on adding\nnew information to .gitmodules. I don't think we'll be making changes to\nthe submodule file format without careful thought so _if_ that ever\ncomes up, we should discuss it then but I don't think it's a discussion\nthat's going to happen any time soon, if ever.\n\nEither way, though, the sync workflow isn't going away so users still\nneed to know how to do that (unfortunately). We'll just add a\nconvenience function on top to make people's lives easier but it's not\nstrictly _necessary_ to use \"set-url\".\n\n> \n> There is nothing _wrong_ to introduce the new subcommand per-se, but\n> given that the URL should not change that often, and due to above\n> concerns, I am not sure if I want to back this change.\n\nI think it changes often enough to cause problems. Seems like at least\n936 people on StackOverflow agree with me[1].\n\nI think that the problem is that it's a common enough use-case but not\ncommon enough that people often forget to \"sync\" after editing the\n.gitmodules. I know that it's bitten me the few times I've done this and\nI've had to go back to that SO post each time.\n\n[1]: https://stackoverflow.com/questions/913701/how-to-change-the-remote-repository-for-a-git-submodule\n"},{"id":"385295","messageId":"xmqqzhhe52hl.fsf@gitster-ct.c.googlers.com","threadId":"51869","inReplyTo":"20191030175817.GA5120@generichostname","subject":"Re: [PATCH v3] submodule: teach set-url subcommand","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-11-02T04:25:10Z","receivedAt":"2019-11-02T04:25:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Denton Liu <liu.denton@gmail.com> writes:\n\n> I think that the problem is that it's a common enough use-case but not\n> common enough that people often forget to \"sync\" after editing the\n> .gitmodules.\n\nWhich means that far from deprecating \"sync\", we should strive for\nimprinting the need for the use of the subcommand deeper in users'\nminds.  I wonder if it makes sense to make sure that .gitmodules\nfile starts with something like\n\n\t# Note that after updating this file, you may want to\n\t# run \"git submodule sync\" so that the URL for the remote\n\t# repository etc. are propagated down.\n\nwhen we create it (via, say \"git submodule add\")?  Or alternatively,\nwarn the users when \"git status\" notices a local modification, or\nsomething along that line?\n"}]}