summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-remote.txt17
-rw-r--r--builtin/remote.c140
-rwxr-xr-xt/t5505-remote.sh125
3 files changed, 228 insertions, 54 deletions
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index cb103c8b6f..bdd0305c29 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -15,9 +15,9 @@ SYNOPSIS
'git remote remove' <name>
'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)
'git remote set-branches' [--add] <name> <branch>...
-'git remote set-url' [--push] <name> <newurl> [<oldurl>]
-'git remote set-url --add' [--push] <name> <newurl>
-'git remote set-url --delete' [--push] <name> <url>
+'git remote set-url' [--both | --fetch | --push] <name> <newurl> [<oldurl>]
+'git remote set-url' [--both | --fetch | --push] '--add' <name> <newurl>
+'git remote set-url' [--both | --fetch | --push] '--delete' <name> <url>
'git remote' [-v | --verbose] 'show' [-n] <name>...
'git remote prune' [-n | --dry-run] <name>...
'git remote' [-v | --verbose] 'update' [-p | --prune] [(<group> | <remote>)...]
@@ -134,7 +134,16 @@ Changes URL remote points to. Sets first URL remote points to matching
regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If
<oldurl> doesn't match any URL, error occurs and nothing is changed.
+
-With '--push', push URLs are manipulated instead of fetch URLs.
+With '--both', both the fetch and push URLs are manipulated.
++
+With '--fetch', only fetch URLs are manipulated.
++
+With '--push', only push URLs are manipulated.
++
+If none of the '--both', '--fetch' or --push' options are given, then
+'--both' applies only if no push URL was set before. Otherwise '--fetch'
+is assumed for historical reasons. This default may change in the
+future to '--both' to avoid surprises depending on the configuration.
+
With '--add', instead of changing some URL, new URL is added.
+
diff --git a/builtin/remote.c b/builtin/remote.c
index 7f28f92a37..a250b23e0e 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -18,9 +18,9 @@ static const char * const builtin_remote_usage[] = {
N_("git remote prune [-n | --dry-run] <name>"),
N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
N_("git remote set-branches [--add] <name> <branch>..."),
- N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
- N_("git remote set-url --add <name> <newurl>"),
- N_("git remote set-url --delete <name> <url>"),
+ N_("git remote set-url [--both | --fetch | --push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url [--both | --fetch | --push] --add <name> <newurl>"),
+ N_("git remote set-url [--both | --fetch | --push] --delete <name> <url>"),
NULL
};
@@ -66,9 +66,9 @@ static const char * const builtin_remote_update_usage[] = {
};
static const char * const builtin_remote_seturl_usage[] = {
- N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
- N_("git remote set-url --add <name> <newurl>"),
- N_("git remote set-url --delete <name> <url>"),
+ N_("git remote set-url [--both | --fetch | --push] <name> <newurl> [<oldurl>]"),
+ N_("git remote set-url [--both | --fetch | --push] --add <name> <newurl>"),
+ N_("git remote set-url [--both | --fetch | --push] --delete <name> <url>"),
NULL
};
@@ -1503,21 +1503,35 @@ static int set_branches(int argc, const char **argv)
return set_remote_branches(argv[0], argv + 1, add_mode);
}
+#define MODIFY_TYPE_FETCH (1 << 0)
+#define MODIFY_TYPE_PUSH (1 << 1)
+#define MODIFY_TYPE_BOTH (MODIFY_TYPE_FETCH | MODIFY_TYPE_PUSH)
+#define MODIFY_TYPE_HISTORIC (MODIFY_TYPE_FETCH | (1 << 2))
+
static int set_url(int argc, const char **argv)
{
- int i, push_mode = 0, add_mode = 0, delete_mode = 0;
+ int i, add_mode = 0, delete_mode = 0;
+ int modify_type = MODIFY_TYPE_HISTORIC;
int matches = 0, negative_matches = 0;
const char *remotename = NULL;
const char *newurl = NULL;
const char *oldurl = NULL;
struct remote *remote;
regex_t old_regex;
- const char **urlset;
- int urlset_nr;
- struct strbuf name_buf = STRBUF_INIT;
+ struct strbuf name_buf_fetch = STRBUF_INIT;
+ struct strbuf name_buf_push = STRBUF_INIT;
struct option options[] = {
- OPT_BOOL('\0', "push", &push_mode,
- N_("manipulate push URLs")),
+ OPT_GROUP(""),
+ OPT_SET_INT('\0', "fetch", &modify_type,
+ N_("manipulate just fetch URLs"),
+ MODIFY_TYPE_FETCH),
+ OPT_SET_INT('\0', "push", &modify_type,
+ N_("manipulate just push URLs"),
+ MODIFY_TYPE_PUSH),
+ OPT_SET_INT('\0', "both", &modify_type,
+ N_("manipulate both push and fetch URLs"),
+ MODIFY_TYPE_BOTH),
+ OPT_GROUP(""),
OPT_BOOL('\0', "add", &add_mode,
N_("add URL")),
OPT_BOOL('\0', "delete", &delete_mode,
@@ -1535,7 +1549,8 @@ static int set_url(int argc, const char **argv)
remotename = argv[1];
newurl = argv[2];
- if (argc > 3)
+ /* The old URL is only meaningful for the primary non-set operation. */
+ if (argc > 3 && !add_mode && !delete_mode)
oldurl = argv[3];
if (delete_mode)
@@ -1545,47 +1560,72 @@ static int set_url(int argc, const char **argv)
die(_("No such remote '%s'"), remotename);
remote = remote_get(remotename);
- if (push_mode) {
- strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
- urlset = remote->pushurl;
- urlset_nr = remote->pushurl_nr;
- } else {
- strbuf_addf(&name_buf, "remote.%s.url", remotename);
- urlset = remote->url;
- urlset_nr = remote->url_nr;
+ strbuf_addf(&name_buf_fetch, "remote.%s.url", remotename);
+ strbuf_addf(&name_buf_push, "remote.%s.pushurl", remotename);
+
+ if (oldurl && !add_mode) {
+ /* Old URL specified, or deletion. Demand that one matches. */
+ if (regcomp(&old_regex, oldurl, REG_EXTENDED))
+ die(_("Invalid old URL pattern: %s"), oldurl);
+
+ if (modify_type & MODIFY_TYPE_FETCH)
+ for (i = 0; i < remote->url_nr; i++)
+ if (!regexec(&old_regex, remote->url[i], 0, NULL, 0))
+ matches++;
+ else
+ negative_matches++;
+ if (delete_mode && !negative_matches && modify_type & MODIFY_TYPE_FETCH)
+ die(_("Will not delete all non-push URLs"));
+ if (modify_type & MODIFY_TYPE_PUSH)
+ for (i = 0; i < remote->pushurl_nr; i++)
+ if (!regexec(&old_regex, remote->pushurl[i], 0, NULL, 0))
+ matches++;
+ else
+ negative_matches++;
+ if (!delete_mode && !matches)
+ die(_("No such URL found: %s"), oldurl);
+
+ regfree(&old_regex);
}
- /* Special cases that add new entry. */
- if ((!oldurl && !delete_mode) || add_mode) {
- if (add_mode)
- git_config_set_multivar(name_buf.buf, newurl,
- "^$", 0);
- else
- git_config_set(name_buf.buf, newurl);
- strbuf_release(&name_buf);
- return 0;
+ /* If --fetch was explicitly given, then ensure that the push
+ * URL does not change by copying the fetch URL to it. */
+ if (modify_type == MODIFY_TYPE_FETCH &&
+ remote->pushurl_nr == 0 && remote->url_nr > 0)
+ for (i = 0; i < remote->url_nr; i++)
+ git_config_set_multivar(name_buf_push.buf,
+ remote->url[i], "^$", 0);
+
+ /* Set the new entry value (not a --add or --delete operation). */
+ if (!add_mode && !delete_mode && !oldurl) {
+ if (modify_type & MODIFY_TYPE_FETCH)
+ git_config_set(name_buf_fetch.buf, newurl);
+ /* URLs will be the same, so remove pushurl. */
+ if (modify_type == MODIFY_TYPE_BOTH)
+ git_config_set(name_buf_push.buf, NULL);
+ else if (modify_type == MODIFY_TYPE_PUSH)
+ git_config_set(name_buf_push.buf, newurl);
+
+ goto cleanup_ok;
}
- /* Old URL specified. Demand that one matches. */
- if (regcomp(&old_regex, oldurl, REG_EXTENDED))
- die(_("Invalid old URL pattern: %s"), oldurl);
-
- for (i = 0; i < urlset_nr; i++)
- if (!regexec(&old_regex, urlset[i], 0, NULL, 0))
- matches++;
- else
- negative_matches++;
- if (!delete_mode && !matches)
- die(_("No such URL found: %s"), oldurl);
- if (delete_mode && !negative_matches && !push_mode)
- die(_("Will not delete all non-push URLs"));
-
- regfree(&old_regex);
-
- if (!delete_mode)
- git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
- else
- git_config_set_multivar(name_buf.buf, NULL, oldurl, 1);
+ /* Set operations (--add, --delete) or change request (oldurl given). */
+ if (delete_mode) {
+ if (modify_type & MODIFY_TYPE_FETCH)
+ git_config_set_multivar(name_buf_fetch.buf, NULL, oldurl, 1);
+ if (modify_type & MODIFY_TYPE_PUSH)
+ git_config_set_multivar(name_buf_push.buf, NULL, oldurl, 1);
+ } else {
+ if (add_mode) /* Do not replace oldurl, but add a new one. */
+ oldurl = "^$";
+ if (modify_type & MODIFY_TYPE_FETCH)
+ git_config_set_multivar(name_buf_fetch.buf, newurl, oldurl, 0);
+ if (modify_type & MODIFY_TYPE_PUSH)
+ git_config_set_multivar(name_buf_push.buf, newurl, oldurl, 0);
+ }
+cleanup_ok:
+ strbuf_release(&name_buf_fetch);
+ strbuf_release(&name_buf_push);
return 0;
}
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index ac79dd915d..390281aa36 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -961,6 +961,59 @@ test_expect_success 'remote set-url --push zot' '
cmp expect actual
'
+test_expect_success 'remote set-url --fetch zox' '
+ git remote set-url --fetch someremote zox &&
+ echo zox >expect &&
+ echo "YYY" >>expect &&
+ echo zot >>expect &&
+ git config --get-all remote.someremote.url >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.pushurl >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --both foo' '
+ git remote set-url --both someremote foo &&
+ echo "YYY" >expect &&
+ echo foo >>expect &&
+ test_must_fail git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --delete --push foo' '
+ git remote set-url --delete --push someremote foo &&
+ echo "YYY" >expect &&
+ echo foo >>expect &&
+ test_must_fail git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --push zot' '
+ git remote set-url --push someremote zot &&
+ echo zot >expect &&
+ echo "YYY" >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --fetch baz foo' '
+ git remote set-url --fetch someremote baz foo &&
+ echo zot >expect &&
+ echo "YYY" >>expect &&
+ echo baz >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
test_expect_success 'remote set-url --push qux zot' '
git remote set-url --push someremote qux zot &&
echo qux >expect &&
@@ -1091,6 +1144,78 @@ test_expect_success 'remote set-url --delete baz' '
cmp expect actual
'
+test_expect_success 'remote set-url --fetch --add bar' '
+ git remote set-url --fetch --add someremote bar &&
+ echo ccc >expect &&
+ echo "YYY" >>expect &&
+ echo ccc >>expect &&
+ echo bar >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --both --add foo' '
+ git remote set-url --both --add someremote foo &&
+ echo ccc >expect &&
+ echo foo >>expect &&
+ echo "YYY" >>expect &&
+ echo ccc >>expect &&
+ echo bar >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --both --delete ccc' '
+ git remote set-url --both --delete someremote ccc &&
+ echo foo >expect &&
+ echo "YYY" >>expect &&
+ echo bar >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --fetch --delete bar' '
+ git remote set-url --fetch --delete someremote bar &&
+ echo foo >expect &&
+ echo "YYY" >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --push --add baz' '
+ git remote set-url --push --add someremote baz &&
+ echo foo >expect &&
+ echo baz >>expect &&
+ echo "YYY" >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
+test_expect_success 'remote set-url --push --delete foo' '
+ git remote set-url --push --delete someremote foo &&
+ echo baz >expect &&
+ echo "YYY" >>expect &&
+ echo foo >>expect &&
+ git config --get-all remote.someremote.pushurl >actual &&
+ echo "YYY" >>actual &&
+ git config --get-all remote.someremote.url >>actual &&
+ cmp expect actual
+'
+
test_expect_success 'extra args: setup' '
# add a dummy origin so that this does not trigger failure
git remote add origin .