X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-remote.c;h=abc8dd8389be4a51b467b4f6d4f74e2037d65423;hb=58f37f3c07ef4869f88c79b61f11829bebf7bf40;hp=e396a3ac9055aa91d0f808abb196fb6ea9a99a29;hpb=a9645b780b698703cd7dee25051d6ce39b0544c6;p=git.git diff --git a/builtin-remote.c b/builtin-remote.c index e396a3ac9..abc8dd838 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -8,12 +8,13 @@ #include "refs.h" static const char * const builtin_remote_usage[] = { - "git remote", - "git remote add ", + "git remote [-v | --verbose]", + "git remote add [-t ] [-m ] [-f] [--mirror] ", + "git remote rename ", "git remote rm ", - "git remote show ", - "git remote prune ", - "git remote update [group]", + "git remote show [-n] ", + "git remote prune [-n | --dry-run] ", + "git remote [-v | --verbose] update [group]", NULL }; @@ -41,7 +42,11 @@ static int opt_parse_track(const struct option *opt, const char *arg, int not) static int fetch_remote(const char *name) { - const char *argv[] = { "fetch", name, NULL }; + const char *argv[] = { "fetch", name, NULL, NULL }; + if (verbose) { + argv[1] = "-v"; + argv[2] = name; + } printf("Updating %s\n", name); if (run_command_v_opt(argv, RUN_GIT_CMD)) return error("Could not fetch %s", name); @@ -320,7 +325,7 @@ static int add_branch_for_removal(const char *refname, /* make sure that symrefs are deleted */ if (flags & REF_ISSYMREF) - return unlink(git_path(refname)); + return unlink(git_path("%s", refname)); item = string_list_append(refname, branches->branches); item->util = xmalloc(20); @@ -329,6 +334,191 @@ 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, void *cb_data) +{ + struct rename_info *rename = cb_data; + struct strbuf buf = STRBUF_INIT; + struct string_list_item *item; + int flag; + unsigned char orig_sha1[20]; + const char *symref; + + strbuf_addf(&buf, "refs/remotes/%s", rename->old); + if(!prefixcmp(refname, buf.buf)) { + item = string_list_append(xstrdup(refname), rename->remote_branches); + symref = resolve_ref(refname, orig_sha1, 1, &flag); + if (flag & REF_ISSYMREF) + item->util = xstrdup(symref); + else + item->util = NULL; + } + + 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); + else if (remote->origin == REMOTE_BRANCHES) + path = git_path("branches/%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[] = { + OPT_END() + }; + struct remote *oldremote, *newremote; + struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT; + struct string_list remote_branches = { NULL, 0, 0, 0 }; + struct rename_info rename; + int i; + + if (argc != 3) + usage_with_options(builtin_remote_usage, options); + + rename.old = argv[1]; + rename.new = argv[2]; + rename.remote_branches = &remote_branches; + + oldremote = remote_get(rename.old); + if (!oldremote) + die("No such remote: %s", rename.old); + + if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG) + return migrate_file(oldremote); + + newremote = remote_get(rename.new); + if (newremote && (newremote->url_nr > 1 || newremote->fetch_refspec_nr)) + die("remote %s already exists.", rename.new); + + strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new); + if (!valid_fetch_refspec(buf.buf)) + die("'%s' is not a valid remote name", rename.new); + + strbuf_reset(&buf); + strbuf_addf(&buf, "remote.%s", rename.old); + strbuf_addf(&buf2, "remote.%s", rename.new); + if (git_config_rename_section(buf.buf, buf2.buf) < 1) + return error("Could not rename config section '%s' to '%s'", + buf.buf, buf2.buf); + + strbuf_reset(&buf); + strbuf_addf(&buf, "remote.%s.fetch", rename.new); + if (git_config_set_multivar(buf.buf, NULL, NULL, 1)) + return error("Could not remove config section '%s'", buf.buf); + for (i = 0; i < oldremote->fetch_refspec_nr; i++) { + char *ptr; + + strbuf_reset(&buf2); + strbuf_addstr(&buf2, oldremote->fetch_refspec[i]); + ptr = strstr(buf2.buf, rename.old); + if (ptr) + strbuf_splice(&buf2, ptr-buf2.buf, strlen(rename.old), + rename.new, strlen(rename.new)); + if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) + return error("Could not append '%s'", buf.buf); + } + + read_branches(); + for (i = 0; i < branch_list.nr; i++) { + struct string_list_item *item = branch_list.items + i; + struct branch_info *info = item->util; + if (info->remote && !strcmp(info->remote, rename.old)) { + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.remote", item->string); + if (git_config_set(buf.buf, rename.new)) { + return error("Could not set '%s'", buf.buf); + } + } + } + + /* + * First remove symrefs, then rename the rest, finally create + * the new symrefs. + */ + for_each_ref(read_remote_branches, &rename); + for (i = 0; i < remote_branches.nr; i++) { + struct string_list_item *item = remote_branches.items + i; + int flag = 0; + unsigned char sha1[20]; + const char *symref; + + symref = resolve_ref(item->string, sha1, 1, &flag); + if (!(flag & REF_ISSYMREF)) + continue; + if (delete_ref(item->string, NULL, REF_NODEREF)) + die("deleting '%s' failed", item->string); + } + for (i = 0; i < remote_branches.nr; i++) { + struct string_list_item *item = remote_branches.items + i; + + if (item->util) + continue; + strbuf_reset(&buf); + strbuf_addstr(&buf, item->string); + strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old), + rename.new, strlen(rename.new)); + strbuf_reset(&buf2); + strbuf_addf(&buf2, "remote: renamed %s to %s", + item->string, buf.buf); + if (rename_ref(item->string, buf.buf, buf2.buf)) + die("renaming '%s' failed", item->string); + } + for (i = 0; i < remote_branches.nr; i++) { + struct string_list_item *item = remote_branches.items + i; + + if (!item->util) + continue; + strbuf_reset(&buf); + strbuf_addstr(&buf, item->string); + strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old), + rename.new, strlen(rename.new)); + strbuf_reset(&buf2); + strbuf_addstr(&buf2, item->util); + strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old), + rename.new, strlen(rename.new)); + strbuf_reset(&buf3); + strbuf_addf(&buf3, "remote: renamed %s to %s", + item->string, buf.buf); + if (create_symref(buf.buf, buf2.buf, buf3.buf)) + die("creating '%s' failed", buf.buf); + } + return 0; +} + static int remove_branches(struct string_list *branches) { int i, result = 0; @@ -584,7 +774,7 @@ static int get_one_remote_for_update(struct remote *remote, void *priv) { struct string_list *list = priv; if (!remote->skip_default_update) - string_list_append(xstrdup(remote->name), list); + string_list_append(remote->name, list); return 0; } @@ -695,6 +885,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix) result = show_all(); else if (!strcmp(argv[0], "add")) result = add(argc, argv); + else if (!strcmp(argv[0], "rename")) + result = mv(argc, argv); else if (!strcmp(argv[0], "rm")) result = rm(argc, argv); else if (!strcmp(argv[0], "show"))