Merge branch 'nd/setup'

* nd/setup: (47 commits)
  setup_work_tree: adjust relative $GIT_WORK_TREE after moving cwd
  git.txt: correct where --work-tree path is relative to
  Revert "Documentation: always respect core.worktree if set"
  t0001: test git init when run via an alias
  Remove all logic from get_git_work_tree()
  setup: rework setup_explicit_git_dir()
  setup: clean up setup_discovered_git_dir()
  t1020-subdirectory: test alias expansion in a subdirectory
  setup: clean up setup_bare_git_dir()
  setup: limit get_git_work_tree()'s to explicit setup case only
  Use git_config_early() instead of git_config() during repo setup
  Add git_config_early()
  git-rev-parse.txt: clarify --git-dir
  t1510: setup case #31
  t1510: setup case #30
  t1510: setup case #29
  t1510: setup case #28
  t1510: setup case #27
  t1510: setup case #26
  t1510: setup case #25
  ...
This commit is contained in:
Junio C Hamano 2010-12-28 11:26:55 -08:00
commit f3bb8b4b84
17 changed files with 4869 additions and 135 deletions

1
.gitignore vendored
View File

@ -177,6 +177,7 @@
/test-sha1 /test-sha1
/test-sigchain /test-sigchain
/test-string-pool /test-string-pool
/test-subprocess
/test-svn-fe /test-svn-fe
/test-treap /test-treap
/common-cmds.h /common-cmds.h

View File

@ -317,24 +317,17 @@ false), while all other repositories are assumed to be bare (bare
= true). = true).
core.worktree:: core.worktree::
Set the path to the root of the work tree. Set the path to the working tree. The value will not be
used in combination with repositories found automatically in
a .git directory (i.e. $GIT_DIR is not set).
This can be overridden by the GIT_WORK_TREE environment This can be overridden by the GIT_WORK_TREE environment
variable and the '--work-tree' command line option. It can be variable and the '--work-tree' command line option. It can be
an absolute path or a relative path to the .git directory, an absolute path or relative path to the directory specified by
either specified by --git-dir or GIT_DIR, or automatically --git-dir or GIT_DIR.
discovered. Note: If --git-dir or GIT_DIR are specified but none of
If --git-dir or GIT_DIR are specified but none of
--work-tree, GIT_WORK_TREE and core.worktree is specified, --work-tree, GIT_WORK_TREE and core.worktree is specified,
the current working directory is regarded as the root of the the current working directory is regarded as the top directory
work tree. of your working tree.
+
Note that this variable is honored even when set in a configuration
file in a ".git" subdirectory of a directory, and its value differs
from the latter directory (e.g. "/path/to/.git/config" has
core.worktree set to "/different/path"), which is most likely a
misconfiguration. Running git commands in "/path/to" directory will
still use "/different/path" as the root of the work tree and can cause
great confusion to the users.
core.logAllRefUpdates:: core.logAllRefUpdates::
Enable the reflog. Updates to a ref <ref> is logged to the file Enable the reflog. Updates to a ref <ref> is logged to the file

View File

@ -136,7 +136,12 @@ appending `/{asterisk}`.
directory (typically a sequence of "../", or an empty string). directory (typically a sequence of "../", or an empty string).
--git-dir:: --git-dir::
Show `$GIT_DIR` if defined else show the path to the .git directory. Show `$GIT_DIR` if defined. Otherwise show the path to
the .git directory, relative to the current directory.
+
If `$GIT_DIR` is not defined and the current directory
is not detected to lie in a git repository or work tree
print a message to stderr and exit with nonzero status.
--is-inside-git-dir:: --is-inside-git-dir::
When the current working directory is below the repository When the current working directory is below the repository

View File

