Merge branch 'ei/worktree+filter'
* ei/worktree+filter: filter-branch: always export GIT_DIR if it is set setup_git_directory: fix segfault if repository is found in cwd test GIT_WORK_TREE extend rev-parse test for --is-inside-work-tree Use new semantics of is_bare/inside_git_dir/inside_work_tree introduce GIT_WORK_TREE to specify the work tree test git rev-parse rev-parse: introduce --is-bare-repository rev-parse: document --is-inside-git-dir
This commit is contained in:
218
setup.c
218
setup.c
@ -95,7 +95,7 @@ void verify_non_filename(const char *prefix, const char *arg)
|
||||
const char *name;
|
||||
struct stat st;
|
||||
|
||||
if (is_inside_git_dir())
|
||||
if (!is_inside_work_tree() || is_inside_git_dir())
|
||||
return;
|
||||
if (*arg == '-')
|
||||
return; /* flag */
|
||||
@ -174,41 +174,96 @@ static int inside_git_dir = -1;
|
||||
|
||||
int is_inside_git_dir(void)
|
||||
{
|
||||
if (inside_git_dir < 0) {
|
||||
char buffer[1024];
|
||||
if (inside_git_dir >= 0)
|
||||
return inside_git_dir;
|
||||
die("BUG: is_inside_git_dir called before setup_git_directory");
|
||||
}
|
||||
|
||||
if (is_bare_repository())
|
||||
return (inside_git_dir = 1);
|
||||
if (getcwd(buffer, sizeof(buffer))) {
|
||||
const char *git_dir = get_git_dir(), *cwd = buffer;
|
||||
while (*git_dir && *git_dir == *cwd) {
|
||||
git_dir++;
|
||||
cwd++;
|
||||
}
|
||||
inside_git_dir = !*git_dir;
|
||||
} else
|
||||
inside_git_dir = 0;
|
||||
static int inside_work_tree = -1;
|
||||
|
||||
int is_inside_work_tree(void)
|
||||
{
|
||||
if (inside_git_dir >= 0)
|
||||
return inside_work_tree;
|
||||
die("BUG: is_inside_work_tree called before setup_git_directory");
|
||||
}
|
||||
|
||||
static char *gitworktree_config;
|
||||
|
||||
static int git_setup_config(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "core.worktree")) {
|
||||
if (gitworktree_config)
|
||||
strlcpy(gitworktree_config, value, PATH_MAX);
|
||||
return 0;
|
||||
}
|
||||
return inside_git_dir;
|
||||
return git_default_config(var, value);
|
||||
}
|
||||
|
||||
const char *setup_git_directory_gently(int *nongit_ok)
|
||||
{
|
||||
static char cwd[PATH_MAX+1];
|
||||
const char *gitdirenv;
|
||||
int len, offset;
|
||||
char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
|
||||
const char *gitdirenv, *gitworktree;
|
||||
int wt_rel_gitdir = 0;
|
||||
|
||||
/*
|
||||
* If GIT_DIR is set explicitly, we're not going
|
||||
* to do any discovery, but we still do repository
|
||||
* validation.
|
||||
*/
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (gitdirenv) {
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv))
|
||||
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
|
||||
if (is_git_directory(gitdirenv))
|
||||
if (!gitdirenv) {
|
||||
int len, offset;
|
||||
|
||||
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
|
||||
die("Unable to read current working directory");
|
||||
|
||||
offset = len = strlen(cwd);
|
||||
for (;;) {
|
||||
if (is_git_directory(".git"))
|
||||
break;
|
||||
if (offset == 0) {
|
||||
offset = -1;
|
||||
break;
|
||||
}
|
||||
chdir("..");
|
||||
while (cwd[--offset] != '/')
|
||||
; /* do nothing */
|
||||
}
|
||||
|
||||
if (offset >= 0) {
|
||||
inside_work_tree = 1;
|
||||
git_config(git_default_config);
|
||||
if (offset == len) {
|
||||
inside_git_dir = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cwd[len++] = '/';
|
||||
cwd[len] = '\0';
|
||||
inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
|
||||
return cwd + offset + 1;
|
||||
}
|
||||
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
if (!is_git_directory(".")) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Not a git repository");
|
||||
}
|
||||
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdirenv)
|
||||
die("getenv after setenv failed");
|
||||
}
|
||||
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("$%s too big", GIT_DIR_ENVIRONMENT);
|
||||
}
|
||||
if (!is_git_directory(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
@ -218,41 +273,92 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
||||
|
||||
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Cannot change directory to $%s '%s'",
|
||||
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||
}
|
||||
if (!getcwd(gitdir, sizeof(gitdir)-1) || gitdir[0] != '/')
|
||||
die("Unable to read current working directory");
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
|
||||
offset = len = strlen(cwd);
|
||||
for (;;) {
|
||||
if (is_git_directory(".git"))
|
||||
break;
|
||||
chdir("..");
|
||||
do {
|
||||
if (!offset) {
|
||||
if (is_git_directory(cwd)) {
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
||||
inside_git_dir = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (nongit_ok) {
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
die("Not a git repository");
|
||||
/*
|
||||
* In case there is a work tree we may change the directory,
|
||||
* therefore make GIT_DIR an absolute path.
|
||||
*/
|
||||
if (gitdirenv[0] != '/') {
|
||||
setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
|
||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||
if (!gitdirenv)
|
||||
die("getenv after setenv failed");
|
||||
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||
if (nongit_ok) {
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
} while (cwd[--offset] != '/');
|
||||
die("$%s too big after expansion to absolute path",
|
||||
GIT_DIR_ENVIRONMENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == len)
|
||||
return NULL;
|
||||
strcat(cwd, "/");
|
||||
strcat(gitdir, "/");
|
||||
inside_git_dir = !prefixcmp(cwd, gitdir);
|
||||
|
||||
/* Make "offset" point to past the '/', and add a '/' at the end */
|
||||
offset++;
|
||||
cwd[len++] = '/';
|
||||
cwd[len] = 0;
|
||||
inside_git_dir = !prefixcmp(cwd + offset, ".git/");
|
||||
return cwd + offset;
|
||||
gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||
if (!gitworktree) {
|
||||
gitworktree_config = worktree;
|
||||
worktree[0] = '\0';
|
||||
}
|
||||
git_config(git_setup_config);
|
||||
if (!gitworktree) {
|
||||
gitworktree_config = NULL;
|
||||
if (worktree[0])
|
||||
gitworktree = worktree;
|
||||
if (gitworktree && gitworktree[0] != '/')
|
||||
wt_rel_gitdir = 1;
|
||||
}
|
||||
|
||||
if (wt_rel_gitdir && chdir(gitdirenv))
|
||||
die("Cannot change directory to $%s '%s'",
|
||||
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||
if (gitworktree && chdir(gitworktree)) {
|
||||
if (nongit_ok) {
|
||||
if (wt_rel_gitdir && chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
*nongit_ok = 1;
|
||||
return NULL;
|
||||
}
|
||||
if (wt_rel_gitdir)
|
||||
die("Cannot change directory to working tree '%s'"
|
||||
" from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
|
||||
else
|
||||
die("Cannot change directory to working tree '%s'",
|
||||
gitworktree);
|
||||
}
|
||||
if (!getcwd(worktree, sizeof(worktree)-1) || worktree[0] != '/')
|
||||
die("Unable to read current working directory");
|
||||
strcat(worktree, "/");
|
||||
inside_work_tree = !prefixcmp(cwd, worktree);
|
||||
|
||||
if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
|
||||
strcmp(worktree, gitdir)) {
|
||||
inside_git_dir = 0;
|
||||
}
|
||||
|
||||
if (!inside_work_tree) {
|
||||
if (chdir(cwd))
|
||||
die("Cannot come back to cwd");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strcmp(cwd, worktree))
|
||||
return NULL;
|
||||
return cwd+strlen(worktree);
|
||||
}
|
||||
|
||||
int git_config_perm(const char *var, const char *value)
|
||||
|
Reference in New Issue
Block a user