submodule: avoid auto-discovery in prepare_submodule_repo_env()
The function is used to set up the environment variable used in a subprocess we spawn in a submodule directory. The callers set up a child_process structure, find the working tree path of one submodule and set .dir field to it, and then use start_command() API to spawn the subprocess like "status", "fetch", etc. When this happens, we expect that the ".git" (either a directory or a gitfile that points at the real location) in the current working directory of the subprocess MUST be the repository for the submodule. If this ".git" thing is a corrupt repository, however, because prepare_submodule_repo_env() unsets GIT_DIR and GIT_WORK_TREE, the subprocess will see ".git", thinks it is not a repository, and attempt to find one by going up, likely to end up in finding the repository of the superproject. In some codepaths, this will cause a command run with the "--recurse-submodules" option to recurse forever. By exporting GIT_DIR=.git, disable the auto-discovery logic in the subprocess, which would instead stop it and report an error. The test illustrates existing problems in a few callsites of this function. Without this fix, "git fetch --recurse-submodules", "git status" and "git diff" keep recursing forever. Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									e0c1ceafc5
								
							
						
					
					
						commit
						10f5c52656
					
				|  | @ -1160,4 +1160,5 @@ void prepare_submodule_repo_env(struct argv_array *out) | |||
| 		if (strcmp(*var, CONFIG_DATA_ENVIRONMENT)) | ||||
| 			argv_array_push(out, *var); | ||||
| 	} | ||||
| 	argv_array_push(out, "GIT_DIR=.git"); | ||||
| } | ||||
|  |  | |||
|  | @ -485,4 +485,39 @@ test_expect_success 'fetching submodules respects parallel settings' ' | |||
| 	) | ||||
| ' | ||||
|  | ||||
| test_expect_success 'fetching submodule into a broken repository' ' | ||||
| 	# Prepare src and src/sub nested in it | ||||
| 	git init src && | ||||
| 	( | ||||
| 		cd src && | ||||
| 		git init sub && | ||||
| 		git -C sub commit --allow-empty -m "initial in sub" && | ||||
| 		git submodule add -- ./sub sub && | ||||
| 		git commit -m "initial in top" | ||||
| 	) && | ||||
|  | ||||
| 	# Clone the old-fashoned way | ||||
| 	git clone src dst && | ||||
| 	git -C dst clone ../src/sub sub && | ||||
|  | ||||
| 	# Make sure that old-fashoned layout is still supported | ||||
| 	git -C dst status && | ||||
|  | ||||
| 	# "diff" would find no change | ||||
| 	git -C dst diff --exit-code && | ||||
|  | ||||
| 	# Recursive-fetch works fine | ||||
| 	git -C dst fetch --recurse-submodules && | ||||
|  | ||||
| 	# Break the receiving submodule | ||||
| 	rm -f dst/sub/.git/HEAD && | ||||
|  | ||||
| 	# NOTE: without the fix the following tests will recurse forever! | ||||
| 	# They should terminate with an error. | ||||
|  | ||||
| 	test_must_fail git -C dst status && | ||||
| 	test_must_fail git -C dst diff && | ||||
| 	test_must_fail git -C dst fetch --recurse-submodules | ||||
| ' | ||||
|  | ||||
| test_done | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano