X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-clone.c;h=5b40e07ba7f13950078d36a48c2cb3f6e6c3c2c4;hb=58245a5e40e1f95976a4f0fd53c2e8d3a1c3c763;hp=e086a40b41810c30a4f5228daa4e38857dae84d5;hpb=372c767610c4e4d7f4832d037ac51a62a59875a3;p=git.git diff --git a/builtin-clone.c b/builtin-clone.c index e086a40b4..5b40e07ba 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -33,7 +33,7 @@ static const char * const builtin_clone_usage[] = { NULL }; -static int option_quiet, option_no_checkout, option_bare; +static int option_quiet, option_no_checkout, option_bare, option_mirror; static int option_local, option_no_hardlinks, option_shared; static char *option_template, *option_reference, *option_depth; static char *option_origin = NULL; @@ -45,6 +45,8 @@ static struct option builtin_clone_options[] = { "don't create a checkout"), OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"), OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"), + OPT_BOOLEAN(0, "mirror", &option_mirror, + "create a mirror repository (implies bare)"), OPT_BOOLEAN('l', "local", &option_local, "to clone from a local repository"), OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks, @@ -56,7 +58,7 @@ static struct option builtin_clone_options[] = { OPT_STRING(0, "reference", &option_reference, "repo", "reference repository"), OPT_STRING('o', "origin", &option_origin, "branch", - "use instead or 'origin' to track upstream"), + "use instead of 'origin' to track upstream"), OPT_STRING('u', "upload-pack", &option_upload_pack, "path", "path to git-upload-pack on the remote"), OPT_STRING(0, "depth", &option_depth, "depth", @@ -93,7 +95,7 @@ static char *get_repo_path(const char *repo, int *is_bundle) return NULL; } -static char *guess_dir_name(const char *repo, int is_bundle) +static char *guess_dir_name(const char *repo, int is_bundle, int is_bare) { const char *end = repo + strlen(repo), *start; @@ -129,6 +131,12 @@ static char *guess_dir_name(const char *repo, int is_bundle) end -= 4; } + if (is_bare) { + char *result = xmalloc(end - start + 5); + sprintf(result, "%.*s.git", (int)(end - start), start); + return result; + } + return xstrndup(start, end - start); } @@ -139,6 +147,15 @@ static int is_directory(const char *path) return !stat(path, &buf) && S_ISDIR(buf.st_mode); } +static void strip_trailing_slashes(char *dir) +{ + char *end = dir + strlen(dir); + + while (dir < end - 1 && is_dir_sep(end[-1])) + end--; + *end = '\0'; +} + static void setup_reference(const char *repo) { const char *ref_git; @@ -322,7 +339,8 @@ static struct ref *write_remote_refs(const struct ref *refs, struct ref *r; get_fetch_map(refs, refspec, &tail, 0); - get_fetch_map(refs, tag_refspec, &tail, 0); + if (!option_mirror) + get_fetch_map(refs, tag_refspec, &tail, 0); for (r = local_refs; r; r = r->next) add_extra_ref(r->peer_ref->name, r->old_sha1, 0); @@ -345,6 +363,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) char branch_top[256], key[256], value[256]; struct strbuf reflog_msg; struct transport *transport = NULL; + char *src_ref_prefix = "refs/heads/"; struct refspec refspec; @@ -359,6 +378,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (option_no_hardlinks) use_local_hardlinks = 0; + if (option_mirror) + option_bare = 1; + if (option_bare) { if (option_origin) die("--bare and --origin %s options are incompatible.", @@ -374,7 +396,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path = get_repo_path(repo_name, &is_bundle); if (path) - repo = path; + repo = xstrdup(make_nonrelative_path(repo_name)); else if (!strchr(repo_name, ':')) repo = xstrdup(make_absolute_path(repo_name)); else @@ -383,7 +405,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (argc == 2) dir = xstrdup(argv[1]); else - dir = guess_dir_name(repo_name, is_bundle); + dir = guess_dir_name(repo_name, is_bundle, option_bare); + strip_trailing_slashes(dir); if (!stat(dir, &buf)) die("destination directory '%s' already exists.", dir); @@ -409,10 +432,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (!option_bare) { junk_work_tree = work_tree; if (safe_create_leading_directories_const(work_tree) < 0) - die("could not create leading directories of '%s'", - work_tree); + die("could not create leading directories of '%s': %s", + work_tree, strerror(errno)); if (mkdir(work_tree, 0755)) - die("could not create work tree dir '%s'.", work_tree); + die("could not create work tree dir '%s': %s.", + work_tree, strerror(errno)); set_git_work_tree(work_tree); } junk_git_dir = git_dir; @@ -440,26 +464,36 @@ int cmd_clone(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); if (option_bare) { - strcpy(branch_top, "refs/heads/"); + if (option_mirror) + src_ref_prefix = "refs/"; + strcpy(branch_top, src_ref_prefix); git_config_set("core.bare", "true"); } else { snprintf(branch_top, sizeof(branch_top), "refs/remotes/%s/", option_origin); + } + if (option_mirror || !option_bare) { /* Configure the remote */ + if (option_mirror) { + snprintf(key, sizeof(key), + "remote.%s.mirror", option_origin); + git_config_set(key, "true"); + } + snprintf(key, sizeof(key), "remote.%s.url", option_origin); git_config_set(key, repo); snprintf(key, sizeof(key), "remote.%s.fetch", option_origin); snprintf(value, sizeof(value), - "+refs/heads/*:%s*", branch_top); + "+%s*:%s*", src_ref_prefix, branch_top); git_config_set_multivar(key, value, "^$", 0); } refspec.force = 0; refspec.pattern = 1; - refspec.src = "refs/heads/"; + refspec.src = src_ref_prefix; refspec.dst = branch_top; if (path && !is_bundle)