Skip to content

Commit 5135d1c

Browse files
committed
Merge branch 'nd/clear-gitenv-upon-use-of-alias'
d95138e (setup: set env $GIT_WORK_TREE when work tree is set, like $GIT_DIR, 2015-06-26) attempted to work around a glitch in alias handling by overwriting GIT_WORK_TREE environment variable to affect subprocesses when set_git_work_tree() gets called, which resulted in a rather unpleasant regression to "clone" and "init". Try to address the same issue by always restoring the environment and respawning the real underlying command when handling alias. * nd/clear-gitenv-upon-use-of-alias: run-command: don't warn on SIGPIPE deaths git.c: make sure we do not leak GIT_* to alias scripts setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when .. git.c: make it clear save_env() is for alias handling only
2 parents cc14ea8 + ac78663 commit 5135d1c

File tree

5 files changed

+65
-20
lines changed

5 files changed

+65
-20
lines changed

git.c

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ static const char *env_names[] = {
2525
GIT_PREFIX_ENVIRONMENT
2626
};
2727
static char *orig_env[4];
28-
static int saved_environment;
28+
static int saved_env_before_alias;
2929

30-
static void save_env(void)
30+
static void save_env_before_alias(void)
3131
{
3232
int i;
33-
if (saved_environment)
33+
if (saved_env_before_alias)
3434
return;
35-
saved_environment = 1;
35+
saved_env_before_alias = 1;
3636
orig_cwd = xgetcwd();
3737
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
3838
orig_env[i] = getenv(env_names[i]);
@@ -41,13 +41,16 @@ static void save_env(void)
4141
}
4242
}
4343

