aboutsummaryrefslogtreecommitdiffstats
path: root/git.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2016-04-14 12:47:44 -0700
committerJunio C Hamano <gitster@pobox.com>2016-04-14 12:47:45 -0700
commitee30f17805f51d372ff9c5036f1d142c167e5e34 (patch)
treef47b60cb10efd46b82c067b3e17a25004808a1c5 /git.c
parentMerge branch 'sb/submodule-helper-clone-regression-fix' into sb/submodule-init (diff)
parentt7407: make expectation as clear as possible (diff)
downloadgit-ee30f17805f51d372ff9c5036f1d142c167e5e34.tar.gz
git-ee30f17805f51d372ff9c5036f1d142c167e5e34.zip
Merge branch 'sb/submodule-path-misc-bugs' into sb/submodule-init
"git submodule" reports the paths of submodules the command recurses into, but this was incorrect when the command was not run from the root level of the superproject. Any further comments? Otherwise will merge to 'next'. * sb/submodule-path-misc-bugs: (600 commits) t7407: make expectation as clear as possible submodule update: test recursive path reporting from subdirectory submodule update: align reporting path for custom command execution submodule status: correct path handling in recursive submodules submodule update --init: correct path handling in recursive submodules submodule foreach: correct path display in recursive submodules Git 2.8 Documentation: fix git-p4 AsciiDoc formatting mingw: skip some tests in t9115 due to file name issues t1300: fix the new --show-origin tests on Windows t1300-repo-config: make it resilient to being run via 'sh -x' config --show-origin: report paths with forward slashes submodule: fix regression for deinit without submodules l10n: pt_PT: Update and add new translations l10n: ca.po: update translation Git 2.8-rc4 Documentation: fix broken linkgit to git-config Documentation: use ASCII quotation marks in git-p4 Revert "config.mak.uname: use clang for Mac OS X 10.6" git-compat-util: st_add4: work around gcc 4.2.x compiler crash ...
Diffstat (limited to 'git.c')
-rw-r--r--git.c103
1 files changed, 57 insertions, 46 deletions
diff --git a/git.c b/git.c
index 6ed824cacf..6cc0c077f9 100644
--- a/git.c
+++ b/git.c
@@ -25,14 +25,14 @@ static const char *env_names[] = {
GIT_PREFIX_ENVIRONMENT
};
static char *orig_env[4];
-static int saved_environment;
+static int save_restore_env_balance;
-static void save_env(void)
+static void save_env_before_alias(void)
{
int i;
- if (saved_environment)
- return;
- saved_environment = 1;
+
+ 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]);
@@ -41,17 +41,25 @@ static void save_env(void)
}
}
-static void restore_env(void)
+static void restore_env(int external_alias)
{
int i;
- if (orig_cwd && chdir(orig_cwd))
+
+ 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 (orig_env[i])
+ if (external_alias &&
+ !strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
+ continue;
+ if (orig_env[i]) {
setenv(env_names[i], orig_env[i], 1);
- else
+ free(orig_env[i]);
+ } else {
unsetenv(env_names[i]);
+ }
}
}
@@ -226,32 +234,29 @@ 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;
char *alias_string;
int unused_nongit;
- subdir = setup_git_directory_gently(&unused_nongit);
+ save_env_before_alias();
+ setup_git_directory_gently(&unused_nongit);
alias_command = (*argv)[0];
alias_string = alias_lookup(alias_command);
if (alias_string) {
if (alias_string[0] == '!') {
- const char **alias_argv;
- int argc = *argcp, i;
+ struct child_process child = CHILD_PROCESS_INIT;
commit_pager_choice();
+ restore_env(1);
- /* build alias_argv */
- alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
- alias_argv[0] = alias_string + 1;
- for (i = 1; i < argc; ++i)
- alias_argv[i] = (*argv)[i];
- alias_argv[argc] = NULL;
+ child.use_shell = 1;
+ argv_array_push(&child.args, alias_string + 1);
+ argv_array_pushv(&child.args, (*argv) + 1);
- ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
+ ret = run_command(&child);
if (ret >= 0) /* normal exit */
exit(ret);
@@ -291,8 +296,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(0);
errno = saved_errno;
@@ -307,7 +311,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 +392,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 +418,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_GENTLY },
{ "log", cmd_log, RUN_SETUP },
{ "ls-files", cmd_ls_files, RUN_SETUP },
@@ -506,21 +509,25 @@ int is_builtin(const char *s)
return !!get_builtin(s);
}
+#ifdef STRIP_EXTENSION
+static void strip_extension(const char **argv)
+{
+ size_t len;
+
+ if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
+ argv[0] = xmemdupz(argv[0], len);
+}
+#else
+#define strip_extension(cmd)
+#endif
+
static void handle_builtin(int argc, const char **argv)
{
- const char *cmd = argv[0];
- int i;
- static const char ext[] = STRIP_EXTENSION;
+ const char *cmd;
struct cmd_struct *builtin;
- if (sizeof(ext) > 1) {
- i = strlen(argv[0]) - strlen(ext);
- if (i > 0 && !strcmp(argv[0] + i, ext)) {
- char *argv0 = xstrdup(argv[0]);
- argv[0] = cmd = argv0;
- argv0[i] = '\0';
- }
- }
+ strip_extension(argv);
+ cmd = argv[0];
/* Turn "git cmd --help" into "git help cmd" */
if (argc > 1 && !strcmp(argv[1], "--help")) {
@@ -529,12 +536,8 @@ static void handle_builtin(int argc, const char **argv)
}
builtin = get_builtin(cmd);
- if (builtin) {
- if (saved_environment && (builtin->option & NO_SETUP))
- restore_env();
- else
- exit(run_builtin(builtin, argc, argv));
- }
+ if (builtin)
+ exit(run_builtin(builtin, argc, argv));
}
static void execv_dashed_external(const char **argv)
@@ -578,8 +581,17 @@ static int run_argv(int *argcp, const char ***argv)
int done_alias = 0;
while (1) {
- /* See if it's a builtin */
- handle_builtin(*argcp, *argv);
+ /*
+ * If we tried alias and futzed with our environment,
+ * it no longer is safe to invoke builtins directly in
+ * general. We have to spawn them as dashed externals.
+ *
+ * NEEDSWORK: if we can figure out cases
+ * where it is safe to do, we can avoid spawning a new
+ * process.
+ */
+ if (!done_alias)
+ handle_builtin(*argcp, *argv);
/* .. then try the external ones */
execv_dashed_external(*argv);
@@ -590,7 +602,6 @@ static int run_argv(int *argcp, const char ***argv)
*/
if (done_alias)
break;
- save_env();
if (!handle_alias(argcp, argv))
break;
done_alias = 1;