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)
|
||||
{
|
||||
int envchanged = 0, ret = 0, saved_errno = errno;
|
||||
const char *subdir;
|
||||
int count, option_count;
|
||||
const char **new_argv;
|
||||
const char *alias_command;
|
||||
|
|
@ -234,7 +233,7 @@ static int handle_alias(int *argcp, const char ***argv)
|
|||
int unused_nongit;
|
||||
|
||||
save_env_before_alias();
|
||||
subdir = setup_git_directory_gently(&unused_nongit);
|
||||
setup_git_directory_gently(&unused_nongit);
|
||||
|
||||
alias_command = (*argv)[0];
|
||||
alias_string = alias_lookup(alias_command);
|
||||
|
|
@ -292,8 +291,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();
|
||||
|
||||
errno = saved_errno;
|
||||
|
||||
|
|
@ -308,7 +306,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 +386,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 +412,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 },
|
||||
{ "log", cmd_log, 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);
|
||||
if (builtin) {
|
||||
if (saved_env_before_alias && (builtin->option & NO_SETUP))
|
||||
restore_env();
|
||||
else
|
||||
/*
|
||||
* XXX: if we can figure out cases where it is _safe_
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ test_expect_success 'check rev-list' '
|
|||
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 &&
|
||||
(
|
||||
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' '
|
||||
|
||||
git clone src long/path/to/dst &&
|
||||
|
|
|
|||
Loading…
Reference in New Issue