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>maint
							parent
							
								
									e61a509a49
								
							
						
					
					
						commit
						31e26ebcb5
					
				|  | @ -393,6 +393,8 @@ false), while all other repositories are assumed to be bare (bare | |||
|  | ||||
| core.worktree:: | ||||
| 	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 | ||||
| 	variable and the '--work-tree' command-line option. | ||||
| 	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 | ||||
| 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:: | ||||
| 	When the current working directory is below the repository | ||||
| 	directory print "true", otherwise "false". | ||||
|  |  | |||
|  | @ -762,6 +762,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) | |||
| 				free(cwd); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (!strcmp(arg, "--git-common-dir")) { | ||||
| 				puts(get_git_common_dir()); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (!strcmp(arg, "--resolve-git-dir")) { | ||||
| 				const char *gitdir = argv[++i]; | ||||
| 				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_graft_file(void); | ||||
| 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 *strip_namespace(const char *namespaced_ref); | ||||
| 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) | ||||
| { | ||||
| 	struct strbuf sb = STRBUF_INIT; | ||||
| 	const char *gitfile; | ||||
| 	const char *shallow_file; | ||||
|  | ||||
|  | @ -150,12 +151,9 @@ static void setup_git_env(void) | |||
| 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; | ||||
| 	gitfile = read_gitfile(git_dir); | ||||
| 	git_dir = xstrdup(gitfile ? gitfile : git_dir); | ||||
| 	git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT); | ||||
| 	if (git_common_dir) { | ||||
| 	if (get_common_dir(&sb, git_dir)) | ||||
| 		git_common_dir_env = 1; | ||||
| 		git_common_dir = xstrdup(git_common_dir); | ||||
| 	} else | ||||
| 		git_common_dir = git_dir; | ||||
| 	git_common_dir = strbuf_detach(&sb, NULL); | ||||
| 	git_object_dir = git_path_from_env(DB_ENVIRONMENT, git_common_dir, | ||||
| 					   "objects", &git_db_env); | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| 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 path = STRBUF_INIT; | ||||
| 	const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT); | ||||
| 	int ret = 0; | ||||
| 	if (git_common_dir) { | ||||
| 		strbuf_addstr(sb, git_common_dir); | ||||
| 		return; | ||||
| 		return 1; | ||||
| 	} | ||||
| 	strbuf_addf(&path, "%s/commondir", gitdir); | ||||
| 	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_addbuf(&path, &data); | ||||
| 		strbuf_addstr(sb, real_path(path.buf)); | ||||
| 		ret = 1; | ||||
| 	} else | ||||
| 		strbuf_addstr(sb, gitdir); | ||||
| 	strbuf_release(&data); | ||||
| 	strbuf_release(&path); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  | @ -340,13 +343,26 @@ void setup_work_tree(void) | |||
| 	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) | ||||
| { | ||||
| 	struct strbuf sb = STRBUF_INIT; | ||||
| 	const char *repo_config; | ||||
| 	config_fn_t fn; | ||||
| 	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"); | ||||
| 	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 | ||||
| 	 * 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 (!nongit_ok) | ||||
| 			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) | ||||
| { | ||||
| 	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); | ||||
| 	else if (strcmp(var, "core.bare") == 0) { | ||||
| 	int ret = check_repo_format(var, value, cb); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 	if (strcmp(var, "core.bare") == 0) { | ||||
| 		is_bare_repository_cfg = git_config_bool(var, value); | ||||
| 		if (is_bare_repository_cfg == 1) | ||||
| 			inside_work_tree = -1; | ||||
|  |  | |||
|  | @ -346,4 +346,80 @@ test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' ' | |||
| 	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 | ||||
|  |  | |||
|  | @ -106,6 +106,7 @@ setup_env () { | |||
| expect () { | ||||
| 	cat >"$1/expected" <<-EOF | ||||
| 	setup: git_dir: $2 | ||||
| 	setup: git_common_dir: $2 | ||||
| 	setup: worktree: $3 | ||||
| 	setup: cwd: $4 | ||||
| 	setup: prefix: $5 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								trace.c
								
								
								
								
							
							
						
						
									
										1
									
								
								trace.c
								
								
								
								
							|  | @ -312,6 +312,7 @@ void trace_repo_setup(const char *prefix) | |||
| 		prefix = "(null)"; | ||||
|  | ||||
| 	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: cwd: %s\n", quote_crnl(cwd)); | ||||
| 	trace_printf_key(&key, "setup: prefix: %s\n", quote_crnl(prefix)); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Nguyễn Thái Ngọc Duy
						Nguyễn Thái Ngọc Duy