Skip to content

Commit 31e26eb

Browse files
pcloudsgitster
authored andcommitted
setup.c: support multi-checkout repo setup
The repo setup procedure is updated to detect $GIT_DIR/commondir and set $GIT_COMMON_DIR properly. The core.worktree is ignored when $GIT_COMMON_DIR is set. This is because the config file is shared in multi-checkout setup, but checkout directories _are_ different. Making core.worktree effective in all checkouts mean it's back to a single checkout. Helped-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent e61a509 commit 31e26eb

9 files changed

Lines changed: 115 additions & 14 deletions

File tree

Documentation/config.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ false), while all other repositories are assumed to be bare (bare
393393

394394
core.worktree::
395395
Set the path to the root of the working tree.
396+
If GIT_COMMON_DIR environment variable is set, core.worktree
397+
is ignored and not used for determining the root of working tree.
396398
This can be overridden by the GIT_WORK_TREE environment
397399
variable and the '--work-tree' command-line option.
398400
The value can be an absolute path or relative to the path to

Documentation/git-rev-parse.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ If `$GIT_DIR` is not defined and the current directory
216216
is not detected to lie in a Git repository or work tree
217217
print a message to stderr and exit with nonzero status.
218218

219+
--git-common-dir::
220+
Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
221+
219222
--is-inside-git-dir::
220223
When the current working directory is below the repository
221224
directory print "true", otherwise "false".

builtin/rev-parse.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
762762
free(cwd);
763763
continue;
764764
}
765+
if (!strcmp(arg, "--git-common-dir")) {
766+
puts(get_git_common_dir());
767+
continue;
768+
}
765769
if (!strcmp(arg, "--resolve-git-dir")) {
766770
const char *gitdir = argv[++i];
767771
if (!gitdir)

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ extern char *get_object_directory(void);
437437
extern char *get_index_file(void);
438438
extern char *get_graft_file(void);
439439
extern int set_git_dir(const char *path);
440+
extern int get_common_dir(struct strbuf *sb, const char *gitdir);
440441
extern const char *get_git_namespace(void);
441442
extern const char *strip_namespace(const char *namespaced_ref);
442443
extern const char *get_git_work_tree(void);

environment.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,
142142

143143
static void setup_git_env(void)
144144
{
145+
struct strbuf sb = STRBUF_INIT;
145146
const char *gitfile;
146147
const char *shallow_file;
147148

@@ -150,12 +151,9 @@ static void setup_git_env(void)
150151
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
151152
gitfile = read_gitfile(git_dir);
152153
git_dir = xstrdup(gitfile ? gitfile : git_dir);
153-
git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
154-
if (git_common_dir) {
154+
if (get_common_dir(&sb, git_dir))
155155
git_common_dir_env = 1;
156-
git_common_dir = xstrdup(git_common_dir);
157-
} else
158-
git_common_dir = git_dir;
156+
git_common_dir = strbuf_detach(&sb, NULL);
159157
git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
160158
"objects", &git_db_env);
161159
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,

setup.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,15 @@ void verify_non_filename(const char *prefix, const char *arg)
224224
"'git <command> [<revision>...] -- [<file>...]'", arg);
225225
}
226226

227-
static void get_common_dir(struct strbuf *sb, const char *gitdir)
227+
int get_common_dir(struct strbuf *sb, const char *gitdir)
228228
{
229229
struct strbuf data = STRBUF_INIT;
230230
struct strbuf path = STRBUF_INIT;
231231
const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
232+
int ret = 0;
232233
if (git_common_dir) {
233234
strbuf_addstr(sb, git_common_dir);
234-
return;
235+
return 1;
235236
}
236237
strbuf_addf(&path, "%s/commondir", gitdir);
237238
if (file_exists(path.buf)) {
@@ -246,10 +247,12 @@ static void get_common_dir(struct strbuf *sb, const char *gitdir)
246247
strbuf_addf(&path, "%s/", gitdir);
247248
strbuf_addbuf(&path, &data);
248249
strbuf_addstr(sb, real_path(path.buf));
250+
ret = 1;
249251
} else
250252
strbuf_addstr(sb, gitdir);
251253
strbuf_release(&data);
252254
strbuf_release(&path);
255+
return ret;
253256
}
254257

