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>
This commit is contained in:
parent
e61a509a49
commit
31e26ebcb5
@ -393,6 +393,8 @@ false), while all other repositories are assumed to be bare (bare
|
|||||||
|
|
||||||
core.worktree::
|
core.worktree::
|
||||||
Set the path to the root of the working tree.
|
Set the path to the root of the working tree.
|
||||||
|
If GIT_COMMON_DIR environment variable is set, core.worktree
|
||||||
|
is ignored and not used for determining the root of working tree.
|
||||||
This can be overridden by the GIT_WORK_TREE environment
|
This can be overridden by the GIT_WORK_TREE environment
|
||||||
variable and the '--work-tree' command-line option.
|
variable and the '--work-tree' command-line option.
|
||||||
The value can be an absolute path or relative to the path to
|
The value can be an absolute path or relative to the path to
|
||||||
|
@ -216,6 +216,9 @@ If `$GIT_DIR` is not defined and the current directory
|
|||||||
is not detected to lie in a Git repository or work tree
|
is not detected to lie in a Git repository or work tree
|
||||||
print a message to stderr and exit with nonzero status.
|
print a message to stderr and exit with nonzero status.
|
||||||
|
|
||||||
|
--git-common-dir::
|
||||||
|
Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
|
||||||
|
|
||||||
--is-inside-git-dir::
|
--is-inside-git-dir::
|
||||||
When the current working directory is below the repository
|
When the current working directory is below the repository
|
||||||
directory print "true", otherwise "false".
|
directory print "true", otherwise "false".
|
||||||
|
@ -762,6 +762,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
|||||||
free(cwd);
|
free(cwd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--git-common-dir")) {
|
||||||
|
puts(get_git_common_dir());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(arg, "--resolve-git-dir")) {
|
if (!strcmp(arg, "--resolve-git-dir")) {
|
||||||
const char *gitdir = argv[++i];
|
const char *gitdir = argv[++i];
|
||||||
if (!gitdir)
|
if (!gitdir)
|
||||||
|
1
cache.h
1
cache.h
@ -437,6 +437,7 @@ extern char *get_object_directory(void);
|
|||||||
extern char *get_index_file(void);
|
extern char *get_index_file(void);
|
||||||
extern char *get_graft_file(void);
|
extern char *get_graft_file(void);
|
||||||
extern int set_git_dir(const char *path);
|
extern int set_git_dir(const char *path);
|
||||||
|
extern int get_common_dir(struct strbuf *sb, const char *gitdir);
|
||||||
extern const char *get_git_namespace(void);
|
extern const char *get_git_namespace(void);
|
||||||
extern const char *strip_namespace(const char *namespaced_ref);
|
extern const char *strip_namespace(const char *namespaced_ref);
|
||||||
extern const char *get_git_work_tree(void);
|
extern const char *get_git_work_tree(void);
|
||||||
|
@ -142,6 +142,7 @@ static char *git_path_from_env(const char *envvar, const char *git_dir,
|
|||||||
|
|
||||||
static void setup_git_env(void)
|
static void setup_git_env(void)
|
||||||
{
|
{
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
const char *gitfile;
|
const char *gitfile;
|
||||||
const char *shallow_file;
|
const char *shallow_file;
|
||||||
|
|
||||||
@ -150,12 +151,9 @@ static void setup_git_env(void)
|
|||||||
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
|
||||||
gitfile = read_gitfile(git_dir);
|
gitfile = read_gitfile(git_dir);
|
||||||
git_dir = xstrdup(gitfile ? gitfile : git_dir);
|
git_dir = xstrdup(gitfile ? gitfile : git_dir);
|
||||||
git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
|
if (get_common_dir(&sb, git_dir))
|
||||||
if (git_common_dir) {
|
|
||||||
git_common_dir_env = 1;
|
git_common_dir_env = 1;
|
||||||
git_common_dir = xstrdup(git_common_dir);
|
git_common_dir = strbuf_detach(&sb, NULL);
|
||||||
} else
|
|
||||||
git_common_dir = git_dir;
|
|
||||||
git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
|
git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir,
|
||||||
"objects", &git_db_env);
|
"objects", &git_db_env);
|
||||||
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
|
git_index_file = git_path_from_env(INDEX_ENVIRONMENT, git_dir,
|
||||||
|
33
setup.c
33
setup.c
@ -224,14 +224,15 @@ void verify_non_filename(const char *prefix, const char *arg)
|
|||||||
"'git <command> [<revision>...] -- [<file>...]'", arg);
|
"'git <command> [<revision>...] -- [<file>...]'", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_common_dir(struct strbuf *sb, const char *gitdir)
|
int get_common_dir(struct strbuf *sb, const char *gitdir)
|
||||||
{
|
{
|
||||||
struct strbuf data = STRBUF_INIT;
|
struct strbuf data = STRBUF_INIT;
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
|
const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT);
|
||||||
|
int ret = 0;
|
||||||
if (git_common_dir) {
|
if (git_common_dir) {
|
||||||
strbuf_addstr(sb, git_common_dir);
|
strbuf_addstr(sb, git_common_dir);
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
strbuf_addf(&path, "%s/commondir", gitdir);
|
strbuf_addf(&path, "%s/commondir", gitdir);
|
||||||
if (file_exists(path.buf)) {
|
if (file_exists(path.buf)) {
|
||||||
@ -246,10 +247,12 @@ static void get_common_dir(struct strbuf *sb, const char *gitdir)
|
|||||||
strbuf_addf(&path, "%s/", gitdir);
|
strbuf_addf(&path, "%s/", gitdir);
|
||||||
strbuf_addbuf(&path, &data);
|
strbuf_addbuf(&path, &data);
|
||||||
strbuf_addstr(sb, real_path(path.buf));
|
strbuf_addstr(sb, real_path(path.buf));
|
||||||
|
ret = 1;
|
||||||
} else
|
} else
|
||||||
strbuf_addstr(sb, gitdir);
|
strbuf_addstr(sb, gitdir);
|
||||||
strbuf_release(&data);
|
strbuf_release(&data);
|
||||||
strbuf_release(&path);
|
strbuf_release(&path);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -340,13 +343,26 @@ void setup_work_tree(void)
|
|||||||
initialized = 1;
|
initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_repo_format(const char *var, const char *value, void *cb)
|
||||||
|
{
|
||||||
|
if (strcmp(var, "core.repositoryformatversion") == 0)
|
||||||
|
repository_format_version = git_config_int(var, value);
|
||||||
|
else if (strcmp(var, "core.sharedrepository") == 0)
|
||||||
|
shared_repository = git_config_perm(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
|
static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
|
||||||
{
|
{
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
const char *repo_config;
|
const char *repo_config;
|
||||||
|
config_fn_t fn;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
get_common_dir(&sb, gitdir);
|
if (get_common_dir(&sb, gitdir))
|
||||||
|
fn = check_repo_format;
|
||||||
|
else
|
||||||
|
fn = check_repository_format_version;
|
||||||
strbuf_addstr(&sb, "/config");
|
strbuf_addstr(&sb, "/config");
|
||||||
repo_config = sb.buf;
|
repo_config = sb.buf;
|
||||||
|
|
||||||
@ -359,7 +375,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
|
|||||||
* Use a gentler version of git_config() to check if this repo
|
* Use a gentler version of git_config() to check if this repo
|
||||||
* is a good one.
|
* is a good one.
|
||||||
*/
|
*/
|
||||||
git_config_early(check_repository_format_version, NULL, repo_config);
|
git_config_early(fn, NULL, repo_config);
|
||||||
if (GIT_REPO_VERSION < repository_format_version) {
|
if (GIT_REPO_VERSION < repository_format_version) {
|
||||||
if (!nongit_ok)
|
if (!nongit_ok)
|
||||||
die ("Expected git repo version <= %d, found %d",
|
die ("Expected git repo version <= %d, found %d",
|
||||||
@ -841,11 +857,10 @@ int git_config_perm(const char *var, const char *value)
|
|||||||
|
|
||||||
int check_repository_format_version(const char *var, const char *value, void *cb)
|
int check_repository_format_version(const char *var, const char *value, void *cb)
|
||||||
{
|
{
|
||||||
if (strcmp(var, "core.repositoryformatversion") == 0)
|
int ret = check_repo_format(var, value, cb);
|
||||||
repository_format_version = git_config_int(var, value);
|
if (ret)
|
||||||
else if (strcmp(var, "core.sharedrepository") == 0)
|
return ret;
|
||||||
shared_repository = git_config_perm(var, value);
|
if (strcmp(var, "core.bare") == 0) {
|
||||||
else if (strcmp(var, "core.bare") == 0) {
|
|
||||||
is_bare_repository_cfg = git_config_bool(var, value);
|
is_bare_repository_cfg = git_config_bool(var, value);
|
||||||
if (is_bare_repository_cfg == 1)
|
if (is_bare_repository_cfg == 1)
|
||||||
inside_work_tree = -1;
|
inside_work_tree = -1;
|
||||||
|
@ -346,4 +346,80 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
|
|||||||
test_cmp expected actual
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'Multi-worktree setup' '
|
||||||
|
mkdir work &&
|
||||||
|
mkdir -p repo.git/repos/foo &&
|
||||||
|
cp repo.git/HEAD repo.git/index repo.git/repos/foo &&
|
||||||
|
sane_unset GIT_DIR GIT_CONFIG GIT_WORK_TREE
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'GIT_DIR set (1)' '
|
||||||
|
echo "gitdir: repo.git/repos/foo" >gitfile &&
|
||||||
|
echo ../.. >repo.git/repos/foo/commondir &&
|
||||||
|
(
|
||||||
|
cd work &&
|
||||||
|
GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
|
||||||
|
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'GIT_DIR set (2)' '
|
||||||
|
echo "gitdir: repo.git/repos/foo" >gitfile &&
|
||||||
|
echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
|
||||||
|
(
|
||||||
|
cd work &&
|
||||||
|
GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
|
||||||
|
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'Auto discovery' '
|
||||||
|
echo "gitdir: repo.git/repos/foo" >.git &&
|
||||||
|
echo ../.. >repo.git/repos/foo/commondir &&
|
||||||
|
(
|
||||||
|
cd work &&
|
||||||
|
git rev-parse --git-common-dir >actual &&
|
||||||
|
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo haha >data1 &&
|
||||||
|
git add data1 &&
|
||||||
|
git ls-files --full-name :/ | grep data1 >actual &&
|
||||||
|
echo work/data1 >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '$GIT_DIR/common overrides core.worktree' '
|
||||||
|
mkdir elsewhere &&
|
||||||
|
git --git-dir=repo.git config core.worktree "$TRASH_DIRECTORY/elsewhere" &&
|
||||||
|
echo "gitdir: repo.git/repos/foo" >.git &&
|
||||||
|
echo ../.. >repo.git/repos/foo/commondir &&
|
||||||
|
(
|
||||||
|
cd work &&
|
||||||
|
git rev-parse --git-common-dir >actual &&
|
||||||
|
test-path-utils real_path "$TRASH_DIRECTORY/repo.git" >expect &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
echo haha >data2 &&
|
||||||
|
git add data2 &&
|
||||||
|
git ls-files --full-name :/ | grep data2 >actual &&
|
||||||
|
echo work/data2 >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
|
||||||
|
echo "gitdir: repo.git/repos/foo" >.git &&
|
||||||
|
echo ../.. >repo.git/repos/foo/commondir &&
|
||||||
|
(
|
||||||
|
cd work &&
|
||||||
|
echo haha >data3 &&
|
||||||
|
git --git-dir=../.git --work-tree=. add data3 &&
|
||||||
|
git ls-files --full-name -- :/ | grep data3 >actual &&
|
||||||
|
echo data3 >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
@ -106,6 +106,7 @@ setup_env () {
|
|||||||
expect () {
|
expect () {
|
||||||
cat >"$1/expected" <<-EOF
|
cat >"$1/expected" <<-EOF
|
||||||
setup: git_dir: $2
|
setup: git_dir: $2
|
||||||
|
setup: git_common_dir: $2
|
||||||
setup: worktree: $3
|
setup: worktree: $3
|
||||||
setup: cwd: $4
|
setup: cwd: $4
|
||||||
setup: prefix: $5
|
setup: prefix: $5
|
||||||
|
1
trace.c
1
trace.c
@ -312,6 +312,7 @@ void trace_repo_setup(const char *prefix)
|
|||||||
prefix = "(null)";
|
prefix = "(null)";
|
||||||
|
|
||||||
trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
|
trace_printf_key(&key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
|
||||||
|
trace_printf_key(&key, "setup: git_common_dir: %s\n", quote_crnl(get_git_common_dir()));
|
||||||
trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
|
trace_printf_key(&key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
|
||||||
trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
|
trace_printf_key(&key, "setup: cwd: %s\n", quote_crnl(cwd));
|
||||||
trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
|
trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix));
|
||||||
|
Loading…
Reference in New Issue
Block a user