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:
commit
f3bb8b4b84
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
1
Makefile
1
Makefile
@ -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
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
2
cache.h
2
cache.h
@ -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 */
|
||||||
|
19
config.c
19
config.c
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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
4
git.c
@ -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
236
setup.c
@ -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;
|
|
||||||
}
|
}
|
||||||
|
@ -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 &&
|
||||||
|
@ -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 &&
|
||||||
(
|
(
|
||||||
|
@ -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
4532
t/t1510-repo-setup.sh
Executable file
File diff suppressed because it is too large
Load Diff
21
test-subprocess.c
Normal file
21
test-subprocess.c
Normal 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
42
trace.c
@ -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));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user