git init: optionally allow a directory argument
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nanako Shiraishi committed
Jul 25, 2009 at 06:59 UTC
53d48885931614a43e414e1272a7f126f8d0c901
3 files changed
+129
-9
Documentation/git-init.txt
+4
-1
@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
8
9
SYNOPSIS
10
--------
11
-'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]]
11
+'git init' [-q | --quiet] [--bare] [--template=<template_directory>] [--shared[=<permissions>]] [directory]
12
13
14
OPTIONS
@@ -74,6 +74,9 @@ By default, the configuration flag receive.denyNonFastForwards is enabled
74
in shared repositories, so that you cannot force a non fast-forwarding push
75
into it.
76
77
+If you name a (possibly non-existent) directory at the end of the command
78
+line, the command is run inside the directory (possibly after creating it).
79
+
80
--
81
82
builtin-init-db.c
+48
-8
@@ -371,7 +371,7 @@ static int guess_repository_type(const char *git_dir)
371
}
372
373
static const char init_db_usage[] =
374
-"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]]";
374
+"git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]";
375
376
/*
377
* If you want to, you can share the DB area with any number of branches.
@@ -384,27 +384,67 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
384
const char *git_dir;
385
const char *template_dir = NULL;
386
unsigned int flags = 0;
387
+ int bare_given = 0;
388
int i;
389
390
for (i = 1; i < argc; i++, argv++) {
391
const char *arg = argv[1];
392
if (!prefixcmp(arg, "--template="))
393
template_dir = arg+11;
393
- else if (!strcmp(arg, "--bare")) {
394
- static char git_dir[PATH_MAX+1];
395
- is_bare_repository_cfg = 1;
396
- setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir,
397
- sizeof(git_dir)), 0);
398
- } else if (!strcmp(arg, "--shared"))
394
+ else if (!strcmp(arg, "--bare"))
395
+ bare_given = is_bare_repository_cfg = 1;
396
+ else if (!strcmp(arg, "--shared"))
397
init_shared_repository = PERM_GROUP;
398
else if (!prefixcmp(arg, "--shared="))
399
init_shared_repository = git_config_perm("arg", arg+9);
400
else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
401
flags |= INIT_DB_QUIET;
404
- else
402
+ else if (arg[0] == '-')
403
usage(init_db_usage);
404
+ else
405
+ break;
406
}
407
408
+ if (i == argc - 1) {
409
+ int mkdir_tried = 0;
410
+ retry:
411
+ if (chdir(argv[1]) < 0) {
412
+ if (!mkdir_tried) {
413
+ int saved;
414
+ /*
415
+ * At this point we haven't read any configuration,
416
+ * and we know shared_repository should always be 0;
417
+ * but just in case we play safe.
418
+ */
419
+ saved = shared_repository;
420
+ shared_repository = 0;
421
+ switch (safe_create_leading_directories_const(argv[1])) {
422
+ case -3:
423
+ errno = EEXIST;
424
+ /* fallthru */
425
+ case -1:
426
+ die_errno("cannot mkdir %s", argv[1]);
427
+ break;
428
+ default:
429
+ break;
430
+ }
431
+ shared_repository = saved;
432
+ if (mkdir(argv[1], 0777) < 0)
433
+ die_errno("cannot mkdir %s", argv[1]);
434
+ mkdir_tried = 1;
435
+ goto retry;
436
+ }
437
+ die_errno("cannot chdir to %s", argv[1]);
438
+ }
439
+ } else if (i < argc - 1) {
440
+ usage(init_db_usage);
441
+ }
442
+ if (bare_given == 1) {
443
+ static char git_dir[PATH_MAX+1];
444
+
445
+ setenv(GIT_DIR_ENVIRONMENT,
446
+ getcwd(git_dir, sizeof(git_dir)), 0);
447
+ }
448
if (init_shared_repository != -1)
449
shared_repository = init_shared_repository;
450
t/t0001-init.sh
+77
@@ -208,4 +208,81 @@ test_expect_success 'init rejects insanely long --template' '
208
)
209
'
210
211
+test_expect_success 'init creates a new directory' '
212
+ rm -fr newdir &&
213
+ (
214
+ git init newdir &&
215
+ test -d newdir/.git/refs
216
+ )
217
+'
218
+
219
+test_expect_success 'init creates a new bare directory' '
220
+ rm -fr newdir &&
221
+ (
222
+ git init --bare newdir &&
223
+ test -d newdir/refs
224
+ )
225
+'
226
+
227
+test_expect_success 'init recreates a directory' '
228
+ rm -fr newdir &&
229
+ (
230
+ mkdir newdir &&
231
+ git init newdir &&
232
+ test -d newdir/.git/refs
233
+ )
234
+'
235
+
236
+test_expect_success 'init recreates a new bare directory' '
237
+ rm -fr newdir &&
238
+ (
239
+ mkdir newdir &&
240
+ git init --bare newdir &&
241
+ test -d newdir/refs
242
+ )
243
+'
244
+
245
+test_expect_success 'init creates a new deep directory' '
246
+ rm -fr newdir &&
247
+ (
248
+ # Leading directories should honor umask while
249
+ # the repository itself should follow "shared"
250
+ umask 002 &&
251
+ git init --bare --shared=0660 newdir/a/b/c &&
252
+ test -d newdir/a/b/c/refs &&
253
+ ls -ld newdir/a newdir/a/b > lsab.out &&
254
+ ! grep -v "^drwxrw[sx]r-x" ls.out &&
255
+ ls -ld newdir/a/b/c > lsc.out &&
256
+ ! grep -v "^drwxrw[sx]---" lsc.out
257
+ )
258
+'
259
+
260
+test_expect_success 'init notices EEXIST (1)' '
261
+ rm -fr newdir &&
262
+ (
263
+ >newdir &&
264
+ test_must_fail git init newdir &&
265
+ test -f newdir
266
+ )
267
+'
268
+
269
+test_expect_success 'init notices EEXIST (2)' '
270
+ rm -fr newdir &&
271
+ (
272
+ mkdir newdir &&
273
+ >newdir/a
274
+ test_must_fail git init newdir/a/b &&
275
+ test -f newdir/a
276
+ )
277
+'
278
+
279
+test_expect_success POSIXPERM 'init notices EPERM' '
280
+ rm -fr newdir &&
281
+ (
282
+ mkdir newdir &&
283
+ chmod -w newdir &&
284
+ test_must_fail git init newdir/a/b
285
+ )
286
+'
287
+
288
test_done