threads / patch / 20223

patchgit init: optionally allow a directory argument

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

## tl;dr

7 messages between Jul 24, 2009 and Jul 25, 2009. Diffs are folded; open one to read it.

replies: 6people: 5as markdown or json

Nanako Shiraishi· Jul 24, 2009, 21:59 UTC · lore
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(-)
Show changes to 3 files +67 −9

Documentation/git-init.txt, builtin-init-db.c, t/t0001-init.sh

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· Jul 24, 2009, 23:36 UTC · re: Nanako Shiraishi · lore

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

Nanako Shiraishi <nanako3@lavabit.com> writes:
Show 11 quoted lines
> 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· Jul 25, 2009, 03:13 UTC · re: Junio C Hamano · lore

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

Junio C Hamano <gitster@pobox.com> writes:
Show 12 quoted lines
> 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
Alex Scarborough· Jul 25, 2009, 06:41 UTC · re: Junio C Hamano · lore

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

On Jul 24, 2009, at 4:36 PM, Junio C Hamano wrote:
Show 18 quoted lines
> 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
Junio C Hamano· Jul 25, 2009, 06:41 UTC · re: Nanako Shiraishi · lore

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

Nanako Shiraishi <nanako3@lavabit.com> writes:
Show 14 quoted lines
> 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.
Show 12 quoted lines
> +	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(-)
Show changes to 2 files +62 −0

builtin-init-db.c, t/t0001-init.sh

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
Johannes Sixt· Jul 25, 2009, 07:45 UTC · re: Junio C Hamano · lore

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

On Samstag, 25. Juli 2009, Junio C Hamano wrote:
Show 8 quoted lines
> +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· Jul 25, 2009, 09:26 UTC · re: Johannes Sixt · lore

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

Johannes Sixt <j6t@kdbg.org> writes:
Show 11 quoted lines
> 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.

← back to recent threads