alias: use the early config machinery to expand aliases
Instead of discovering the .git/ directory, reading the config and then trying to painstakingly reset all the global state if we did not find a matching alias, let's use the early config machinery instead. It may look like unnecessary work to discover the .git/ directory in the early config machinery and then call setup_git_directory_gently() in the case of a shell alias, repeating the very same discovery *again*. However, we have to do this as the early config machinery takes pains *not* to touch any global state, while shell aliases expect a possibly changed working directory and at least the GIT_PREFIX and GIT_DIR variables to be set. This change also fixes a known issue where Git tried to read the pager config from an incorrect path in a subdirectory of a Git worktree if an alias expanded to a shell command. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									3f9c5dfb71
								
							
						
					
					
						commit
						a9bcf6586d
					
				
							
								
								
									
										28
									
								
								alias.c
								
								
								
								
							
							
						
						
									
										28
									
								
								alias.c
								
								
								
								
							|  | @ -1,14 +1,28 @@ | ||||||
| #include "cache.h" | #include "cache.h" | ||||||
|  |  | ||||||
|  | struct config_alias_data { | ||||||
|  | 	const char *alias; | ||||||
|  | 	char *v; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int config_alias_cb(const char *key, const char *value, void *d) | ||||||
|  | { | ||||||
|  | 	struct config_alias_data *data = d; | ||||||
|  | 	const char *p; | ||||||
|  |  | ||||||
|  | 	if (skip_prefix(key, "alias.", &p) && !strcmp(p, data->alias)) | ||||||
|  | 		return git_config_string((const char **)&data->v, key, value); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| char *alias_lookup(const char *alias) | char *alias_lookup(const char *alias) | ||||||
| { | { | ||||||
| 	char *v = NULL; | 	struct config_alias_data data = { alias, NULL }; | ||||||
| 	struct strbuf key = STRBUF_INIT; |  | ||||||
| 	strbuf_addf(&key, "alias.%s", alias); | 	read_early_config(config_alias_cb, &data); | ||||||
| 	if (git_config_key_is_valid(key.buf)) |  | ||||||
| 		git_config_get_string(key.buf, &v); | 	return data.v; | ||||||
| 	strbuf_release(&key); |  | ||||||
| 	return v; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #define SPLIT_CMDLINE_BAD_ENDING 1 | #define SPLIT_CMDLINE_BAD_ENDING 1 | ||||||
|  |  | ||||||
							
								
								
									
										55
									
								
								git.c
								
								
								
								
							
							
						
						
									
										55
									
								
								git.c
								
								
								
								
							|  | @ -16,50 +16,6 @@ const char git_more_info_string[] = | ||||||
| 	   "to read about a specific subcommand or concept."); | 	   "to read about a specific subcommand or concept."); | ||||||
|  |  | ||||||
| static int use_pager = -1; | static int use_pager = -1; | ||||||
| static char *orig_cwd; |  | ||||||
| static const char *env_names[] = { |  | ||||||
| 	GIT_DIR_ENVIRONMENT, |  | ||||||
| 	GIT_WORK_TREE_ENVIRONMENT, |  | ||||||
| 	GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, |  | ||||||
| 	GIT_PREFIX_ENVIRONMENT |  | ||||||
| }; |  | ||||||
| static char *orig_env[4]; |  | ||||||
| static int save_restore_env_balance; |  | ||||||
|  |  | ||||||
| static void save_env_before_alias(void) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
|  |  | ||||||
| 	assert(save_restore_env_balance == 0); |  | ||||||
| 	save_restore_env_balance = 1; |  | ||||||
| 	orig_cwd = xgetcwd(); |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(env_names); i++) { |  | ||||||
| 		orig_env[i] = getenv(env_names[i]); |  | ||||||
| 		orig_env[i] = xstrdup_or_null(orig_env[i]); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void restore_env(int external_alias) |  | ||||||
| { |  | ||||||
| 	int i; |  | ||||||
|  |  | ||||||
| 	assert(save_restore_env_balance == 1); |  | ||||||
| 	save_restore_env_balance = 0; |  | ||||||
| 	if (!external_alias && orig_cwd && chdir(orig_cwd)) |  | ||||||
| 		die_errno("could not move to %s", orig_cwd); |  | ||||||
| 	free(orig_cwd); |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(env_names); i++) { |  | ||||||
| 		if (external_alias && |  | ||||||
| 		    !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT)) |  | ||||||
| 			continue; |  | ||||||
| 		if (orig_env[i]) { |  | ||||||
| 			setenv(env_names[i], orig_env[i], 1); |  | ||||||
| 			free(orig_env[i]); |  | ||||||
| 		} else { |  | ||||||
| 			unsetenv(env_names[i]); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void commit_pager_choice(void) { | static void commit_pager_choice(void) { | ||||||
| 	switch (use_pager) { | 	switch (use_pager) { | ||||||
|  | @ -250,19 +206,18 @@ static int handle_alias(int *argcp, const char ***argv) | ||||||
| 	const char **new_argv; | 	const char **new_argv; | ||||||
| 	const char *alias_command; | 	const char *alias_command; | ||||||
| 	char *alias_string; | 	char *alias_string; | ||||||
| 	int unused_nongit; |  | ||||||
|  |  | ||||||
| 	save_env_before_alias(); |  | ||||||
| 	setup_git_directory_gently(&unused_nongit); |  | ||||||
|  |  | ||||||
| 	alias_command = (*argv)[0]; | 	alias_command = (*argv)[0]; | ||||||
| 	alias_string = alias_lookup(alias_command); | 	alias_string = alias_lookup(alias_command); | ||||||
| 	if (alias_string) { | 	if (alias_string) { | ||||||
| 		if (alias_string[0] == '!') { | 		if (alias_string[0] == '!') { | ||||||
| 			struct child_process child = CHILD_PROCESS_INIT; | 			struct child_process child = CHILD_PROCESS_INIT; | ||||||
|  | 			int nongit_ok; | ||||||
|  |  | ||||||
|  | 			/* Aliases expect GIT_PREFIX, GIT_DIR etc to be set */ | ||||||
|  | 			setup_git_directory_gently(&nongit_ok); | ||||||
|  |  | ||||||
| 			commit_pager_choice(); | 			commit_pager_choice(); | ||||||
| 			restore_env(1); |  | ||||||
|  |  | ||||||
| 			child.use_shell = 1; | 			child.use_shell = 1; | ||||||
| 			argv_array_push(&child.args, alias_string + 1); | 			argv_array_push(&child.args, alias_string + 1); | ||||||
|  | @ -308,8 +263,6 @@ static int handle_alias(int *argcp, const char ***argv) | ||||||
| 		ret = 1; | 		ret = 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	restore_env(0); |  | ||||||
|  |  | ||||||
| 	errno = saved_errno; | 	errno = saved_errno; | ||||||
|  |  | ||||||
| 	return ret; | 	return ret; | ||||||
|  |  | ||||||
|  | @ -391,7 +391,7 @@ test_expect_success TTY 'core.pager in repo config works and retains cwd' ' | ||||||
| 	) | 	) | ||||||
| ' | ' | ||||||
|  |  | ||||||
| test_expect_failure TTY 'core.pager is found via alias in subdirectory' ' | test_expect_success TTY 'core.pager is found via alias in subdirectory' ' | ||||||
| 	sane_unset GIT_PAGER && | 	sane_unset GIT_PAGER && | ||||||
| 	test_config core.pager "cat >via-alias" && | 	test_config core.pager "cat >via-alias" && | ||||||
| 	( | 	( | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Johannes Schindelin
						Johannes Schindelin