setup.c: re-fix d95138e (setup: set env $GIT_WORK_TREE when ..
Commitmaintd95138e[1] attempted to fix a .git file problem by setting GIT_WORK_TREE whenever GIT_DIR is set. It sounded harmless because we handle GIT_DIR and GIT_WORK_TREE side by side for most commands, with two exceptions: git-init and git-clone. "git clone" is not happy withd95138e. This command ignores GIT_DIR but respects GIT_WORK_TREE [2] [3] which means it used to run fine from a hook, where GIT_DIR was set but GIT_WORK_TREE was not (*). Withd95138e, GIT_WORK_TREE is set all the time and git-clone interprets that as "I give you order to put the worktree here", usually against the user's intention. The solution ind95138eis reverted earlier, and instead we reuse the solution fromc056261[4]. It fixed another setup-messed- up-by-alias by saving and restoring env and spawning a new process, but for git-clone and git-init only. Now we conclude that setup-messed-up-by-alias is always evil. So the env restoration is done for _all_ commands, including external ones, whenever aliases are involved. It fixes whatd95138etried to fix, without upsetting git-clone-inside-hooks. The test fromd95138eremains to verify it's not broken by this. A new test is added to make sure git-clone-inside-hooks remains happy. (*) GIT_WORK_TREE was not set _most of the time_. In some cases GIT_WORK_TREE is set and git-clone will behave differently. The use of GIT_WORK_TREE to direct git-clone to put work tree elsewhere looks like a mistake because it causes surprises this way. But that's a separate story. [1]d95138e(setup: set env $GIT_WORK_TREE when work tree is set, like $GIT_DIR - 2015-06-26) [2]2beebd2(clone: create intermediate directories of destination repo - 2008-06-25) [3]20ccef4(make git-clone GIT_WORK_TREE aware - 2007-07-06) [4]c056261(git potty: restore environments after alias expansion - 2014-06-08) Reported-by: Anthony Sottile <asottile@umich.edu> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
parent
0d5466d244
commit
86d26f240f
23
git.c
23
git.c
|
|
@ -226,7 +226,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
|
||||||
static int handle_alias(int *argcp, const char ***argv)
|
static int handle_alias(int *argcp, const char ***argv)
|
||||||
{
|
{
|
||||||
int envchanged = 0, ret = 0, saved_errno = errno;
|
int envchanged = 0, ret = 0, saved_errno = errno;
|
||||||
const char *subdir;
|
|
||||||
int count, option_count;
|
int count, option_count;
|
||||||
const char **new_argv;
|
const char **new_argv;
|
||||||
const char *alias_command;
|
const char *alias_command;
|
||||||
|
|
@ -234,7 +233,7 @@ static int handle_alias(int *argcp, const char ***argv)
|
||||||
int unused_nongit;
|
int unused_nongit;
|
||||||
|
|
||||||
save_env_before_alias();
|
save_env_before_alias();
|
||||||
subdir = setup_git_directory_gently(&unused_nongit);
|
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);
|
||||||
|
|
@ -292,8 +291,7 @@ static int handle_alias(int *argcp, const char ***argv)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subdir && chdir(subdir))
|
restore_env();
|
||||||
die_errno("Cannot change to '%s'", subdir);
|
|
||||||
|
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
|
|
||||||
|
|
@ -308,7 +306,6 @@ static int handle_alias(int *argcp, const char ***argv)
|
||||||
* RUN_SETUP for reading from the configuration file.
|
* RUN_SETUP for reading from the configuration file.
|
||||||
*/
|
*/
|
||||||
#define NEED_WORK_TREE (1<<3)
|
#define NEED_WORK_TREE (1<<3)
|
||||||
#define NO_SETUP (1<<4)
|
|
||||||
|
|
||||||
struct cmd_struct {
|
struct cmd_struct {
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
|
|
@ -389,7 +386,7 @@ static struct cmd_struct commands[] = {
|
||||||
{ "cherry", cmd_cherry, RUN_SETUP },
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||||
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "clean", cmd_clean, 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 },
|
{ "column", cmd_column, RUN_SETUP_GENTLY },
|
||||||
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||||
|
|
@ -415,8 +412,8 @@ static struct cmd_struct commands[] = {
|
||||||
{ "hash-object", cmd_hash_object },
|
{ "hash-object", cmd_hash_object },
|
||||||
{ "help", cmd_help },
|
{ "help", cmd_help },
|
||||||
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
|
{ "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
|
||||||
{ "init", cmd_init_db, NO_SETUP },
|
{ "init", cmd_init_db },
|
||||||
{ "init-db", cmd_init_db, NO_SETUP },
|
{ "init-db", cmd_init_db },
|
||||||
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP },
|
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP },
|
||||||
{ "log", cmd_log, RUN_SETUP },
|
{ "log", cmd_log, RUN_SETUP },
|
||||||
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
||||||
|
|
@ -528,9 +525,13 @@ static void handle_builtin(int argc, const char **argv)
|
||||||
|
|
||||||
builtin = get_builtin(cmd);
|
builtin = get_builtin(cmd);
|
||||||
if (builtin) {
|
if (builtin) {
|
||||||
if (saved_env_before_alias && (builtin->option & NO_SETUP))
|
/*
|
||||||
restore_env();
|
* XXX: if we can figure out cases where it is _safe_
|
||||||
else
|
* to do, we can avoid spawning a new process when
|
||||||
|
* saved_env_before_alias is true
|
||||||
|
* (i.e. setup_git_dir* has been run once)
|
||||||
|
*/
|
||||||
|
if (!saved_env_before_alias)
|
||||||
exit(run_builtin(builtin, argc, argv));
|
exit(run_builtin(builtin, argc, argv));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ test_expect_success 'check rev-list' '
|
||||||
test "$SHA" = "$(git rev-list HEAD)"
|
test "$SHA" = "$(git rev-list HEAD)"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_failure 'setup_git_dir twice in subdir' '
|
test_expect_success 'setup_git_dir twice in subdir' '
|
||||||
git init sgd &&
|
git init sgd &&
|
||||||
(
|
(
|
||||||
cd sgd &&
|
cd sgd &&
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,29 @@ test_expect_success 'clone respects GIT_WORK_TREE' '
|
||||||
|
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone from hooks' '
|
||||||
|
|
||||||
|
test_create_repo r0 &&
|
||||||
|
cd r0 &&
|
||||||
|
test_commit initial &&
|
||||||
|
cd .. &&
|
||||||
|
git init r1 &&
|
||||||
|
cd r1 &&
|
||||||
|
cat >.git/hooks/pre-commit <<-\EOF &&
|
||||||
|
#!/bin/sh
|
||||||
|
git clone ../r0 ../r2
|
||||||
|
exit 1
|
||||||
|
EOF
|
||||||
|
chmod u+x .git/hooks/pre-commit &&
|
||||||
|
: >file &&
|
||||||
|
git add file &&
|
||||||
|
test_must_fail git commit -m invoke-hook &&
|
||||||
|
cd .. &&
|
||||||
|
test_cmp r0/.git/HEAD r2/.git/HEAD &&
|
||||||
|
test_cmp r0/initial.t r2/initial.t
|
||||||
|
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'clone creates intermediate directories' '
|
test_expect_success 'clone creates intermediate directories' '
|
||||||
|
|
||||||
git clone src long/path/to/dst &&
|
git clone src long/path/to/dst &&
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue