# [PATCH 1/2] clone: Add an option to set up a mirror

9 messages from 2008-08-01 to 2008-08-02. Participants: Johannes Schindelin, Marcus Griep, Miklos Vajna, Bert Wesarg, Junio C Hamano.
Thread: https://gitlist.dev/t/14792

## Johannes Schindelin, 2008-08-01 14:00

Subject: [PATCH 1/2] clone: Add an option to set up a mirror
Message-ID: <alpine.DEB.1.00.0808011600170.9611@pacific.mpi-cbg.de.mpi-cbg.de>
URL: https://gitlist.dev/e/alpine.DEB.1.00.0808011600170.9611%40pacific.mpi-cbg.de.mpi-cbg.de

```

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>
---
 Documentation/git-clone.txt |    5 ++++-
 builtin-clone.c             |    9 ++++++++-
 t/t5601-clone.sh            |   10 ++++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)

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 @@ SYNOPSIS
 --------
 [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 @@ then the cloned repository will become corrupt.
 	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..a45179c 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,
@@ -359,6 +361,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.",
@@ -446,7 +451,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	} else {
 		snprintf(branch_top, sizeof(branch_top),
 			 "refs/remotes/%s/", option_origin);
+	}
 
+	if (option_mirror || !option_bare) {
 		/* Configure the remote */
 		snprintf(key, sizeof(key), "remote.%s.url", option_origin);
 		git_config_set(key, repo);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d785b3d..4b2533f 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -70,4 +70,14 @@ test_expect_success 'clone creates intermediate directories for bare repo' '
 
 '
 
+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/heads/*:refs/heads/*" = "$FETCH"
+
+'
+
 test_done
-- 
1.6.0.rc1.46.g279e5

```

## Marcus Griep, 2008-08-01 14:01

Subject: Re: [PATCH 2/2] clone --bare: Add ".git" suffix to the directory name to clone into
Message-ID: <4893172C.1060203@griep.us>
URL: https://gitlist.dev/e/4893172C.1060203%40griep.us
In-Reply-To: <alpine.DEB.1.00.0808011601200.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```
Does this patch forgo adding a ".git" suffix if one is already present?

Marcus

Johannes Schindelin wrote:
> We have a tradition that bare repositories live in directories ending
> in ".git".  To make this more a convention than just a tradition, teach
> "git clone --bare" to add a ".git" suffix to the directory name.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> 
> 	This patch is only conceptionally dependent on patch 1/2.
> 
>  builtin-clone.c  |   10 ++++++++--
>  t/t5601-clone.sh |    7 +++++++
>  2 files changed, 15 insertions(+), 2 deletions(-)
> 
> diff --git a/builtin-clone.c b/builtin-clone.c
> index a45179c..82f5b67 100644
> --- a/builtin-clone.c
> +++ b/builtin-clone.c
> @@ -95,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;
>  
> @@ -131,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);
>  }
>  
> @@ -388,7 +394,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);
> diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
> index 4b2533f..e0a68ab 100755
> --- a/t/t5601-clone.sh
> +++ b/t/t5601-clone.sh
> @@ -80,4 +80,11 @@ test_expect_success 'clone --mirror' '
>  
>  '
>  
> +test_expect_success 'clone --bare names the local repository <name>.git' '
> +
> +	git clone --bare src &&
> +	test -d src.git
> +
> +'
> +
>  test_done

-- 
Marcus Griep
GPG Key ID: 0x5E968152
——
http://www.boohaunt.net
את.ψο´


```

## Johannes Schindelin, 2008-08-01 14:01

Subject: [PATCH 2/2] clone --bare: Add ".git" suffix to the directory name to clone into
Message-ID: <alpine.DEB.1.00.0808011601200.9611@pacific.mpi-cbg.de.mpi-cbg.de>
URL: https://gitlist.dev/e/alpine.DEB.1.00.0808011601200.9611%40pacific.mpi-cbg.de.mpi-cbg.de
In-Reply-To: <alpine.DEB.1.00.0808011600170.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```

We have a tradition that bare repositories live in directories ending
in ".git".  To make this more a convention than just a tradition, teach
"git clone --bare" to add a ".git" suffix to the directory name.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	This patch is only conceptionally dependent on patch 1/2.

 builtin-clone.c  |   10 ++++++++--
 t/t5601-clone.sh |    7 +++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/builtin-clone.c b/builtin-clone.c
index a45179c..82f5b67 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -95,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;
 
@@ -131,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);
 }
 
@@ -388,7 +394,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);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 4b2533f..e0a68ab 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -80,4 +80,11 @@ test_expect_success 'clone --mirror' '
 
 '
 
+test_expect_success 'clone --bare names the local repository <name>.git' '
+
+	git clone --bare src &&
+	test -d src.git
+
+'
+
 test_done
-- 
1.6.0.rc1.46.g279e5

```

## Miklos Vajna, 2008-08-01 14:27