44-
static void restore_env(void)
44+
static void restore_env(int external_alias)
4545
{
4646
int i;
47-
if (orig_cwd && chdir(orig_cwd))
47+
if (!external_alias && orig_cwd && chdir(orig_cwd))
4848
die_errno("could not move to %s", orig_cwd);
4949
free(orig_cwd);
5050
for (i = 0; i < ARRAY_SIZE(env_names); i++) {
51+
if (external_alias &&
52+
!strcmp(env_names[i], GIT_PREFIX_ENVIRONMENT))
53+
continue;
5154
if (orig_env[i])
5255
setenv(env_names[i], orig_env[i], 1);
5356
else
@@ -226,14 +229,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
226229
static int handle_alias(int *argcp, const char ***argv)
227230
{
228231
int envchanged = 0, ret = 0, saved_errno = errno;
229-
const char *subdir;
230232
int count, option_count;
231233
const char **new_argv;
232234
const char *alias_command;
233235
char *alias_string;
234236
int unused_nongit;
235237

236-
subdir = setup_git_directory_gently(&unused_nongit);
238+
save_env_before_alias();
239+
setup_git_directory_gently(&unused_nongit);
237240

238241
alias_command = (*argv)[0];
239242
alias_string = alias_lookup(alias_command);
@@ -243,6 +246,7 @@ static int handle_alias(int *argcp, const char ***argv)
243246
int argc = *argcp, i;
244247

245248
commit_pager_choice();
249+
restore_env(1);
246250

247251
/* build alias_argv */
248252
alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
@@ -291,8 +295,7 @@ static int handle_alias(int *argcp, const char ***argv)
291295
ret = 1;
292296
}
293297

294-
if (subdir && chdir(subdir))
295-
die_errno("Cannot change to '%s'", subdir);
298+
restore_env(0);
296299

297300
errno = saved_errno;
298301

@@ -307,7 +310,6 @@ static int handle_alias(int *argcp, const char ***argv)
307310
* RUN_SETUP for reading from the configuration file.
308311
*/
309312
#define NEED_WORK_TREE (1<<3)
310-
#define NO_SETUP (1<<4)
311313

312314
struct cmd_struct {
313315
const char *cmd;
@@ -389,7 +391,7 @@ static struct cmd_struct commands[] = {
389391
{ "cherry", cmd_cherry, RUN_SETUP },
390392
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
391393
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
392-
{ "clone", cmd_clone, NO_SETUP },
394+
{ "clone", cmd_clone },
393395
{ "column", cmd_column, RUN_SETUP_GENTLY },
394396
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
395397
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
@@ -415,8 +417,8 @@ static struct cmd_struct commands[] = {
415417
{ "hash-object", cmd_hash_object },
416418
{ "help", cmd_help },
417419
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
418-
{ "init", cmd_init_db, NO_SETUP },
419-
{ "init-db", cmd_init_db, NO_SETUP },
420+
{ "init", cmd_init_db },
421+
{ "init-db", cmd_init_db },
420422
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
421423
{ "log", cmd_log, RUN_SETUP },
422424
{ "ls-files", cmd_ls_files, RUN_SETUP },
@@ -530,9 +532,13 @@ static void handle_builtin(int argc, const char **argv)
530532

531533
builtin = get_builtin(cmd);
532534
if (builtin) {
533-
if (saved_environment && (builtin->option & NO_SETUP))
534-
restore_env();
535-
else
535+
/*
536+
* XXX: if we can figure out cases where it is _safe_
537+
* to do, we can avoid spawning a new process when
538+
* saved_env_before_alias is true
539+
* (i.e. setup_git_dir* has been run once)
540+
*/
541+
if (!saved_env_before_alias)
536542
exit(run_builtin(builtin, argc, argv));
537543
}
538544
}
@@ -590,7 +596,6 @@ static int run_argv(int *argcp, const char ***argv)
590596
*/
591597
if (done_alias)
592598
break;
593-
save_env();
594599
if (!handle_alias(argcp, argv))
595600
break;
596601
done_alias = 1;

run-command.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal)
247247
error("waitpid is confused (%s)", argv0);
248248
} else if (WIFSIGNALED(status)) {
249249
code = WTERMSIG(status);
250-
if (code != SIGINT && code != SIGQUIT)
250+
if (code != SIGINT && code != SIGQUIT && code != SIGPIPE)
251251
error("%s died of signal %d", argv0, code);
252252
/*
253253
* This return value is chosen so that code & 0xff

t/t0001-init.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,23 @@ test_expect_success 'plain nested in bare through aliased command' '
8787
check_config bare-ancestor-aliased.git/plain-nested/.git false unset
8888
'
8989

90+
test_expect_success 'No extra GIT_* on alias scripts' '
91+
(
92+
env | sed -ne "/^GIT_/s/=.*//p" &&
93+
echo GIT_PREFIX && # setup.c
94+
echo GIT_TEXTDOMAINDIR # wrapper-for-bin.sh
95+
) | sort | uniq >expected &&
96+
cat <<-\EOF >script &&
97+
#!/bin/sh
98+
env | sed -ne "/^GIT_/s/=.*//p" | sort >actual
99+
exit 0
100+
EOF
101+
chmod 755 script &&
102+
git config alias.script \!./script &&
103+
( mkdir sub && cd sub && git script ) &&
104+
test_cmp expected actual
105+
'
106+
90107
test_expect_success 'plain with GIT_WORK_TREE' '
91108
mkdir plain-wt &&
92109
test_must_fail env GIT_WORK_TREE="$(pwd)/plain-wt" git init plain-wt

t/t0002-gitfile.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ test_expect_success 'check rev-list' '
9999
test "$SHA" = "$(git rev-list HEAD)"
100100
'
101101

102-
test_expect_failure 'setup_git_dir twice in subdir' '
102+
test_expect_success 'setup_git_dir twice in subdir' '
103103
git init sgd &&
104104
(
105105
cd sgd &&

t/t5601-clone.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
6565
6666
'
6767

68+
test_expect_success 'clone from hooks' '
69+
70+
test_create_repo r0 &&
71+
cd r0 &&
72+
test_commit initial &&
73+
cd .. &&
74+
git init r1 &&
75+
cd r1 &&
76+
cat >.git/hooks/pre-commit <<-\EOF &&
77+
#!/bin/sh
78+
git clone ../r0 ../r2
79+
exit 1
80+
EOF
81+
chmod u+x .git/hooks/pre-commit &&
82+
: >file &&
83+
git add file &&
84+
test_must_fail git commit -m invoke-hook &&
85+
cd .. &&
86+
test_cmp r0/.git/HEAD r2/.git/HEAD &&
87+
test_cmp r0/initial.t r2/initial.t
88+
89+
'
90+
6891
test_expect_success 'clone creates intermediate directories' '
6992
7093
git clone src long/path/to/dst &&

0 commit comments

Comments
 (0)