# [PATCH] git init: optionally allow a directory argument

7 messages from 2009-07-24 to 2009-07-25. Participants: Nanako Shiraishi, Junio C Hamano, Daniel Pittman, Alex Scarborough, Johannes Sixt.
Thread: https://gitlist.dev/t/20223

## Nanako Shiraishi, 2009-07-24 21:59

Subject: [PATCH] git init: optionally allow a directory argument
Message-ID: <20090725065928.6117@nanako3.lavabit.com>
URL: https://gitlist.dev/e/20090725065928.6117%40nanako3.lavabit.com

```
When starting a new repository, I see my students often say

    % git init newrepo

and curse git.  They could say

    % mkdir newrepo; cd newrepo; git init

but allowing it as an obvious short-cut may be nicer.

Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
---

 Please be gentle; I don't write C very well.

 Documentation/git-init.txt |    5 ++++-
 builtin-init-db.c          |   37 +++++++++++++++++++++++++++++--------
 t/t0001-init.sh            |   34 ++++++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 7151d12..f081b24 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
 
 SYNOPSIS
 --------
-'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
+'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]] [directory]
 
 
 OPTIONS
@@ -74,6 +74,9 @@ By default, the configuration flag receive.denyNonFastForwards is enabled
 in shared repositories, so that you cannot force a non fast-forwarding push
 into it.
 
+If you name a (possibly non-existent) directory at the end of the command
+line, the command is run inside the directory (possibly after creating it).
+
 --
 
 
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 4a56006..100db73 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -371,7 +371,7 @@ static int guess_repository_type(const char *git_dir)
 }
 
 static const char init_db_usage[] =
-"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -384,27 +384,48 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	const char *git_dir;
 	const char *template_dir = NULL;
 	unsigned int flags = 0;
+	int bare_given = 0;
 	int i;
 
 	for (i = 1; i < argc; i++, argv++) {
 		const char *arg = argv[1];
 		if (!prefixcmp(arg, "--template="))
 			template_dir = arg+11;
-		else if (!strcmp(arg, "--bare")) {
-			static char git_dir[PATH_MAX+1];
-			is_bare_repository_cfg = 1;
-			setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
-						sizeof(git_dir)), 0);
-		} else if (!strcmp(arg, "--shared"))
+		else if (!strcmp(arg, "--bare"))
+			bare_given = is_bare_repository_cfg = 1;
+		else if (!strcmp(arg, "--shared"))
 			init_shared_repository = PERM_GROUP;
 		else if (!prefixcmp(arg, "--shared="))
 			init_shared_repository = git_config_perm("arg", arg+9);
 		else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
 			flags |= INIT_DB_QUIET;
-		else
+		else if (arg[0] == '-')
 			usage(init_db_usage);
+		else
+			break;
 	}
 
+	if (i == argc - 1) {
+		int mkdir_tried = 0;
+	retry:
+		if (chdir(argv[1]) < 0) {
+			if (!mkdir_tried) {
+				if (mkdir(argv[1], 0777) < 0)
+					die_errno("cannot mkdir %s", argv[1]);
+				mkdir_tried = 1;
+				goto retry;
+			}
+			die_errno("cannot chdir to %s", argv[1]);
+		}
+	} else if (i < argc - 1) {
+		usage(init_db_usage);
+	}
+	if (bare_given == 1) {
+		static char git_dir[PATH_MAX+1];
+
+		setenv(GIT_DIR_ENVIRONMENT,
+			getcwd(git_dir, sizeof(git_dir)), 0);
+	}
 	if (init_shared_repository != -1)
 		shared_repository = init_shared_repository;
 
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index e3d8464..0ded031 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -208,4 +208,38 @@ test_expect_success 'init rejects insanely long --template' '
 	)
 '
 
+test_expect_success 'init creates a new directory' '
+	rm -fr newdir &&
+	(
+		git init newdir &&
+		test -d newdir/.git/refs
+	)
+'
+
+test_expect_success 'init creates a new bare directory' '
+	rm -fr newdir &&
+	(
+		git init --bare newdir &&
+		test -d newdir/refs
+	)
+'
+
+test_expect_success 'init recreates a directory' '
+	rm -fr newdir &&
+	(
+		mkdir newdir &&
+		git init newdir &&
+		test -d newdir/.git/refs
+	)
+'
+
+test_expect_success 'init recreates a new bare directory' '
+	rm -fr newdir &&
+	(
+		mkdir newdir &&
+		git init --bare newdir &&
+		test -d newdir/refs
+	)
+'
+
 test_done

-- 
Nanako Shiraishi
http://ivory.ap.teacup.com/nanako3/

```

