Skip to content

Commit 6adcca3

Browse files
committed
Fix initialization of a bare repository
Here is my attempt to fix this with a minimally intrusive patch. * As "git --bare init" cannot tell if it was called with --bare or just "GIT_DIR=. git init", I added an explicit assignment of is_bare_repository_cfg on the codepath for "git --bare". * GIT_WORK_TREE alone without GIT_DIR does not make any sense, nor GIT_WORK_TREE with an explicit "git --bare". Catch that mistake. It might make sense to move this check to "git.c" side as well, but I tried to shoot for the minimum change for now. * Some scripts, especially from the olden days, rely on traditional GIT_DIR behaviour in "git init". Namely, these are some notable patterns: (create a bare repository) - mkdir some.git && cd some.git && GIT_DIR=. git init - mkdir some.git && cd some.git && git --bare init (create a non-bare repository) - mkdir .git && GIT_DIR=.git git init - mkdir .git && GIT_DIR=`pwd`/.git git init This comes with a new test script and also passes the existing test suite, but there may be cases that are still broken with the current tip of master and this patch does not yet fix. I'd appreciate help in straightening this mess out. Signed-off-by: Junio C Hamano <[email protected]>
1 parent ac076c2 commit 6adcca3

File tree

3 files changed

+177
-5
lines changed

3 files changed

+177
-5
lines changed

builtin-init-db.c

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,44 @@ static int create_default_files(const char *git_dir, const char *template_path)
267267
return reinit;
268268
}
269269

270+
static void guess_repository_type(const char *git_dir)
271+
{
272+
char cwd[PATH_MAX];
273+
const char *slash;
274+
275+
if (0 <= is_bare_repository_cfg)
276+
return;
277+
if (!git_dir)
278+
return;
279+
280+
/*
281+
* "GIT_DIR=. git init" is always bare.
282+
* "GIT_DIR=`pwd` git init" too.
283+
*/
284+
if (!strcmp(".", git_dir))
285+
goto force_bare;
286+
if (!getcwd(cwd, sizeof(cwd)))
287+
die("cannot tell cwd");
288+
if (!strcmp(git_dir, cwd))
289+
goto force_bare;
290+
/*
291+
* "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
292+
*/
293+
if (!strcmp(git_dir, ".git"))
294+
return;
295+
slash = strrchr(git_dir, '/');
296+
if (slash && !strcmp(slash, "/.git"))
297+
return;
298+
299+
/*
300+
* Otherwise it is often bare. At this point
301+
* we are just guessing.
302+
*/
303+
force_bare:
304+
is_bare_repository_cfg = 1;
305+
return;
306+
}
307+
270308
static const char init_db_usage[] =
271309
"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
272310

@@ -299,11 +337,28 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
299337
usage(init_db_usage);
300338
}
301339

302-
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
303-
if (!getcwd(git_work_tree_cfg, PATH_MAX))
304-
die ("Cannot access current working directory.");
305-
if (access(get_git_work_tree(), X_OK))
306-
die ("Cannot access work tree '%s'", get_git_work_tree());
340+
/*
341+
* GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
342+
* without --bare. Catch the error early.
343+
*/
344+
git_dir = getenv(GIT_DIR_ENVIRONMENT);
345+
if ((!git_dir || is_bare_repository_cfg == 1)
346+
&& getenv(GIT_WORK_TREE_ENVIRONMENT))
347+
die("%s (or --work-tree=<directory>) not allowed without "
348+
"specifying %s (or --git-dir=<directory>)",
349+
GIT_WORK_TREE_ENVIRONMENT,
350+
GIT_DIR_ENVIRONMENT);
351+
352+
guess_repository_type(git_dir);
353+
354+
if (is_bare_repository_cfg <= 0) {
355+
git_work_tree_cfg = xcalloc(PATH_MAX, 1);
356+
if (!getcwd(git_work_tree_cfg, PATH_MAX))
357+
die ("Cannot access current working directory.");
358+
if (access(get_git_work_tree(), X_OK))
359+
die ("Cannot access work tree '%s'",
360+
get_git_work_tree());
361+
}
307362

