setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when ..
				
					
				
			Commitmaintd95138e[1] attempted to fix a .git file problem by setting GIT_WORK_TREE whenever GIT_DIR is set. It sounded harmless because we handle GIT_DIR and GIT_WORK_TREE side by side for most commands, with two exceptions: git-init and git-clone. "git clone" is not happy withd95138e. This command ignores GIT_DIR but respects GIT_WORK_TREE [2] [3] which means it used to run fine from a hook, where GIT_DIR was set but GIT_WORK_TREE was not (*). Withd95138e, GIT_WORK_TREE is set all the time and git-clone interprets that as "I give you order to put the worktree here", usually against the user's intention. The solution ind95138eis reverted earlier, and instead we reuse the solution fromc056261[4]. It fixed another setup-messed- up-by-alias by saving and restoring env and spawning a new process, but for git-clone and git-init only. Now we conclude that setup-messed-up-by-alias is always evil. So the env restoration is done for _all_ commands, including external ones, whenever aliases are involved. It fixes whatd95138etried to fix, without upsetting git-clone-inside-hooks. The test fromd95138eremains to verify it's not broken by this. A new test is added to make sure git-clone-inside-hooks remains happy. (*) GIT_WORK_TREE was not set _most of the time_. In some cases GIT_WORK_TREE is set and git-clone will behave differently. The use of GIT_WORK_TREE to direct git-clone to put work tree elsewhere looks like a mistake because it causes surprises this way. But that's a separate story. [1]d95138e(setup: set env $GIT_WORK_TREE when work tree is set, like $GIT_DIR - 2015-06-26) [2]2beebd2(clone: create intermediate directories of destination repo - 2008-06-25) [3]20ccef4(make git-clone GIT_WORK_TREE aware - 2007-07-06) [4]c056261(git potty: restore environments after alias expansion - 2014-06-08) Reported-by: Anthony Sottile <asottile@umich.edu> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
							parent
							
								
									0d5466d244
								
							
						
					
					
						commit
						86d26f240f
					
				
							
								
								
									
										23
									
								
								git.c
								
								
								
								
							
							
						
						
									
										23
									
								
								git.c
								
								
								
								
							|  | @ -226,7 +226,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
| static int handle_alias(int *argcp, const char ***argv) | ||||
| { | ||||
| 	int envchanged = 0, ret = 0, saved_errno = errno; | ||||
| 	const char *subdir; | ||||
| 	int count, option_count; | ||||
| 	const char **new_argv; | ||||
| 	const char *alias_command; | ||||
|  | @ -234,7 +233,7 @@ static int handle_alias(int *argcp, const char ***argv) | |||
| 	int unused_nongit; | ||||
|  | ||||
| 	save_env_before_alias(); | ||||
| 	subdir = setup_git_directory_gently(&unused_nongit); | ||||
| 	setup_git_directory_gently(&unused_nongit); | ||||
|  | ||||
| 	alias_command = (*argv)[0]; | ||||
| 	alias_string = alias_lookup(alias_command); | ||||
|  | @ -292,8 +291,7 @@ static int handle_alias(int *argcp, const char ***argv) | |||
| 		ret = 1; | ||||
| 	} | ||||
|  | ||||
| 	if (subdir && chdir(subdir)) | ||||
| 		die_errno("Cannot change to '%s'", subdir); | ||||
| 	restore_env(); | ||||
|  | ||||
| 	errno = saved_errno; | ||||
|  | ||||
|  | @ -308,7 +306,6 @@ static int handle_alias(int *argcp, const char ***argv) | |||
|  * RUN_SETUP for reading from the configuration file. | ||||
|  */ | ||||
| #define NEED_WORK_TREE		(1<<3) | ||||
| #define NO_SETUP		(1<<4) | ||||
|  | ||||
| struct cmd_struct { | ||||
| 	const char *cmd; | ||||
|  | @ -389,7 +386,7 @@ static struct cmd_struct commands[] = { | |||
| 	{ "cherry", cmd_cherry, RUN_SETUP }, | ||||
| 	{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 	{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 	{ "clone", cmd_clone, NO_SETUP }, | ||||
| 	{ "clone", cmd_clone }, | ||||
| 	{ "column", cmd_column, RUN_SETUP_GENTLY }, | ||||
| 	{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE }, | ||||
| 	{ "commit-tree", cmd_commit_tree, RUN_SETUP }, | ||||
|  | @ -415,8 +412,8 @@ static struct cmd_struct commands[] = { | |||
| 	{ "hash-object", cmd_hash_object }, | ||||
| 	{ "help", cmd_help }, | ||||
| 	{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY }, | ||||
| 	{ "init", cmd_init_db, NO_SETUP }, | ||||
| 	{ "init-db", cmd_init_db, NO_SETUP }, | ||||
| 	{ "init", cmd_init_db }, | ||||
| 	{ "init-db", cmd_init_db }, | ||||
| 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP }, | ||||
| 	{ "log", cmd_log, RUN_SETUP }, | ||||
| 	{ "ls-files", cmd_ls_files, RUN_SETUP }, | ||||
|  | @ -528,9 +525,13 @@ static void handle_builtin(int argc, const char **argv) | |||
|  | ||||
| 	builtin = get_builtin(cmd); | ||||
| 	if (builtin) { | ||||
| 		if (saved_env_before_alias && (builtin->option & NO_SETUP)) | ||||
| 			restore_env(); | ||||
| 		else | ||||
| 		/* | ||||
| 		 * XXX: if we can figure out cases where it is _safe_ | ||||
| 		 * to do, we can avoid spawning a new process when | ||||
| 		 * saved_env_before_alias is true | ||||
| 		 * (i.e. setup_git_dir* has been run once) | ||||
| 		 */ | ||||
| 		if (!saved_env_before_alias) | ||||
| 			exit(run_builtin(builtin, argc, argv)); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -99,7 +99,7 @@ test_expect_success 'check rev-list' ' | |||
| 	test "$SHA" = "$(git rev-list HEAD)" | ||||
| ' | ||||
|  | ||||
| test_expect_failure 'setup_git_dir twice in subdir' ' | ||||
| test_expect_success 'setup_git_dir twice in subdir' ' | ||||
| 	git init sgd && | ||||
| 	( | ||||
| 		cd sgd && | ||||
|  |  | |||
|  | @ -65,6 +65,29 @@ test_expect_success 'clone respects GIT_WORK_TREE' ' | |||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'clone from hooks' ' | ||||
|  | ||||
| 	test_create_repo r0 && | ||||
| 	cd r0 && | ||||
| 	test_commit initial && | ||||
| 	cd .. && | ||||
| 	git init r1 && | ||||
| 	cd r1 && | ||||
| 	cat >.git/hooks/pre-commit <<-\EOF && | ||||
| 	#!/bin/sh | ||||
| 	git clone ../r0 ../r2 | ||||
| 	exit 1 | ||||
| 	EOF | ||||
| 	chmod u+x .git/hooks/pre-commit && | ||||
| 	: >file && | ||||
| 	git add file && | ||||
| 	test_must_fail git commit -m invoke-hook && | ||||
| 	cd .. && | ||||
| 	test_cmp r0/.git/HEAD r2/.git/HEAD && | ||||
| 	test_cmp r0/initial.t r2/initial.t | ||||
|  | ||||
| ' | ||||
|  | ||||
| test_expect_success 'clone creates intermediate directories' ' | ||||
|  | ||||
| 	git clone src long/path/to/dst && | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Nguyễn Thái Ngọc Duy
						Nguyễn Thái Ngọc Duy