The new rename subcommand does the followings:
1) Renames the remote.foo configuration section to remote.bar
2) Updates the remote.bar.fetch refspecs
3) Updates the branch.*.remote settings
4) Renames the tracking branches.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
Documentation/git-remote.txt | 6 +++
builtin-remote.c | 102 ++++++++++++++++++++++++++++++++++++++++++
t/t5505-remote.sh | 14 ++++++
3 files changed, 122 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index bb99810..4b5542a 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -11,6 +11,7 @@ SYNOPSIS
[verse]
'git remote' [-v | --verbose]
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git remote mv' <old> <new>
'git remote rm' <name>
'git remote show' [-n] <name>
'git remote prune' [-n | --dry-run] <name>
@@ -61,6 +62,11 @@ only makes sense in bare repositories. If a remote uses mirror
mode, furthermore, `git push` will always behave as if `\--mirror`
was passed.
+'mv'::
+
+Rename the remote named <old> to <new>. All remote tracking branches and
+configuration settings for the remote are updated.
+
'rm'::
Remove the remote named <name>. All remote tracking branches and
diff --git a/builtin-remote.c b/builtin-remote.c
index 6b3325d..4a23738 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -10,6 +10,7 @@
static const char * const builtin_remote_usage[] = {
"git remote",
"git remote add <name> <url>",
+ "git remote mv <old> <new>",
"git remote rm <name>",
"git remote show <name>",
"git remote prune <name>",
@@ -329,6 +330,105 @@ static int add_branch_for_removal(const char *refname,
return 0;
}
+struct rename_info {
+ const char *old;
+ const char *new;
+ struct string_list *remote_branches;
+};
+
+static int read_remote_branches(const char *refname,
+ const unsigned char *sha1, int flags, ...I think some non-c99 compilers would have issues with this run-time initialization from function arguments. Plus, what if argv doesn't have -brandon --
The new rename subcommand does the followings:
1) Renames the remote.foo configuration section to remote.bar
2) Updates the remote.bar.fetch refspecs
3) Updates the branch.*.remote settings
4) Renames the tracking branches.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
Hm true. Here is a corrected version.
Documentation/git-remote.txt | 6 ++
builtin-remote.c | 106 ++++++++++++++++++++++++++++++++++++++++++
t/t5505-remote.sh | 14 ++++++
3 files changed, 126 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index bb99810..4b5542a 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -11,6 +11,7 @@ SYNOPSIS
[verse]
'git remote' [-v | --verbose]
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git remote mv' <old> <new>
'git remote rm' <name>
'git remote show' [-n] <name>
'git remote prune' [-n | --dry-run] <name>
@@ -61,6 +62,11 @@ only makes sense in bare repositories. If a remote uses mirror
mode, furthermore, `git push` will always behave as if `\--mirror`
was passed.
+'mv'::
+
+Rename the remote named <old> to <new>. All remote tracking branches and
+configuration settings for the remote are updated.
+
'rm'::
Remove the remote named <name>. All remote tracking branches and
diff --git a/builtin-remote.c b/builtin-remote.c
index 6b3325d..8a54bca 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -10,6 +10,7 @@
static const char * const builtin_remote_usage[] = {
"git remote",
"git remote add <name> <url>",
+ "git remote mv <old> <new>",
"git remote rm <name>",
"git remote show <name>",
"git remote prune <name>",
@@ -329,6 +330,109 @@ static int add_branch_for_removal(const char *refname,
return 0;
}
+struct rename_info {
+ const char *old;
+ const char *new;
+ struct string_list *remote_branches;
+};
+
+static int read_remote_branches(const char ...I can't help but notice that the word "rename" appears all over the commit description and in the code, but not in the user interface. Maybe "rename" would be a better name for the command instead of (or in addition to) "mv"? -Peff --
The new rename subcommand does the followings:
1) Renames the remote.foo configuration section to remote.bar
2) Updates the remote.bar.fetch refspecs
3) Updates the branch.*.remote settings
4) Renames the tracking branches.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
I called it "mv" because of "rm" (it is not "remove") and
git-mv/git-add, but I don't think it's a problem if it's called
"rename". Here is an updated patch.
The function name is still "mv" because of rename(2).
Documentation/git-remote.txt | 6 ++
builtin-remote.c | 106 ++++++++++++++++++++++++++++++++++++++++++
t/t5505-remote.sh | 14 ++++++
3 files changed, 126 insertions(+), 0 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index bb99810..7b227b3 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -11,6 +11,7 @@ SYNOPSIS
[verse]
'git remote' [-v | --verbose]
'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git remote rename' <old> <new>
'git remote rm' <name>
'git remote show' [-n] <name>
'git remote prune' [-n | --dry-run] <name>
@@ -61,6 +62,11 @@ only makes sense in bare repositories. If a remote uses mirror
mode, furthermore, `git push` will always behave as if `\--mirror`
was passed.
+'rename'::
+
+Rename the remote named <old> to <new>. All remote tracking branches and
+configuration settings for the remote are updated.
+
'rm'::
Remove the remote named <name>. All remote tracking branches and
diff --git a/builtin-remote.c b/builtin-remote.c
index 6b3325d..106d6f6 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -10,6 +10,7 @@
static const char * const builtin_remote_usage[] = {
"git remote",
"git remote add <name> <url>",
+ "git remote rename <old> <new>",
"git remote rm <name>",
"git remote show <name>",
"git remote prune <name>",
@@ -329,6 +330,109 @@ static int add_branch_for_removal(const char ...Hmm, remote_get() can read from all three supported places that you can define remotes. Could you explain what happens if the old remote is read from say $GIT_DIR/remotes/origin and you are renaming it to "upstream" with "git remote rename origin upstream"? I suspect that if you record where you read the configuration from in "struct remote" and add necessary code to remove the original when rename.old is *not* coming from in-config definition, you would make it possible for repositories initialized with older git that has either $GIT_DIR/branches/origin or $GIT_DIR/remotes/origin to be migrated to the in-config format using "git remote rename origin origin". --
While trying to answer your question, I noticed that rename_ref()/delete_ref() did not really handled symrefs. Regarding rename_ref() (for users: git branch -m) I think you can't create symrefs in the refs/heads namespace without using plumbing, so most users are not affected. Regarding delete_ref() (for users: git update-ref --no-deref -d) in most repos you just have HEAD as symref and you never want to delete it, but in case the user asks for it, I think we just have to do so. Here are two patches to fix these issues (and in fact they will be required for git remote rename as well). Miklos Vajna (2): Fix git branch -m for symrefs. Fix git update-ref --no-deref -d. builtin-branch.c | 2 +- builtin-receive-pack.c | 2 +- builtin-remote.c | 4 +- builtin-reset.c | 2 +- builtin-send-pack.c | 2 +- builtin-tag.c | 2 +- builtin-update-ref.c | 8 ++++-- cache.h | 2 +- refs.c | 56 ++++++++++++++++++++++++++++++------------------ t/t1400-update-ref.sh | 7 ++++++ t/t3200-branch.sh | 9 +++++++ 11 files changed, 64 insertions(+), 32 deletions(-) --
This had two problems with symrefs. First, it copied the actual sha1
instead of the "pointer", second it failed to remove the old ref after a
successful rename.
Given that till now delete_ref() always dereferenced symrefs, a new
parameters has been introduced to delete_ref() to allow deleting refs
without a dereference.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
builtin-branch.c | 2 +-
builtin-receive-pack.c | 2 +-
builtin-remote.c | 4 +-
builtin-reset.c | 2 +-
builtin-send-pack.c | 2 +-
builtin-tag.c | 2 +-
builtin-update-ref.c | 2 +-
cache.h | 2 +-
refs.c | 56 ++++++++++++++++++++++++++++++------------------
t/t3200-branch.sh | 9 +++++++
10 files changed, 53 insertions(+), 30 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index 8d634ff..2b3613f 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -160,7 +160,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
continue;
}
- if (delete_ref(name, sha1)) {
+ if (delete_ref(name, sha1, 0)) {
error("Error deleting %sbranch '%s'", remote,
argv[i]);
ret = 1;
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 45e3cd9..ab5fa1c 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -224,7 +224,7 @@ static const char *update(struct command *cmd)
warning ("Allowing deletion of corrupt ref.");
old_sha1 = NULL;
}
- if (delete_ref(name, old_sha1)) {
+ if (delete_ref(name, old_sha1, 0)) {
error("failed to delete %s", name);
return "failed to delete";
}
diff --git a/builtin-remote.c b/builtin-remote.c
index a5883df..3f2113c 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -441,7 +441,7 @@ static int remove_branches(struct string_list *branches)
const char *refname = item->string;
unsigned char *sha1 = item->util;
- if (delete_ref(refname, ...Till now --no-deref was just ignored when deleting refs, fix this.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
builtin-update-ref.c | 8 +++++---
t/t1400-update-ref.sh | 7 +++++++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index d8f3142..378dc1b 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -13,7 +13,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
{
const char *refname, *oldval, *msg=NULL;
unsigned char sha1[20], oldsha1[20];
- int delete = 0, no_deref = 0;
+ int delete = 0, no_deref = 0, flags = 0;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
@@ -47,9 +47,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
if (oldval && *oldval && get_sha1(oldval, oldsha1))
die("%s: not a valid old SHA1", oldval);
+ if (no_deref)
+ flags = REF_NODEREF;
if (delete)
- return delete_ref(refname, oldval ? oldsha1 : NULL, 0);
+ return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
else
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
- no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
+ flags, DIE_ON_ERR);
}
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 04c2b16..8139cd6 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -75,6 +75,13 @@ test_expect_success "delete $m (by HEAD)" '
'
rm -f .git/$m
+cp -f .git/HEAD .git/HEAD.orig
+test_expect_success "delete symref without dereference" '
+ git update-ref --no-deref -d HEAD &&
+ ! test -f .git/HEAD
+'
+cp -f .git/HEAD.orig .git/HEAD
+
test_expect_success '(not) create HEAD with old sha1' "
test_must_fail git update-ref HEAD $A $B
"
--
1.6.0.2
--
Two variables flag vs flags is a bit confusing, isn't it? How about naming the new one "delopt" or something? The new variable "char *path" at the toplevel can be confined in the scope Possible bug in the context. When there is no reflog for the ref being renamed, lstat would fail; it doesn't feel right to have this S_ISLNK() Do we really need two calls to resolve_ref()? Your new call calls it without must-exist bit --- why? Immediately after that, the existing call will barf if it does not exist anyway. I agree it is good to have symref aware delete_ref(), but I am not sure supporting symref in rename_ref() is either needed or necessarily a good idea. You also need to worry about a symref pointing at a branch yet to be born. In the meantime, I think we should just check (flag & REF_ISSYMREF) after the existing resolve_ref() we can see in the context above, and error out saying you cannot rename a symref, and do nothing else. --
Just having
if (!symref)
return error("refname %s not found", oldref);
first looks weird, given that the error message is not "refname %s is
That is currently not supported and the error message of 'git branch -m'
is (in case foo points to refs/heads/bar and bar is not yet born):
error: refname refs/heads/foo not found
fatal: Branch rename failed
A symref-aware rename_ref() is needed by git remove rename, since it
typically does origin/HEAD -> upstream/HEAD symref renames there.
Of course you can say that this should be handled by git-remote itself,
without using rename_ref() but that not seem to be a good solution to
me. (Workaround in the wrong layer, instead of a solution in a good
one.)
[1] I mean, I have a real-world scenario (git remove rename) for "why
renaming a symref is a good idea", but I don't think renaming a ref
pointing to a yet-to-be-born ref has any real world users.
Miklos Vajna (3):
Fix git branch -m for symrefs.
rename_ref(): handle the case when the reflog of a ref does not exist
Fix git update-ref --no-deref -d.
builtin-branch.c | 2 +-
builtin-receive-pack.c | 2 +-
builtin-remote.c | 4 +-
builtin-reset.c | 2 +-
builtin-send-pack.c | 2 +-
builtin-tag.c | 2 +-
builtin-update-ref.c | 8 ++++--
cache.h | 2 +-
refs.c | 61 +++++++++++++++++++++++++++++------------------
t/t1400-update-ref.sh | 7 +++++
t/t3200-branch.sh | 9 +++++++
11 files changed, 67 insertions(+), 34 deletions(-)
Also available in the 'symref-mv' branch of 'git://repo.or.cz/git/vmiklos.git'.
--
This had two problems with symrefs. First, it copied the actual sha1
instead of the "pointer", second it failed to remove the old ref after a
successful rename.
Given that till now delete_ref() always dereferenced symrefs, a new
parameters has been introduced to delete_ref() to allow deleting refs
without a dereference.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
builtin-branch.c | 2 +-
builtin-receive-pack.c | 2 +-
builtin-remote.c | 4 +-
builtin-reset.c | 2 +-
builtin-send-pack.c | 2 +-
builtin-tag.c | 2 +-
builtin-update-ref.c | 2 +-
cache.h | 2 +-
refs.c | 59 ++++++++++++++++++++++++++++++------------------
t/t3200-branch.sh | 9 +++++++
10 files changed, 55 insertions(+), 31 deletions(-)
diff --git a/builtin-branch.c b/builtin-branch.c
index 8d634ff..2b3613f 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -160,7 +160,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
continue;
}
- if (delete_ref(name, sha1)) {
+ if (delete_ref(name, sha1, 0)) {
error("Error deleting %sbranch '%s'", remote,
argv[i]);
ret = 1;
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 45e3cd9..ab5fa1c 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -224,7 +224,7 @@ static const char *update(struct command *cmd)
warning ("Allowing deletion of corrupt ref.");
old_sha1 = NULL;
}
- if (delete_ref(name, old_sha1)) {
+ if (delete_ref(name, old_sha1, 0)) {
error("failed to delete %s", name);
return "failed to delete";
}
diff --git a/builtin-remote.c b/builtin-remote.c
index df2be06..e396a3a 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -337,7 +337,7 @@ static int remove_branches(struct string_list *branches)
const char *refname = item->string;
unsigned char *sha1 = item->util;
- if (delete_ref(refname, ...We tried to check if a reflog of a ref is a symlink without first checking if it exists, which is a bug. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- refs.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/refs.c b/refs.c index 70c0967..3c39a31 100644 --- a/refs.c +++ b/refs.c @@ -975,7 +975,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) const char *symref = NULL; int is_symref = 0; - if (S_ISLNK(loginfo.st_mode)) + if (log && S_ISLNK(loginfo.st_mode)) return error("reflog for %s is a symlink", oldref); symref = resolve_ref(oldref, orig_sha1, 1, &flag); -- 1.6.0.2 --
Till now --no-deref was just ignored when deleting refs, fix this.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
builtin-update-ref.c | 8 +++++---
t/t1400-update-ref.sh | 7 +++++++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index d8f3142..378dc1b 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -13,7 +13,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
{
const char *refname, *oldval, *msg=NULL;
unsigned char sha1[20], oldsha1[20];
- int delete = 0, no_deref = 0;
+ int delete = 0, no_deref = 0, flags = 0;
struct option options[] = {
OPT_STRING( 'm', NULL, &msg, "reason", "reason of the update"),
OPT_BOOLEAN('d', NULL, &delete, "deletes the reference"),
@@ -47,9 +47,11 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
if (oldval && *oldval && get_sha1(oldval, oldsha1))
die("%s: not a valid old SHA1", oldval);
+ if (no_deref)
+ flags = REF_NODEREF;
if (delete)
- return delete_ref(refname, oldval ? oldsha1 : NULL, 0);
+ return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
else
return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
- no_deref ? REF_NODEREF : 0, DIE_ON_ERR);
+ flags, DIE_ON_ERR);
}
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 04c2b16..8139cd6 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -75,6 +75,13 @@ test_expect_success "delete $m (by HEAD)" '
'
rm -f .git/$m
+cp -f .git/HEAD .git/HEAD.orig
+test_expect_success "delete symref without dereference" '
+ git update-ref --no-deref -d HEAD &&
+ ! test -f .git/HEAD
+'
+cp -f .git/HEAD.orig .git/HEAD
+
test_expect_success '(not) create HEAD with old sha1' "
test_must_fail git update-ref HEAD $A $B
"
--
1.6.0.2
--
The new rename subcommand does the followings: 1) Renames the remote.foo configuration section to remote.bar 2) Updates the remote.bar.fetch refspecs 3) Updates the branch.*.remote settings 4) Renames the tracking branches: renames the normal refs and rewrites the symrefs to point to the new refs. Signed-off-by: Miklos Vajna <vmiklos@frugalware.org> --- Currently it dies because it can't rename config section 'remote.origin' Yes, that's possible. I think the patch is already large enough that it would be better to do it as a separate patch, but I like the idea. One important step is that currently we have to care about the remote.upstream.fetch variable, but once migration is supported, we have to pay attention to remote.upstream.url/push as well. In the meantime here is an updated patch which applies on top of mv/maint-branch-m-symref. However, it is not meant for 'maint', of course. :) The old version did not "rename" (in fact it is not just a rename but it replaces origin with upstream in the contents) symrefs properly, now the testcases are extended to check for this, too. Documentation/git-remote.txt | 6 ++ builtin-remote.c | 153 ++++++++++++++++++++++++++++++++++++++++++ t/t5505-remote.sh | 15 ++++ 3 files changed, 174 insertions(+), 0 deletions(-) diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index bb99810..7b227b3 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -11,6 +11,7 @@ SYNOPSIS [verse] 'git remote' [-v | --verbose] 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url> +'git remote rename' <old> <new> 'git remote rm' <name> 'git remote show' [-n] <name> 'git remote prune' [-n | --dry-run] <name> @@ -61,6 +62,11 @@ only makes sense in bare repositories. If a remote uses mirror mode, furthermore, `git push` will always behave as if `\--mirror` was passed. +'rename':: + +Rename the remote named <old> to ...
Here are 4 patches to implement this + add the related testcases/documentation. Miklos Vajna (4): remote: add a new 'origin' variable to the struct git-remote rename: support remotes->config migration git-remote rename: support branches->config migration git-remote: document the migration feature of the rename subcommand Documentation/git-remote.txt | 4 ++++ builtin-remote.c | 35 +++++++++++++++++++++++++++++++++++ remote.c | 3 +++ remote.h | 7 +++++++ t/t5505-remote.sh | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 0 deletions(-) --
This allows one to track where was the remote's original source, so that
it's possible to decide if it makes sense to migrate it to the config
format or not.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
remote.c | 3 +++
remote.h | 7 +++++++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/remote.c b/remote.c
index e530a21..cbb3e48 100644
--- a/remote.c
+++ b/remote.c
@@ -201,6 +201,7 @@ static void read_remotes_file(struct remote *remote)
if (!f)
return;
+ remote->origin = REMOTE_REMOTES;
while (fgets(buffer, BUF_SIZE, f)) {
int value_list;
char *s, *p;
@@ -261,6 +262,7 @@ static void read_branches_file(struct remote *remote)
s++;
if (!*s)
return;
+ remote->origin = REMOTE_BRANCHES;
p = s + strlen(s);
while (isspace(p[-1]))
*--p = 0;
@@ -350,6 +352,7 @@ static int handle_config(const char *key, const char *value, void *cb)
if (!subkey)
return error("Config with no key for remote %s", name);
remote = make_remote(name, subkey - name);
+ remote->origin = REMOTE_CONFIG;
if (!strcmp(subkey, ".mirror"))
remote->mirror = git_config_bool(key, value);
else if (!strcmp(subkey, ".skipdefaultupdate"))
diff --git a/remote.h b/remote.h
index d2e170c..a46a5be 100644
--- a/remote.h
+++ b/remote.h
@@ -1,8 +1,15 @@
#ifndef REMOTE_H
#define REMOTE_H
+enum {
+ REMOTE_CONFIG,
+ REMOTE_REMOTES,
+ REMOTE_BRANCHES
+};
+
struct remote {
const char *name;
+ int origin;
const char **url;
int url_nr;
--
1.6.0.2
--
This patch makes it possible to migrate a remote stored in a
$GIT_DIR/remotes/nick file to the configuration file format.
Signed-off-by: Miklos Vajna <vmiklos@frugalware.org>
---
builtin-remote.c | 33 +++++++++++++++++++++++++++++++++
t/t5505-remote.sh | 21 +++++++++++++++++++++
2 files changed, 54 insertions(+), 0 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index 1ca6cdb..d9d0ba3 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -359,6 +359,36 @@ static int read_remote_branches(const char *refname,
return 0;
}
+static int migrate_file(struct remote *remote)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int i;
+ char *path = NULL;
+
+ strbuf_addf(&buf, "remote.%s.url", remote->name);
+ for (i = 0; i < remote->url_nr; i++)
+ if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0))
+ return error("Could not append '%s' to '%s'",
+ remote->url[i], buf.buf);
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.push", remote->name);
+ for (i = 0; i < remote->push_refspec_nr; i++)
+ if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0))
+ return error("Could not append '%s' to '%s'",
+ remote->push_refspec[i], buf.buf);
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.fetch", remote->name);
+ for (i = 0; i < remote->fetch_refspec_nr; i++)
+ if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0))
+ return error("Could not append '%s' to '%s'",
+ remote->fetch_refspec[i], buf.buf);
+ if (remote->origin == REMOTE_REMOTES)
+ path = git_path("remotes/%s", remote->name);
+ if (path && unlink(path))
+ warning("failed to remove '%s'", path);
+ return 0;
+}
+
static int mv(int argc, const char **argv)
{
struct option options[] = {
@@ -381,6 +411,9 @@ static int mv(int argc, const char **argv)
if (!oldremote)
die("No such remote: %s", rename.old);
+ if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG)
+ return migrate_file(oldremote);
+
...