308363
/*
309364
* Set up the default .git directory contents

git.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
9393
*envchanged = 1;
9494
} else if (!strcmp(cmd, "--bare")) {
9595
static char git_dir[PATH_MAX+1];
96+
is_bare_repository_cfg = 1;
9697
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
9798
if (envchanged)
9899
*envchanged = 1;

t/t0001-init.sh

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/bin/sh
2+
3+
test_description='git init'
4+
5+
. ./test-lib.sh
6+
7+
check_config () {
8+
if test -d "$1" && test -f "$1/config" && test -d "$1/refs"
9+
then
10+
: happy
11+
else
12+
echo "expected a directory $1, a file $1/config and $1/refs"
13+
return 1
14+
fi
15+
bare=$(GIT_CONFIG="$1/config" git config --bool core.bare)
16+
worktree=$(GIT_CONFIG="$1/config" git config core.worktree) ||
17+
worktree=unset
18+
19+
test "$bare" = "$2" && test "$worktree" = "$3" || {
20+
echo "expected bare=$2 worktree=$3"
21+
echo " got bare=$bare worktree=$worktree"
22+
return 1
23+
}
24+
}
25+
26+
test_expect_success 'plain' '
27+
(
28+
unset GIT_DIR GIT_WORK_TREE &&
29+
mkdir plain &&
30+
cd plain &&
31+
git init
32+
) &&
33+
check_config plain/.git false unset
34+
'
35+
36+
test_expect_success 'plain with GIT_WORK_TREE' '
37+
if (
38+
unset GIT_DIR &&
39+
mkdir plain-wt &&
40+
cd plain-wt &&
41+
GIT_WORK_TREE=$(pwd) git init
42+
)
43+
then
44+
echo Should have failed -- GIT_WORK_TREE should not be used
45+
false
46+
fi
47+
'
48+
49+
test_expect_success 'plain bare' '
50+
(
51+
unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
52+
mkdir plain-bare-1 &&
53+
cd plain-bare-1 &&
54+
git --bare init
55+
) &&
56+
check_config plain-bare-1 true unset
57+
'
58+
59+
test_expect_success 'plain bare with GIT_WORK_TREE' '
60+
if (
61+
unset GIT_DIR GIT_CONFIG &&
62+
mkdir plain-bare-2 &&
63+
cd plain-bare-2 &&
64+
GIT_WORK_TREE=$(pwd) git --bare init
65+
)
66+
then
67+
echo Should have failed -- GIT_WORK_TREE should not be used
68+
false
69+
fi
70+
'
71+
72+
test_expect_success 'GIT_DIR bare' '
73+
74+
(
75+
unset GIT_CONFIG &&
76+
mkdir git-dir-bare.git &&
77+
GIT_DIR=git-dir-bare.git git init
78+
) &&
79+
check_config git-dir-bare.git true unset
80+
'
81+
82+
test_expect_success 'GIT_DIR non-bare' '
83+
84+
(
85+
unset GIT_CONFIG &&
86+
mkdir non-bare &&
87+
cd non-bare &&
88+
GIT_DIR=.git git init
89+
) &&
90+
check_config non-bare/.git false unset
91+
'
92+
93+
test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' '
94+
95+
(
96+
unset GIT_CONFIG &&
97+
mkdir git-dir-wt-1.git &&
98+
GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init
99+
) &&
100+
check_config git-dir-wt-1.git false "$(pwd)"
101+
'
102+
103+
test_expect_success 'GIT_DIR & GIT_WORK_TREE (2)' '
104+
105+
if (
106+
unset GIT_CONFIG &&
107+
mkdir git-dir-wt-2.git &&
108+
GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-2.git git --bare init
109+
)
110+
then
111+
echo Should have failed -- --bare should not be used
112+
false
113+
fi
114+
'
115+
116+
test_done

0 commit comments

Comments
 (0)