@ -296,7 +296,7 @@ help ...`.
This can also be controlled by setting the GIT_WORK_TREE This can also be controlled by setting the GIT_WORK_TREE
environment variable and the core.worktree configuration environment variable and the core.worktree configuration
variable. It can be an absolute path or relative path to variable. It can be an absolute path or relative path to
the directory specified by --git-dir or GIT_DIR. current working directory.
Note: If --git-dir or GIT_DIR are specified but none of Note: If --git-dir or GIT_DIR are specified but none of
--work-tree, GIT_WORK_TREE and core.worktree is specified, --work-tree, GIT_WORK_TREE and core.worktree is specified,
the current working directory is regarded as the top directory the current working directory is regarded as the top directory

View File

@ -431,6 +431,7 @@ TEST_PROGRAMS_NEED_X += test-run-command
TEST_PROGRAMS_NEED_X += test-sha1 TEST_PROGRAMS_NEED_X += test-sha1
TEST_PROGRAMS_NEED_X += test-sigchain TEST_PROGRAMS_NEED_X += test-sigchain
TEST_PROGRAMS_NEED_X += test-string-pool TEST_PROGRAMS_NEED_X += test-string-pool
TEST_PROGRAMS_NEED_X += test-subprocess
TEST_PROGRAMS_NEED_X += test-svn-fe TEST_PROGRAMS_NEED_X += test-svn-fe
TEST_PROGRAMS_NEED_X += test-treap TEST_PROGRAMS_NEED_X += test-treap
TEST_PROGRAMS_NEED_X += test-index-version TEST_PROGRAMS_NEED_X += test-index-version

View File

@ -414,6 +414,7 @@ static const char *const init_db_usage[] = {
int cmd_init_db(int argc, const char **argv, const char *prefix) int cmd_init_db(int argc, const char **argv, const char *prefix)
{ {
const char *git_dir; const char *git_dir;
const char *work_tree;
const char *template_dir = NULL; const char *template_dir = NULL;
unsigned int flags = 0; unsigned int flags = 0;
const struct option init_db_options[] = { const struct option init_db_options[] = {
@ -480,8 +481,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
* without --bare. Catch the error early. * without --bare. Catch the error early.
*/ */
git_dir = getenv(GIT_DIR_ENVIRONMENT); git_dir = getenv(GIT_DIR_ENVIRONMENT);
if ((!git_dir || is_bare_repository_cfg == 1) work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
&& getenv(GIT_WORK_TREE_ENVIRONMENT)) if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
die("%s (or --work-tree=<directory>) not allowed without " die("%s (or --work-tree=<directory>) not allowed without "
"specifying %s (or --git-dir=<directory>)", "specifying %s (or --git-dir=<directory>)",
GIT_WORK_TREE_ENVIRONMENT, GIT_WORK_TREE_ENVIRONMENT,
@ -510,10 +511,18 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (!getcwd(git_work_tree_cfg, PATH_MAX)) if (!getcwd(git_work_tree_cfg, PATH_MAX))
die_errno ("Cannot access current working directory"); die_errno ("Cannot access current working directory");
} }
if (work_tree)
set_git_work_tree(make_absolute_path(work_tree));
else
set_git_work_tree(git_work_tree_cfg);
if (access(get_git_work_tree(), X_OK)) if (access(get_git_work_tree(), X_OK))
die_errno ("Cannot access work tree '%s'", die_errno ("Cannot access work tree '%s'",
get_git_work_tree()); get_git_work_tree());
} }
else {
if (work_tree)
set_git_work_tree(make_absolute_path(work_tree));
}
set_git_dir(make_absolute_path(git_dir)); set_git_dir(make_absolute_path(git_dir));

View File

@ -987,6 +987,7 @@ extern int git_config_parse_parameter(const char *text);
extern int git_config_parse_environment(void); extern int git_config_parse_environment(void);
extern int git_config_from_parameters(config_fn_t fn, void *data); extern int git_config_from_parameters(config_fn_t fn, void *data);
extern int git_config(config_fn_t fn, void *); extern int git_config(config_fn_t fn, void *);
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
extern int git_parse_ulong(const char *, unsigned long *); extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *); extern int git_config_int(const char *, const char *);
extern unsigned long git_config_ulong(const char *, const char *); extern unsigned long git_config_ulong(const char *, const char *);
@ -1066,6 +1067,7 @@ __attribute__((format (printf, 1, 2)))
extern void trace_printf(const char *format, ...); extern void trace_printf(const char *format, ...);
__attribute__((format (printf, 2, 3))) __attribute__((format (printf, 2, 3)))
extern void trace_argv_printf(const char **argv, const char *format, ...); extern void trace_argv_printf(const char **argv, const char *format, ...);
extern void trace_repo_setup(const char *prefix);
/* convert.c */ /* convert.c */
/* returns 1 if *dst was used */ /* returns 1 if *dst was used */

View File

@ -852,10 +852,9 @@ int git_config_from_parameters(config_fn_t fn, void *data)
return 0; return 0;
} }
int git_config(config_fn_t fn, void *data) int git_config_early(config_fn_t fn, void *data, const char *repo_config)
{ {
int ret = 0, found = 0; int ret = 0, found = 0;
char *repo_config = NULL;
const char *home = NULL; const char *home = NULL;
/* Setting $GIT_CONFIG makes git read _only_ the given config file. */ /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
@ -877,12 +876,10 @@ int git_config(config_fn_t fn, void *data)
free(user_config); free(user_config);
} }
repo_config = git_pathdup("config"); if (repo_config && !access(repo_config, R_OK)) {
if (!access(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data); ret += git_config_from_file(fn, repo_config, data);
found += 1; found += 1;
} }
free(repo_config);
ret += git_config_from_parameters(fn, data); ret += git_config_from_parameters(fn, data);
if (config_parameters) if (config_parameters)
@ -891,6 +888,18 @@ int git_config(config_fn_t fn, void *data)
return ret == 0 ? found : ret; return ret == 0 ? found : ret;
} }
int git_config(config_fn_t fn, void *data)
{
char *repo_config = NULL;
int ret;
repo_config = git_pathdup("config");
ret = git_config_early(fn, data, repo_config);
if (repo_config)
free(repo_config);
return ret;
}
/* /*
* Find all the stuff for git_config_set() below. * Find all the stuff for git_config_set() below.
*/ */

View File

@ -139,30 +139,20 @@ static int git_work_tree_initialized;
*/ */
void set_git_work_tree(const char *new_work_tree) void set_git_work_tree(const char *new_work_tree)
{ {
if (is_bare_repository_cfg >= 0) if (git_work_tree_initialized) {
die("cannot set work tree after initialization"); new_work_tree = make_absolute_path(new_work_tree);
if (strcmp(new_work_tree, work_tree))
die("internal error: work tree has already been set\n"
"Current worktree: %s\nNew worktree: %s",
work_tree, new_work_tree);
return;
}
git_work_tree_initialized = 1; git_work_tree_initialized = 1;
free(work_tree);
work_tree = xstrdup(make_absolute_path(new_work_tree)); work_tree = xstrdup(make_absolute_path(new_work_tree));
is_bare_repository_cfg = 0;
} }
const char *get_git_work_tree(void) const char *get_git_work_tree(void)
{ {
if (!git_work_tree_initialized) {
work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
/* core.bare = true overrides implicit and config work tree */
if (!work_tree && is_bare_repository_cfg < 1) {
work_tree = git_work_tree_cfg;
/* make_absolute_path also normalizes the path */
if (work_tree && !is_absolute_path(work_tree))
work_tree = xstrdup(make_absolute_path(git_path("%s", work_tree)));
} else if (work_tree)
work_tree = xstrdup(make_absolute_path(work_tree));
git_work_tree_initialized = 1;
if (work_tree)
is_bare_repository_cfg = 0;
}
return work_tree; return work_tree;
} }

4
git.c
View File

@ -275,6 +275,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = check_pager_config(p->cmd); use_pager = check_pager_config(p->cmd);
if (use_pager == -1 && p->option & USE_PAGER) if (use_pager == -1 && p->option & USE_PAGER)
use_pager = 1; use_pager = 1;
if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
trace_repo_setup(prefix);
} }
commit_pager_choice(); commit_pager_choice();

236
setup.c
View File

@ -208,24 +208,6 @@ int is_inside_work_tree(void)
return inside_work_tree; return inside_work_tree;
} }
/*
* set_work_tree() is only ever called if you set GIT_DIR explicitly.
* The old behaviour (which we retain here) is to set the work tree root
* to the cwd, unless overridden by the config, the command line, or
* GIT_WORK_TREE.
*/
static const char *set_work_tree(const char *dir)
{
char buffer[PATH_MAX + 1];
if (!getcwd(buffer, sizeof(buffer)))
die ("Could not get the current working directory");
git_work_tree_cfg = xstrdup(buffer);
inside_work_tree = 1;
return NULL;
}
void setup_work_tree(void) void setup_work_tree(void)
{ {
const char *work_tree, *git_dir; const char *work_tree, *git_dir;
@ -239,13 +221,33 @@ void setup_work_tree(void)
git_dir = make_absolute_path(git_dir); git_dir = make_absolute_path(git_dir);
if (!work_tree || chdir(work_tree)) if (!work_tree || chdir(work_tree))
die("This operation must be run in a work tree"); die("This operation must be run in a work tree");
/*
* Make sure subsequent git processes find correct worktree
* if $GIT_WORK_TREE is set relative
*/
if (getenv(GIT_WORK_TREE_ENVIRONMENT))
setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
set_git_dir(make_relative_path(git_dir, work_tree)); set_git_dir(make_relative_path(git_dir, work_tree));
initialized = 1; initialized = 1;
} }
static int check_repository_format_gently(int *nongit_ok) static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
{ {
git_config(check_repository_format_version, NULL); char repo_config[PATH_MAX+1];
/*
* git_config() can't be used here because it calls git_pathdup()
* to get $GIT_CONFIG/config. That call will make setup_git_env()
* set git_dir to ".git".
*
* We are in gitdir setup, no git dir has been found useable yet.
* Use a gentler version of git_config() to check if this repo
* is a good one.
*/
snprintf(repo_config, PATH_MAX, "%s/config", gitdir);
git_config_early(check_repository_format_version, NULL, repo_config);
if (GIT_REPO_VERSION < repository_format_version) { if (GIT_REPO_VERSION < repository_format_version) {
if (!nongit_ok) if (!nongit_ok)
die ("Expected git repo version <= %d, found %d", die ("Expected git repo version <= %d, found %d",
@ -314,64 +316,115 @@ const char *read_gitfile_gently(const char *path)
} }
static const char *setup_explicit_git_dir(const char *gitdirenv, static const char *setup_explicit_git_dir(const char *gitdirenv,
const char *work_tree_env, int *nongit_ok) char *cwd, int len,
int *nongit_ok)
{ {
static char buffer[1024 + 1]; const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
const char *retval; const char *worktree;
char *gitfile;
if (PATH_MAX - 40 < strlen(gitdirenv)) if (PATH_MAX - 40 < strlen(gitdirenv))
die("'$%s' too big", GIT_DIR_ENVIRONMENT); die("'$%s' too big", GIT_DIR_ENVIRONMENT);
gitfile = (char*)read_gitfile_gently(gitdirenv);
if (gitfile) {
gitfile = xstrdup(gitfile);
gitdirenv = gitfile;
}
if (!is_git_directory(gitdirenv)) { if (!is_git_directory(gitdirenv)) {
if (nongit_ok) { if (nongit_ok) {
*nongit_ok = 1; *nongit_ok = 1;
free(gitfile);
return NULL; return NULL;
} }
die("Not a git repository: '%s'", gitdirenv); die("Not a git repository: '%s'", gitdirenv);
} }
if (!work_tree_env) {
retval = set_work_tree(gitdirenv); if (check_repository_format_gently(gitdirenv, nongit_ok)) {
/* config may override worktree */ free(gitfile);
if (check_repository_format_gently(nongit_ok))
return NULL; return NULL;
return retval;
} }
if (check_repository_format_gently(nongit_ok))
/* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
if (work_tree_env)
set_git_work_tree(work_tree_env);
else if (is_bare_repository_cfg > 0) {
if (git_work_tree_cfg) /* #22.2, #30 */
die("core.bare and core.worktree do not make sense");
/* #18, #26 */
set_git_dir(gitdirenv);
free(gitfile);
return NULL; return NULL;
retval = get_relative_cwd(buffer, sizeof(buffer) - 1, }
get_git_work_tree()); else if (git_work_tree_cfg) { /* #6, #14 */
if (!retval || !*retval) if (is_absolute_path(git_work_tree_cfg))
set_git_work_tree(git_work_tree_cfg);
else {
char core_worktree[PATH_MAX];
if (chdir(gitdirenv))
die_errno("Could not chdir to '%s'", gitdirenv);
if (chdir(git_work_tree_cfg))
die_errno("Could not chdir to '%s'", git_work_tree_cfg);
if (!getcwd(core_worktree, PATH_MAX))
die_errno("Could not get directory '%s'", git_work_tree_cfg);
if (chdir(cwd))
die_errno("Could not come back to cwd");
set_git_work_tree(core_worktree);
}
}
else /* #2, #10 */
set_git_work_tree(".");
/* set_git_work_tree() must have been called by now */
worktree = get_git_work_tree();
/* both get_git_work_tree() and cwd are already normalized */
if (!strcmp(cwd, worktree)) { /* cwd == worktree */
set_git_dir(gitdirenv);
free(gitfile);
return NULL; return NULL;
}
if (!prefixcmp(cwd, worktree) &&
cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
set_git_dir(make_absolute_path(gitdirenv)); set_git_dir(make_absolute_path(gitdirenv));
if (chdir(work_tree_env) < 0) if (chdir(worktree))
die_errno ("Could not chdir to '%s'", work_tree_env); die_errno("Could not chdir to '%s'", worktree);
strcat(buffer, "/"); cwd[len++] = '/';
return retval; cwd[len] = '\0';
} free(gitfile);
return cwd + strlen(worktree) + 1;
static int cwd_contains_git_dir(const char **gitfile_dirp)
{
const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
*gitfile_dirp = gitfile_dir;
if (gitfile_dir) {
if (set_git_dir(gitfile_dir))
die("Repository setup failed");
return 1;
} }
return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT);
/* cwd outside worktree */
set_git_dir(gitdirenv);
free(gitfile);
return NULL;
} }
static const char *setup_discovered_git_dir(const char *work_tree_env, static const char *setup_discovered_git_dir(const char *gitdir,
int offset, int len, char *cwd, int *nongit_ok) char *cwd, int offset, int len,
int *nongit_ok)
{ {
int root_len; if (check_repository_format_gently(gitdir, nongit_ok))
inside_git_dir = 0;
if (!work_tree_env)
inside_work_tree = 1;
root_len = offset_1st_component(cwd);
git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
if (check_repository_format_gently(nongit_ok))
return NULL; return NULL;
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
if (is_bare_repository_cfg > 0) {
set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir));
if (chdir(cwd))
die_errno("Could not come back to cwd");
return NULL;
}
/* #0, #1, #5, #8, #9, #12, #13 */
set_git_work_tree(".");
if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
set_git_dir(gitdir);
inside_git_dir = 0;
inside_work_tree = 1;
if (offset == len) if (offset == len)
return NULL; return NULL;
@ -382,13 +435,15 @@ static const char *setup_discovered_git_dir(const char *work_tree_env,
return cwd + offset; return cwd + offset;
} }
static const char *setup_bare_git_dir(const char *work_tree_env, /* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
int offset, int len, char *cwd, int *nongit_ok) static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
{ {
int root_len; int root_len;
if (check_repository_format_gently(".", nongit_ok))
return NULL;
inside_git_dir = 1; inside_git_dir = 1;
if (!work_tree_env)
inside_work_tree = 0; inside_work_tree = 0;
if (offset != len) { if (offset != len) {
if (chdir(cwd)) if (chdir(cwd))
@ -396,9 +451,9 @@ static const char *setup_bare_git_dir(const char *work_tree_env,
root_len = offset_1st_component(cwd); root_len = offset_1st_component(cwd);
cwd[offset > root_len ? offset : root_len] = '\0'; cwd[offset > root_len ? offset : root_len] = '\0';
set_git_dir(cwd); set_git_dir(cwd);
} else }
else
set_git_dir("."); set_git_dir(".");
check_repository_format_gently(nongit_ok);
return NULL; return NULL;
} }
@ -428,11 +483,10 @@ static dev_t get_device_or_die(const char *path, const char *prefix)
*/ */
static const char *setup_git_directory_gently_1(int *nongit_ok) static const char *setup_git_directory_gently_1(int *nongit_ok)
{ {
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
static char cwd[PATH_MAX+1]; static char cwd[PATH_MAX+1];
const char *gitdirenv; const char *gitdirenv, *ret;
const char *gitfile_dir; char *gitfile;
int len, offset, ceil_offset; int len, offset, ceil_offset;
dev_t current_device = 0; dev_t current_device = 0;
int one_filesystem = 1; int one_filesystem = 1;
@ -445,6 +499,10 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
if (nongit_ok) if (nongit_ok)
*nongit_ok = 0; *nongit_ok = 0;
if (!getcwd(cwd, sizeof(cwd)-1))
die_errno("Unable to read current working directory");
offset = len = strlen(cwd);
/* /*
* If GIT_DIR is set explicitly, we're not going * If GIT_DIR is set explicitly, we're not going
* to do any discovery, but we still do repository * to do any discovery, but we still do repository
@ -452,10 +510,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
*/ */
gitdirenv = getenv(GIT_DIR_ENVIRONMENT); gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
if (gitdirenv) if (gitdirenv)
return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok); return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
if (!getcwd(cwd, sizeof(cwd)-1))
die_errno("Unable to read current working directory");
ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
@ -472,17 +527,30 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
* - ../../.git/ * - ../../.git/
* etc. * etc.
*/ */
offset = len = strlen(cwd);
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0); one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
if (one_filesystem) if (one_filesystem)
current_device = get_device_or_die(".", NULL); current_device = get_device_or_die(".", NULL);
for (;;) { for (;;) {
if (cwd_contains_git_dir(&gitfile_dir)) gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
return setup_discovered_git_dir(work_tree_env, offset, if (gitfile)
len, cwd, nongit_ok); gitdirenv = gitfile = xstrdup(gitfile);
else {
if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
}
if (gitdirenv) {
ret = setup_discovered_git_dir(gitdirenv,
cwd, offset, len,
nongit_ok);
free(gitfile);
return ret;
}
free(gitfile);
if (is_git_directory(".")) if (is_git_directory("."))
return setup_bare_git_dir(work_tree_env, offset, return setup_bare_git_dir(cwd, offset, len, nongit_ok);
len, cwd, nongit_ok);
while (--offset > ceil_offset && cwd[offset] != '/'); while (--offset > ceil_offset && cwd[offset] != '/');
if (offset <= ceil_offset) if (offset <= ceil_offset)
return setup_nongit(cwd, nongit_ok); return setup_nongit(cwd, nongit_ok);
@ -592,7 +660,7 @@ int check_repository_format_version(const char *var, const char *value, void *cb
int check_repository_format(void) int check_repository_format(void)
{ {
return check_repository_format_gently(NULL); return check_repository_format_gently(get_git_dir(), NULL);
} }
/* /*
@ -603,19 +671,5 @@ int check_repository_format(void)
*/ */
const char *setup_git_directory(void) const char *setup_git_directory(void)
{ {
const char *retval = setup_git_directory_gently(NULL); return setup_git_directory_gently(NULL);
/* If the work tree is not the default one, recompute prefix */
if (inside_work_tree < 0) {
static char buffer[PATH_MAX + 1];
char *rel;
if (retval && chdir(retval))
die_errno ("Could not jump back into original cwd");
rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
if (rel && *rel && chdir(get_git_work_tree()))
die_errno ("Could not jump to working directory");
return rel && *rel ? strcat(rel, "/") : NULL;
}
return retval;
} }

View File

@ -33,6 +33,62 @@ test_expect_success 'plain' '
check_config plain/.git false unset check_config plain/.git false unset
' '
test_expect_success 'plain nested in bare' '
(
unset GIT_DIR GIT_WORK_TREE &&
git init --bare bare-ancestor.git &&
cd bare-ancestor.git &&
mkdir plain-nested &&
cd plain-nested &&
git init
) &&
check_config bare-ancestor.git/plain-nested/.git false unset
'
test_expect_success 'plain through aliased command, outside any git repo' '
(
unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
HOME=$(pwd)/alias-config &&
export HOME &&
mkdir alias-config &&
echo "[alias] aliasedinit = init" >alias-config/.gitconfig &&
GIT_CEILING_DIRECTORIES=$(pwd) &&
export GIT_CEILING_DIRECTORIES &&
mkdir plain-aliased &&
cd plain-aliased &&
git aliasedinit
) &&
check_config plain-aliased/.git false unset
'
test_expect_failure 'plain nested through aliased command' '
(
unset GIT_DIR GIT_WORK_TREE &&
git init plain-ancestor-aliased &&
cd plain-ancestor-aliased &&
echo "[alias] aliasedinit = init" >>.git/config &&
mkdir plain-nested &&
cd plain-nested &&
git aliasedinit
) &&
check_config plain-ancestor-aliased/plain-nested/.git false unset
'
test_expect_failure 'plain nested in bare through aliased command' '
(
unset GIT_DIR GIT_WORK_TREE &&
git init --bare bare-ancestor-aliased.git &&
cd bare-ancestor-aliased.git &&
echo "[alias] aliasedinit = init" >>config &&
mkdir plain-nested &&
cd plain-nested &&
git aliasedinit
) &&
check_config bare-ancestor-aliased.git/plain-nested/.git false unset
'
test_expect_success 'plain with GIT_WORK_TREE' ' test_expect_success 'plain with GIT_WORK_TREE' '
if ( if (
sane_unset GIT_DIR && sane_unset GIT_DIR &&

View File

@ -110,6 +110,14 @@ test_expect_success 'read-tree' '
) )
' '
test_expect_success 'alias expansion' '
(
git config alias.ss status &&
cd dir &&
git status &&
git ss
)
'
test_expect_success 'no file/rev ambiguity check inside .git' ' test_expect_success 'no file/rev ambiguity check inside .git' '
git commit -a -m 1 && git commit -a -m 1 &&
( (

View File

@ -340,4 +340,11 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
' '
test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
echo "$TRASH_DIRECTORY/repo.git/work" >expected &&
test_cmp expected actual
'
test_done test_done

4532
t/t1510-repo-setup.sh Executable file

File diff suppressed because it is too large Load Diff

21
test-subprocess.c Normal file
View File

@ -0,0 +1,21 @@
#include "cache.h"
#include "run-command.h"
int main(int argc, char **argv)
{
const char *prefix;
struct child_process cp;
int nogit = 0;
prefix = setup_git_directory_gently(&nogit);
if (nogit)
die("No git repo found");
if (!strcmp(argv[1], "--setup-work-tree")) {
setup_work_tree();
argv++;
}
memset(&cp, 0, sizeof(cp));
cp.git_cmd = 1;
cp.argv = (const char **)argv+1;
return run_command(&cp);
}

42
trace.c
View File

@ -127,3 +127,45 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
if (need_close) if (need_close)
close(fd); close(fd);
} }
static const char *quote_crnl(const char *path)
{
static char new_path[PATH_MAX];
const char *p2 = path;
char *p1 = new_path;
if (!path)
return NULL;
while (*p2) {
switch (*p2) {
case '\\': *p1++ = '\\'; *p1++ = '\\'; break;
case '\n': *p1++ = '\\'; *p1++ = 'n'; break;
case '\r': *p1++ = '\\'; *p1++ = 'r'; break;
default:
*p1++ = *p2;
}
p2++;
}
*p1 = '\0';
return new_path;
}
/* FIXME: move prefix to startup_info struct and get rid of this arg */
void trace_repo_setup(const char *prefix)
{
char cwd[PATH_MAX];
char *trace = getenv("GIT_TRACE");
if (!trace || !strcmp(trace, "") ||
!strcmp(trace, "0") || !strcasecmp(trace, "false"))
return;
if (!getcwd(cwd, PATH_MAX))
die("Unable to get current working directory");
trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir()));
trace_printf("setup: worktree: %s\n", quote_crnl(get_git_work_tree()));
trace_printf("setup: cwd: %s\n", quote_crnl(cwd));
trace_printf("setup: prefix: %s\n", quote_crnl(prefix));
}