clone: Add an option to set up a mirror

The command line

	$ git clone --mirror $URL

is now a short-hand for

	$ git clone --bare $URL
	$ (cd $(basename $URL) && git remote add --mirror origin $URL)

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 26fd1b1..0e14e73 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -10,7 +10,7 @@
 --------
 [verse]
 'git clone' [--template=<template_directory>]
-	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare]
+	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
 	  [-o <name>] [-u <upload-pack>] [--reference <repository>]
 	  [--depth <depth>] [--] <repository> [<directory>]
 
@@ -106,6 +106,9 @@
 	used, neither remote-tracking branches nor the related
 	configuration variables are created.
 
+--mirror::
+	Set up a mirror of the remote repository.  This implies --bare.
+
 --origin <name>::
 -o <name>::
 	Instead of using the remote name 'origin' to keep track
diff --git a/builtin-clone.c b/builtin-clone.c
index e086a40..ecdcefa 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -33,7 +33,7 @@
 	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 @@
 		    "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,
@@ -345,6 +347,7 @@
 	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 +362,9 @@
 	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.",
@@ -440,26 +446,36 @@
 	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)
diff --git a/builtin-remote.c b/builtin-remote.c
index 54d1c3e..01945a8 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -115,7 +115,7 @@
 	if (mirror) {
 		strbuf_reset(&buf);
 		strbuf_addf(&buf, "remote.%s.mirror", name);
-		if (git_config_set(buf.buf, "yes"))
+		if (git_config_set(buf.buf, "true"))
 			return 1;
 	}
 
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d785b3d..a533457 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -70,4 +70,16 @@
 
 '
 
+test_expect_success 'clone --mirror' '
+
+	git clone --mirror src mirror &&
+	test -f mirror/HEAD &&
+	test ! -f mirror/file &&
+	FETCH="$(cd mirror && git config remote.origin.fetch)" &&
+	test "+refs/*:refs/*" = "$FETCH" &&
+	MIRROR="$(cd mirror && git config --bool remote.origin.mirror)" &&
+	test "$MIRROR" = true
+
+'
+
 test_done