## Junio C Hamano, 2009-07-24 23:36

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <7vab2t64cg.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vab2t64cg.fsf%40alter.siamese.dyndns.org
In-Reply-To: <20090725065928.6117@nanako3.lavabit.com>

```
Nanako Shiraishi <nanako3@lavabit.com> writes:

> When starting a new repository, I see my students often say
>
>     % git init newrepo
>
> and curse git.  They could say
>
>     % mkdir newrepo; cd newrepo; git init
>
> but allowing it as an obvious short-cut may be nicer.
>
> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>

Hmm, I didn't realize this is so common a wish among new people.

The patch seems clean.  Anybody has comments, both on code and the use
case?

```

## Daniel Pittman, 2009-07-25 03:13

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <87r5w5h2uy.fsf@rimspace.net>
URL: https://gitlist.dev/e/87r5w5h2uy.fsf%40rimspace.net
In-Reply-To: <7vab2t64cg.fsf@alter.siamese.dyndns.org>

```
Junio C Hamano <gitster@pobox.com> writes:
> Nanako Shiraishi <nanako3@lavabit.com> writes:
>
>> When starting a new repository, I see my students often say
>>     % git init newrepo
>> and curse git.  They could say
>>     % mkdir newrepo; cd newrepo; git init
>> but allowing it as an obvious short-cut may be nicer.
>>
>> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
>
> Hmm, I didn't realize this is so common a wish among new people.  The patch
> seems clean.  Anybody has comments, both on code and the use case?

It still surprises me that git doesn't do this, since it is at odds with
almost every other version control system I have on hand or experience with,
other than CVS; Subversion, svk, Bazaar and Mercurial all take a trailing
target argument.

CVS and monotone take an option to specify where; only darcs is like git and
uses the current directory as the target.

So, from where I sit it makes sense to have 'git init foo' create a 'foo'
directory and repository below the current location.

Regards,
        Daniel

...and, yeah, I still get caught every now and then when I create a new
repository by hand.
-- 
✣ Daniel Pittman            ✉ daniel@rimspace.net            ☎ +61 401 155 707
               ♽ made with 100 percent post-consumer electrons

```

## Junio C Hamano, 2009-07-25 06:41

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <7v7hxxz2lt.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7v7hxxz2lt.fsf%40alter.siamese.dyndns.org
In-Reply-To: <20090725065928.6117@nanako3.lavabit.com>

```
Nanako Shiraishi <nanako3@lavabit.com> writes:

> When starting a new repository, I see my students often say
>
>     % git init newrepo
>
> and curse git.  They could say
>
>     % mkdir newrepo; cd newrepo; git init
>
> but allowing it as an obvious short-cut may be nicer.
>
> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
> ---
>
>  Please be gentle; I don't write C very well.

As I already said, the patch looked reasonable.

> +	if (i == argc - 1) {
> +		int mkdir_tried = 0;
> +	retry:
> +		if (chdir(argv[1]) < 0) {
> +			if (!mkdir_tried) {
> +				if (mkdir(argv[1], 0777) < 0)
> +					die_errno("cannot mkdir %s", argv[1]);
> +				mkdir_tried = 1;
> +				goto retry;
> +			}
> +			die_errno("cannot chdir to %s", argv[1]);
> +		}

But I have to wonder if we would also want to allow

	$ git init --bare project/repo-000.git

when you do not even have "project" directory.  After all, we are talking
about people who do not bother "mkdir repo-000.git", so instead of doing
equivalent of "mkdir project/repo-000.git", it would make more sense to do
an equivalent of "mkdir -p project/repo-000.git" instead.

Here is a patch to do so on top of yours, possibly you may want to squash
in.

 builtin-init-db.c |   19 +++++++++++++++++++
 t/t0001-init.sh   |   43 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/builtin-init-db.c b/builtin-init-db.c
index 100db73..b7f708d 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -410,6 +410,25 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
 	retry:
 		if (chdir(argv[1]) < 0) {
 			if (!mkdir_tried) {
+				int saved;
+				/*
+				 * At this point we haven't read any configuration,
+				 * and we know shared_repository should always be 0;
+				 * but just in case we play safe.
+				 */
+				saved = shared_repository;
+				shared_repository = 0;
+				switch (safe_create_leading_directories_const(argv[1])) {
+				case -3:
+					errno = EEXIST;
+					/* fallthru */
+				case -1:
+					die_errno("cannot mkdir %s", argv[1]);
+					break;
+				default:
+					break;
+				}
+				shared_repository = saved;
 				if (mkdir(argv[1], 0777) < 0)
 					die_errno("cannot mkdir %s", argv[1]);
 				mkdir_tried = 1;
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 0ded031..8c55404 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -242,4 +242,47 @@ test_expect_success 'init recreates a new bare directory' '
 	)
 '
 
+test_expect_success 'init creates a new deep directory' '
+	rm -fr newdir &&
+	(
+		# Leading directories should honor umask while
+		# the repository itself should follow "shared"
+		umask 002 &&
+		git init --bare --shared=0660 newdir/a/b/c &&
+		test -d newdir/a/b/c/refs &&
+		ls -ld newdir/a newdir/a/b > lsab.out &&
+		! grep -v "^drwxrw[sx]r-x" ls.out &&
+		ls -ld newdir/a/b/c > lsc.out &&
+		! grep -v "^drwxrw[sx]---" lsc.out
+	)
+'
+
+test_expect_success 'init notices EEXIST (1)' '
+	rm -fr newdir &&
+	(
+		>newdir &&
+		test_must_fail git init newdir &&
+		test -f newdir
+	)
+'
+
+test_expect_success 'init notices EEXIST (2)' '
+	rm -fr newdir &&
+	(
+		mkdir newdir &&
+		>newdir/a
+		test_must_fail git init newdir/a/b &&
+		test -f newdir/a
+	)
+'
+
+test_expect_success 'init notices EPERM' '
+	rm -fr newdir &&
+	(
+		mkdir newdir &&
+		chmod -w newdir &&
+		test_must_fail git init newdir/a/b
+	)
+'
+
 test_done

```