255258
/*
@@ -340,13 +343,26 @@ void setup_work_tree(void)
340343
initialized = 1;
341344
}
342345

346+
static int check_repo_format(const char *var, const char *value, void *cb)
347+
{
348+
if (strcmp(var, "core.repositoryformatversion") == 0)
349+
repository_format_version = git_config_int(var, value);
350+
else if (strcmp(var, "core.sharedrepository") == 0)
351+
shared_repository = git_config_perm(var, value);
352+
return 0;
353+
}
354+
343355
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
344356
{
345357
struct strbuf sb = STRBUF_INIT;
346358
const char *repo_config;
359+
config_fn_t fn;
347360
int ret = 0;
348361

349-
get_common_dir(&sb, gitdir);
362+
if (get_common_dir(&sb, gitdir))
363+
fn = check_repo_format;
364+
else
365+
fn = check_repository_format_version;
350366
strbuf_addstr(&sb, "/config");
351367
repo_config = sb.buf;
352368

@@ -359,7 +375,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
359375
* Use a gentler version of git_config() to check if this repo
360376
* is a good one.
361377
*/
362-
git_config_early(check_repository_format_version, NULL, repo_config);
378+
git_config_early(fn, NULL, repo_config);
363379
if (GIT_REPO_VERSION < repository_format_version) {
364380
if (!nongit_ok)
365381
die ("Expected git repo version <= %d, found %d",
@@ -841,11 +857,10 @@ int git_config_perm(const char *var, const char *value)
841857

842858
int check_repository_format_version(const char *var, const char *value, void *cb)
843859
{
844-
if (strcmp(var, "core.repositoryformatversion") == 0)
845-
repository_format_version = git_config_int(var, value);
846-
else if (strcmp(var, "core.sharedrepository") == 0)
847-
shared_repository = git_config_perm(var, value);
848-
else if (strcmp(var, "core.bare") == 0) {
860+
int ret = check_repo_format(var, value, cb);
861+
if (ret)
862+
return ret;
863+
if (strcmp(var, "core.bare") == 0) {
849864
is_bare_repository_cfg = git_config_bool(var, value);
850865
if (is_bare_repository_cfg == 1)
851866
inside_work_tree = -1;

t/t1501-worktree.sh

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,80 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
346346
test_cmp expected actual
347347
'
348348

349+
test_expect_success 'Multi-worktree setup' '
350+
mkdir work &&
351+
mkdir -p repo.git/repos/foo &&
352+
cp repo.git/HEAD repo.git/index repo.git/repos/foo &&
353+
sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE
354+
'
355+
356+
test_expect_success 'GIT_DIR set (1)' '
357+
echo "gitdir: repo.git/repos/foo" >gitfile &&
358+
echo ../.. >repo.git/repos/foo/commondir &&
359+
(
360+
cd work &&
361+
GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
362+
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
363+
test_cmp expect actual
364+
)
365+
'
366+
367+
test_expect_success 'GIT_DIR set (2)' '
368+
echo "gitdir: repo.git/repos/foo" >gitfile &&
369+
echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
370+
(
371+
cd work &&
372+
GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
373+
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
374+
test_cmp expect actual
375+
)
376+
'
377+
378+
test_expect_success 'Auto discovery' '
379+
echo "gitdir: repo.git/repos/foo" >.git &&
380+
echo ../.. >repo.git/repos/foo/commondir &&
381+
(
382+
cd work &&
383+
git rev-parse --git-common-dir >actual &&
384+
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
385+
test_cmp expect actual &&
386+
echo haha >data1 &&
387+
git add data1 &&
388+
git ls-files --full-name :/ | grep data1 >actual &&
389+
echo work/data1 >expect &&
390+
test_cmp expect actual
391+
)
392+
'
393+
394+
test_expect_success '$GIT_DIR/common overrides core.worktree' '
395+
mkdir elsewhere &&
396+
git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" &&
397+
echo "gitdir: repo.git/repos/foo" >.git &&
398+
echo ../.. >repo.git/repos/foo/commondir &&
399+
(
400+
cd work &&
401+
git rev-parse --git-common-dir >actual &&
402+
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
403+
test_cmp expect actual &&
404+
echo haha >data2 &&
405+
git add data2 &&
406+
git ls-files --full-name :/ | grep data2 >actual &&
407+
echo work/data2 >expect &&
408+
test_cmp expect actual
409+
)
410+
'
411+
412+
test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
413+
echo "gitdir: repo.git/repos/foo" >.git &&
414+
echo ../.. >repo.git/repos/foo/commondir &&
415+
(
416+
cd work &&
417+
echo haha >data3 &&
418+
git --git-dir=../.git --work-tree=. add data3 &&
419+
git ls-files --full-name -- :/ | grep data3 >actual &&
420+
echo data3 >expect &&
421+
test_cmp expect actual
422+
)
423+
'
424+
349425
test_done

t/t1510-repo-setup.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ setup_env () {
106106
expect () {
107107
cat >"$1/expected" <<-EOF
108108
setup: git_dir: $2
109+
setup: git_common_dir: $2
109110
setup: worktree: $3
110111
setup: cwd: $4
111112
setup: prefix: $5

trace.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ void trace_repo_setup(const char *prefix)
312312
prefix = "(null)";
313313

314314
trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
315+
trace_printf_key(&key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
315316
trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
316317
trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
317318
trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));

0 commit comments

Comments
 (0)