git potty: restore environments after alias expansion

Commit 4ad8332 (t0001: test git init when run via an alias -
2010-11-26) noted breakages when running init via alias. The problem
is for alias to be used, $GIT_DIR must be searched, but 'init' and
'clone' are not happy with that. So we start a new process like an
external command, with clean environment in this case. Env variables
that are set by command line (e.g. "git --git-dir=.. ") are kept.

This should also fix autocorrecting a command typo to "init" because
it's the same problem: aliases are read, then "init" is unhappy with
$GIT_DIR already set up because of that.

Reminded-by: David Turner <dturner@twopensource.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy 2014-06-08 16:37:10 +07:00 committed by Junio C Hamano
parent e156455ea4
commit c0562611c5
2 changed files with 51 additions and 6 deletions

53
git.c
View File

@ -20,6 +20,43 @@ const char git_more_info_string[] =
static struct startup_info git_startup_info;
static int use_pager = -1;
static char orig_cwd[PATH_MAX];
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;
if (!getcwd(orig_cwd, sizeof(orig_cwd)))
die_errno("cannot getcwd");
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);
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) {
@ -272,6 +309,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;
@ -352,7 +390,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 +416,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 },
{ "init-db", cmd_init_db },
{ "init", cmd_init_db, NO_SETUP },
{ "init-db", cmd_init_db, NO_SETUP },
{ "log", cmd_log, RUN_SETUP },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
@ -484,6 +522,10 @@ static void handle_builtin(int argc, const char **argv)
struct cmd_struct *p = commands+i;
if (strcmp(p->cmd, cmd))
continue;
if (saved_environment && (p->option & NO_SETUP)) {
restore_env();
break;
}
exit(run_builtin(p, argc, argv));
}
}
@ -539,7 +581,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;
}

View File

@ -56,7 +56,7 @@ test_expect_success 'plain through aliased command, outside any git repo' '
check_config plain-aliased/.git false unset
'
test_expect_failure 'plain nested through aliased command' '
test_expect_success 'plain nested through aliased command' '
(
git init plain-ancestor-aliased &&
cd plain-ancestor-aliased &&
@ -68,7 +68,7 @@ test_expect_failure 'plain nested through aliased command' '
check_config plain-ancestor-aliased/plain-nested/.git false unset
'
test_expect_failure 'plain nested in bare through aliased command' '
test_expect_success 'plain nested in bare through aliased command' '
(
git init --bare bare-ancestor-aliased.git &&
cd bare-ancestor-aliased.git &&