## Alex Scarborough, 2009-07-25 06:41

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <EA5BDEF8-BACD-49FD-8AE9-D76D87DCFA40@garagegames.com>
URL: https://gitlist.dev/e/EA5BDEF8-BACD-49FD-8AE9-D76D87DCFA40%40garagegames.com
In-Reply-To: <7vab2t64cg.fsf@alter.siamese.dyndns.org>

```

On Jul 24, 2009, at 4:36 PM, Junio C Hamano wrote:

> Nanako Shiraishi <nanako3@lavabit.com> writes:
>
>> When starting a new repository, I see my students often say
>>
>>    % git init newrepo
>>
>> and curse git.  They could say
>>
>>    % mkdir newrepo; cd newrepo; git init
>>
>> but allowing it as an obvious short-cut may be nicer.
>>
>> Signed-off-by: Nanako Shiraishi <nanako3@lavabit.com>
>
> Hmm, I didn't realize this is so common a wish among new people.
>
> The patch seems clean.  Anybody has comments, both on code and the use
> case?

The use case makes sense.  This helps make git init be a bit more  
consistent
with git clone, which can take a trailing target.

For the code, I would replace the direct use of mkdir with  
safe_create_dir.
Otherwise it looks fine.

-Alex Scarborough

```

## Johannes Sixt, 2009-07-25 07:45

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <200907250945.18398.j6t@kdbg.org>
URL: https://gitlist.dev/e/200907250945.18398.j6t%40kdbg.org
In-Reply-To: <7v7hxxz2lt.fsf@alter.siamese.dyndns.org>

```
On Samstag, 25. Juli 2009, Junio C Hamano wrote:
> +test_expect_success 'init notices EPERM' '
> +	rm -fr newdir &&
> +	(
> +		mkdir newdir &&
> +		chmod -w newdir &&
> +		test_must_fail git init newdir/a/b
> +	)
> +'

This test will require POSIXPERM prerequisite.

-- Hannes

```

## Junio C Hamano, 2009-07-25 09:26

Subject: Re: [PATCH] git init: optionally allow a directory argument
Message-ID: <7vd47pun9p.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vd47pun9p.fsf%40alter.siamese.dyndns.org
In-Reply-To: <200907250945.18398.j6t@kdbg.org>

```
Johannes Sixt <j6t@kdbg.org> writes:

> On Samstag, 25. Juli 2009, Junio C Hamano wrote:
>> +test_expect_success 'init notices EPERM' '
>> +	rm -fr newdir &&
>> +	(
>> +		mkdir newdir &&
>> +		chmod -w newdir &&
>> +		test_must_fail git init newdir/a/b
>> +	)
>> +'
>
> This test will require POSIXPERM prerequisite.

Heh, I knew it ;-)

Thanks.

```