Subject: Re: [PATCH 1/2] clone: Add an option to set up a mirror
Message-ID: <20080801142732.GS32057@genesis.frugalware.org>
URL: https://gitlist.dev/e/20080801142732.GS32057%40genesis.frugalware.org
In-Reply-To: <alpine.DEB.1.00.0808011600170.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```
On Fri, Aug 01, 2008 at 04:00:45PM +0200, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> 
> 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)

Funny, someone asked exactly this on #git yesterday (IIRC), but we ended
up using clone & remote, since I didn't find clone --mirror in the man.
;-)

Thanks!

```

## Bert Wesarg, 2008-08-01 15:34

Subject: Re: [PATCH 2/2] clone --bare: Add ".git" suffix to the directory name to clone into
Message-ID: <36ca99e90808010834q6bb2f0a7i52a7aafb8dbafb70@mail.gmail.com>
URL: https://gitlist.dev/e/36ca99e90808010834q6bb2f0a7i52a7aafb8dbafb70%40mail.gmail.com
In-Reply-To: <4893172C.1060203@griep.us>

```
On Fri, Aug 1, 2008 at 16:01, Marcus Griep <marcus@griep.us> wrote:
> Does this patch forgo adding a ".git" suffix if one is already present?

No, the purpose of the guess_dir_name() function is exactly to remove
any present ".git", and more.

Bert
>
> Marcus
>

```

## Junio C Hamano, 2008-08-02 18:55

Subject: Re: [PATCH 1/2] clone: Add an option to set up a mirror
Message-ID: <7vr697l01j.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vr697l01j.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <alpine.DEB.1.00.0808011600170.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> 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)

I think this would be a useful behaviour and I am very tempted to violate
the general policy of not taking any new options nor features after -rc1.

I however notice that there are differences bewteen the above sequence and
what your code actually does:

 - The "remote add --mirror" sequence tells it to mirror everything, but
   the patch still mirrors only heads;

 - You are not setting up "remote.*.mirror = yes" in the configuration;

```

## Johannes Schindelin, 2008-08-02 19:38

Subject: [PATCH v2] clone: Add an option to set up a mirror
Message-ID: <alpine.DEB.1.00.0808022126270.9611@pacific.mpi-cbg.de.mpi-cbg.de>
URL: https://gitlist.dev/e/alpine.DEB.1.00.0808022126270.9611%40pacific.mpi-cbg.de.mpi-cbg.de
In-Reply-To: <7vr697l01j.fsf@gitster.siamese.dyndns.org>

```

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>
---

	Interdiff to follow.

 Documentation/git-clone.txt |    5 ++++-
 builtin-clone.c             |   24 ++++++++++++++++++++----
 t/t5601-clone.sh            |   10 ++++++++++
 3 files changed, 34 insertions(+), 5 deletions(-)

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 @@ SYNOPSIS
 --------
 [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 @@ then the cloned repository will become corrupt.
 	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 @@ 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,
@@ -345,6 +347,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 +362,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.",
@@ -440,26 +446,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)
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index d785b3d..9cd5ef4 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -70,4 +70,14 @@ test_expect_success 'clone creates intermediate directories for bare repo' '
 
 '
 
+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"
+
+'
+
 test_done
-- 
1.6.0.rc1.70.g91e1d

```

## Johannes Schindelin, 2008-08-02 19:39

Subject: Re: [PATCH v2] clone: Add an option to set up a mirror
Message-ID: <alpine.DEB.1.00.0808022139150.9611@pacific.mpi-cbg.de.mpi-cbg.de>
URL: https://gitlist.dev/e/alpine.DEB.1.00.0808022139150.9611%40pacific.mpi-cbg.de.mpi-cbg.de
In-Reply-To: <alpine.DEB.1.00.0808022126270.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```
The interdiff:

diff --git a/builtin-clone.c b/builtin-clone.c
index a45179c..ecdcefa 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -347,6 +347,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;
 
@@ -445,7 +446,9 @@ 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 {
@@ -455,18 +458,24 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
 	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/t/t5601-clone.sh b/t/t5601-clone.sh
index 4b2533f..9cd5ef4 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -76,7 +76,7 @@ test_expect_success 'clone --mirror' '
 	test -f mirror/HEAD &&
 	test ! -f mirror/file &&
 	FETCH="$(cd mirror && git config remote.origin.fetch)" &&
-	test "+refs/heads/*:refs/heads/*" = "$FETCH"
+	test "+refs/*:refs/*" = "$FETCH"
 
 '
 

```

## Junio C Hamano, 2008-08-02 20:46

Subject: Re: [PATCH v2] clone: Add an option to set up a mirror
Message-ID: <7vd4krdu1p.fsf@gitster.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vd4krdu1p.fsf%40gitster.siamese.dyndns.org
In-Reply-To: <alpine.DEB.1.00.0808022126270.9611@pacific.mpi-cbg.de.mpi-cbg.de>

```
Thanks for a quick turnaround.

```
