diff options
Diffstat (limited to 'git.c')
| -rw-r--r-- | git.c | 158 | 
1 files changed, 116 insertions, 42 deletions
@@ -1,25 +1,59 @@  #include "builtin.h" -#include "cache.h"  #include "exec_cmd.h"  #include "help.h" -#include "quote.h"  #include "run-command.h" -#include "commit.h"  const char git_usage_string[] =  	"git [--version] [--help] [-C <path>] [-c name=value]\n"  	"           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n" -	"           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n" +	"           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"  	"           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"  	"           <command> [<args>]";  const char git_more_info_string[] = -	N_("'git help -a' and 'git help -g' lists available subcommands and some\n" +	N_("'git help -a' and 'git help -g' list available subcommands and some\n"  	   "concept guides. See 'git help <command>' or 'git help <concept>'\n"  	   "to read about a specific subcommand or concept.");  static struct startup_info git_startup_info;  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 saved_environment; + +static void save_env(void) +{ +	int i; +	if (saved_environment) +		return; +	saved_environment = 1; +	orig_cwd = xgetcwd(); +	for (i = 0; i < ARRAY_SIZE(env_names); i++) { +		orig_env[i] = getenv(env_names[i]); +		if (orig_env[i]) +			orig_env[i] = xstrdup(orig_env[i]); +	} +} + +static void restore_env(void) +{ +	int i; +	if (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 (orig_env[i]) +			setenv(env_names[i], orig_env[i], 1); +		else +			unsetenv(env_names[i]); +	} +}  static void commit_pager_choice(void) {  	switch (use_pager) { @@ -54,8 +88,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)  		/*  		 * Check remaining flags.  		 */ -		if (starts_with(cmd, "--exec-path")) { -			cmd += 11; +		if (skip_prefix(cmd, "--exec-path", &cmd)) {  			if (*cmd == '=')  				git_set_argv_exec_path(cmd + 1);  			else { @@ -92,8 +125,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)  				*envchanged = 1;  			(*argv)++;  			(*argc)--; -		} else if (starts_with(cmd, "--git-dir=")) { -			setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1); +		} else if (skip_prefix(cmd, "--git-dir=", &cmd)) { +			setenv(GIT_DIR_ENVIRONMENT, cmd, 1);  			if (envchanged)  				*envchanged = 1;  		} else if (!strcmp(cmd, "--namespace")) { @@ -106,8 +139,8 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)  				*envchanged = 1;  			(*argv)++;  			(*argc)--; -		} else if (starts_with(cmd, "--namespace=")) { -			setenv(GIT_NAMESPACE_ENVIRONMENT, cmd + 12, 1); +		} else if (skip_prefix(cmd, "--namespace=", &cmd)) { +			setenv(GIT_NAMESPACE_ENVIRONMENT, cmd, 1);  			if (envchanged)  				*envchanged = 1;  		} else if (!strcmp(cmd, "--work-tree")) { @@ -120,14 +153,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)  				*envchanged = 1;  			(*argv)++;  			(*argc)--; -		} else if (starts_with(cmd, "--work-tree=")) { -			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1); +		} else if (skip_prefix(cmd, "--work-tree=", &cmd)) { +			setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);  			if (envchanged)  				*envchanged = 1;  		} else if (!strcmp(cmd, "--bare")) { -			static char git_dir[PATH_MAX+1]; +			char *cwd = xgetcwd();  			is_bare_repository_cfg = 1; -			setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0); +			setenv(GIT_DIR_ENVIRONMENT, cwd, 0); +			free(cwd);  			setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);  			if (envchanged)  				*envchanged = 1; @@ -170,10 +204,12 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)  				fprintf(stderr, "No directory given for -C.\n" );  				usage(git_usage_string);  			} -			if (chdir((*argv)[1])) -				die_errno("Cannot change to '%s'", (*argv)[1]); -			if (envchanged) -				*envchanged = 1; +			if ((*argv)[1][0]) { +				if (chdir((*argv)[1])) +					die_errno("Cannot change to '%s'", (*argv)[1]); +				if (envchanged) +					*envchanged = 1; +			}  			(*argv)++;  			(*argc)--;  		} else { @@ -245,8 +281,7 @@ static int handle_alias(int *argcp, const char ***argv)  				  "trace: alias expansion: %s =>",  				  alias_command); -		new_argv = xrealloc(new_argv, sizeof(char *) * -				    (count + *argcp)); +		REALLOC_ARRAY(new_argv, count + *argcp);  		/* insert after command name */  		memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); @@ -272,6 +307,7 @@ 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; @@ -290,7 +326,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)  	if (!help) {  		if (p->option & RUN_SETUP)  			prefix = setup_git_directory(); -		if (p->option & RUN_SETUP_GENTLY) { +		else if (p->option & RUN_SETUP_GENTLY) {  			int nongit_ok;  			prefix = setup_git_directory_gently(&nongit_ok);  		} @@ -334,6 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)  static struct cmd_struct commands[] = {  	{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE }, +	{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },  	{ "annotate", cmd_annotate, RUN_SETUP },  	{ "apply", cmd_apply, RUN_SETUP_GENTLY },  	{ "archive", cmd_archive }, @@ -352,7 +389,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 }, +	{ "clone", cmd_clone, NO_SETUP },  	{ "column", cmd_column, RUN_SETUP_GENTLY },  	{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },  	{ "commit-tree", cmd_commit_tree, RUN_SETUP }, @@ -378,8 +415,9 @@ 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 }, -	{ "init-db", cmd_init_db }, +	{ "init", cmd_init_db, NO_SETUP }, +	{ "init-db", cmd_init_db, NO_SETUP }, +	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },  	{ "log", cmd_log, RUN_SETUP },  	{ "ls-files", cmd_ls_files, RUN_SETUP },  	{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, @@ -408,6 +446,7 @@ static struct cmd_struct commands[] = {  	{ "pickaxe", cmd_blame, RUN_SETUP },  	{ "prune", cmd_prune, RUN_SETUP },  	{ "prune-packed", cmd_prune_packed, RUN_SETUP }, +	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },  	{ "push", cmd_push, RUN_SETUP },  	{ "read-tree", cmd_read_tree, RUN_SETUP },  	{ "receive-pack", cmd_receive_pack }, @@ -431,6 +470,7 @@ static struct cmd_struct commands[] = {  	{ "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },  	{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },  	{ "stripspace", cmd_stripspace }, +	{ "submodule--helper", cmd_submodule__helper, RUN_SETUP },  	{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },  	{ "tag", cmd_tag, RUN_SETUP },  	{ "unpack-file", cmd_unpack_file, RUN_SETUP }, @@ -441,22 +481,29 @@ static struct cmd_struct commands[] = {  	{ "upload-archive", cmd_upload_archive },  	{ "upload-archive--writer", cmd_upload_archive_writer },  	{ "var", cmd_var, RUN_SETUP_GENTLY }, +	{ "verify-commit", cmd_verify_commit, RUN_SETUP },  	{ "verify-pack", cmd_verify_pack },  	{ "verify-tag", cmd_verify_tag, RUN_SETUP },  	{ "version", cmd_version },  	{ "whatchanged", cmd_whatchanged, RUN_SETUP }, +	{ "worktree", cmd_worktree, RUN_SETUP },  	{ "write-tree", cmd_write_tree, RUN_SETUP },  }; -int is_builtin(const char *s) +static struct cmd_struct *get_builtin(const char *s)  {  	int i;  	for (i = 0; i < ARRAY_SIZE(commands); i++) { -		struct cmd_struct *p = commands+i; +		struct cmd_struct *p = commands + i;  		if (!strcmp(s, p->cmd)) -			return 1; +			return p;  	} -	return 0; +	return NULL; +} + +int is_builtin(const char *s) +{ +	return !!get_builtin(s);  }  static void handle_builtin(int argc, const char **argv) @@ -464,6 +511,7 @@ static void handle_builtin(int argc, const char **argv)  	const char *cmd = argv[0];  	int i;  	static const char ext[] = STRIP_EXTENSION; +	struct cmd_struct *builtin;  	if (sizeof(ext) > 1) {  		i = strlen(argv[0]) - strlen(ext); @@ -480,11 +528,12 @@ static void handle_builtin(int argc, const char **argv)  		argv[0] = cmd = "help";  	} -	for (i = 0; i < ARRAY_SIZE(commands); i++) { -		struct cmd_struct *p = commands+i; -		if (strcmp(p->cmd, cmd)) -			continue; -		exit(run_builtin(p, argc, argv)); +	builtin = get_builtin(cmd); +	if (builtin) { +		if (saved_environment && (builtin->option & NO_SETUP)) +			restore_env(); +		else +			exit(run_builtin(builtin, argc, argv));  	}  } @@ -539,7 +588,10 @@ static int run_argv(int *argcp, const char ***argv)  		 * of overriding "git log" with "git show" by having  		 * alias.log = show  		 */ -		if (done_alias || !handle_alias(argcp, argv)) +		if (done_alias) +			break; +		save_env(); +		if (!handle_alias(argcp, argv))  			break;  		done_alias = 1;  	} @@ -547,11 +599,32 @@ static int run_argv(int *argcp, const char ***argv)  	return done_alias;  } +/* + * Many parts of Git have subprograms communicate via pipe, expect the + * upstream of a pipe to die with SIGPIPE when the downstream of a + * pipe does not need to read all that is written.  Some third-party + * programs that ignore or block SIGPIPE for their own reason forget + * to restore SIGPIPE handling to the default before spawning Git and + * break this carefully orchestrated machinery. + * + * Restore the way SIGPIPE is handled to default, which is what we + * expect. + */ +static void restore_sigpipe_to_default(void) +{ +	sigset_t unblock; + +	sigemptyset(&unblock); +	sigaddset(&unblock, SIGPIPE); +	sigprocmask(SIG_UNBLOCK, &unblock, NULL); +	signal(SIGPIPE, SIG_DFL); +}  int main(int argc, char **av)  {  	const char **argv = (const char **) av;  	const char *cmd; +	int done_help = 0;  	startup_info = &git_startup_info; @@ -566,8 +639,12 @@ int main(int argc, char **av)  	 */  	sanitize_stdfds(); +	restore_sigpipe_to_default(); +  	git_setup_gettext(); +	trace_command_performance(argv); +  	/*  	 * "git-xxxx" is the same as "git xxxx", but we obviously:  	 * @@ -578,8 +655,7 @@ int main(int argc, char **av)  	 * So we just directly call the builtin handler, and die if  	 * that one cannot handle it.  	 */ -	if (starts_with(cmd, "git-")) { -		cmd += 4; +	if (skip_prefix(cmd, "git-", &cmd)) {  		argv[0] = cmd;  		handle_builtin(argc, argv);  		die("cannot handle %s as a builtin", cmd); @@ -590,8 +666,8 @@ int main(int argc, char **av)  	argc--;  	handle_options(&argv, &argc, NULL);  	if (argc > 0) { -		if (starts_with(argv[0], "--")) -			argv[0] += 2; +		/* translate --help and --version into commands */ +		skip_prefix(argv[0], "--", &argv[0]);  	} else {  		/* The user didn't specify a command; give them help */  		commit_pager_choice(); @@ -611,9 +687,7 @@ int main(int argc, char **av)  	setup_path();  	while (1) { -		static int done_help = 0; -		static int was_alias = 0; -		was_alias = run_argv(&argc, &argv); +		int was_alias = run_argv(&argc, &argv);  		if (errno != ENOENT)  			break;  		if (was_alias) {  | 
