summaryrefslogtreecommitdiff
path: root/builtin-clone.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin-clone.c')
-rw-r--r--builtin-clone.c37
1 files changed, 30 insertions, 7 deletions
diff --git a/builtin-clone.c b/builtin-clone.c
index e086a40b41..c0e3086437 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,
@@ -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);
}
@@ -322,7 +330,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 +354,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 +369,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.",
@@ -383,7 +396,7 @@ 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);
if (!stat(dir, &buf))
die("destination directory '%s' already exists.", dir);
@@ -440,26 +453,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)