/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset, int *nongit_ok) { int root_len; if (check_repository_format_gently(".", nongit_ok)) return NULL; setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1); /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { const char *gitdir; gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); return setup_explicit_git_dir(gitdir, cwd, nongit_ok); } inside_git_dir = 1; inside_work_tree = 0; if (offset != cwd->len) { if (chdir(cwd->buf)) die_errno("Cannot come back to cwd"); root_len = offset_1st_component(cwd->buf); strbuf_setlen(cwd, offset > root_len ? offset : root_len); set_git_dir(cwd->buf); } else set_git_dir("."); return NULL; }
static const char *setup_discovered_git_dir(const char *gitdir, char *cwd, int offset, int len, int *nongit_ok) { if (check_repository_format_gently(gitdir, nongit_ok)) return NULL; /* --work-tree is set without --git-dir; use discovered one */ if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) { if (offset != len && !is_absolute_path(gitdir)) gitdir = xstrdup(real_path(gitdir)); if (chdir(cwd)) die_errno("Could not come back to cwd"); return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok); } /* #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 : real_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) return NULL; /* Make "offset" point to past the '/', and add a '/' at the end */ offset++; cwd[len++] = '/'; cwd[len] = 0; return cwd + offset; }
int check_repository_format(void) { return check_repository_format_gently(NULL); }
/* * We cannot decide in this function whether we are in the work tree or * not, since the config can only be read _after_ this function was called. */ const char *setup_git_directory_gently(int *nongit_ok) { const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT); static char cwd[PATH_MAX+1]; const char *gitdirenv; const char *gitfile_dir; int len, offset, ceil_offset; /* * Let's assume that we are in a git repository. * If it turns out later that we are somewhere else, the value will be * updated accordingly. */ if (nongit_ok) *nongit_ok = 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)) { static char buffer[1024 + 1]; const char *retval; if (!work_tree_env) { retval = set_work_tree(gitdirenv); /* config may override worktree */ if (check_repository_format_gently(nongit_ok)) return NULL; return retval; } if (check_repository_format_gently(nongit_ok)) return NULL; retval = get_relative_cwd(buffer, sizeof(buffer) - 1, get_git_work_tree()); if (!retval || !*retval) return NULL; set_git_dir(make_absolute_path(gitdirenv)); if (chdir(work_tree_env) < 0) die_errno ("Could not chdir to '%s'", work_tree_env); strcat(buffer, "/"); return retval; } if (nongit_ok) { *nongit_ok = 1; return NULL; } die("Not a git repository: '%s'", gitdirenv); } if (!getcwd(cwd, sizeof(cwd)-1)) die_errno("Unable to read current working directory"); ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) ceil_offset = 1; /* * Test in the following order (relative to the cwd): * - .git (file containing "gitdir: <path>") * - .git/ * - ./ (bare) * - ../.git * - ../.git/ * - ../ (bare) * - ../../.git/ * etc. */ offset = len = strlen(cwd); for (;;) { gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT); if (gitfile_dir) { if (set_git_dir(gitfile_dir)) die("Repository setup failed"); break; } if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) break; if (is_git_directory(".")) { inside_git_dir = 1; if (!work_tree_env) inside_work_tree = 0; if (offset != len) { cwd[offset] = '\0'; setenv(GIT_DIR_ENVIRONMENT, cwd, 1); } else setenv(GIT_DIR_ENVIRONMENT, ".", 1); check_repository_format_gently(nongit_ok); return NULL; } while (--offset > ceil_offset && cwd[offset] != '/'); if (offset <= ceil_offset) { if (nongit_ok) { if (chdir(cwd)) die_errno("Cannot come back to cwd"); *nongit_ok = 1; return NULL; } die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); } if (chdir("..")) die_errno("Cannot change to '%s/..'", cwd); } inside_git_dir = 0; if (!work_tree_env) inside_work_tree = 1; git_work_tree_cfg = xstrndup(cwd, offset); if (check_repository_format_gently(nongit_ok)) return NULL; if (offset == len) return NULL; /* Make "offset" point to past the '/', and add a '/' at the end */ offset++; cwd[len++] = '/'; cwd[len] = 0; return cwd + offset; }
int check_repository_format(void) { return check_repository_format_gently(get_git_dir(), NULL); }
static const char *setup_explicit_git_dir(const char *gitdirenv, struct strbuf *cwd, int *nongit_ok) { const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; int offset; if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); gitfile = (char*)read_gitfile(gitdirenv); if (gitfile) { gitfile = xstrdup(gitfile); gitdirenv = gitfile; } if (!is_git_directory(gitdirenv)) { if (nongit_ok) { *nongit_ok = 1; free(gitfile); return NULL; } die("Not a git repository: '%s'", gitdirenv); } if (check_repository_format_gently(gitdirenv, nongit_ok)) { free(gitfile); return NULL; } /* #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 */ warning("core.bare and core.worktree do not make sense"); work_tree_config_is_bogus = 1; } /* #18, #26 */ set_git_dir(gitdirenv); free(gitfile); return NULL; } else if (git_work_tree_cfg) { /* #6, #14 */ if (is_absolute_path(git_work_tree_cfg)) set_git_work_tree(git_work_tree_cfg); else { char *core_worktree; 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); core_worktree = xgetcwd(); if (chdir(cwd->buf)) die_errno("Could not come back to cwd"); set_git_work_tree(core_worktree); free(core_worktree); } } else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) { /* #16d */ set_git_dir(gitdirenv); free(gitfile); return NULL; } 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->buf, worktree)) { /* cwd == worktree */ set_git_dir(gitdirenv); free(gitfile); return NULL; } offset = dir_inside_of(cwd->buf, worktree); if (offset >= 0) { /* cwd inside worktree? */ set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); strbuf_addch(cwd, '/'); free(gitfile); return cwd->buf + offset; } /* cwd outside worktree */ set_git_dir(gitdirenv); free(gitfile); return NULL; }
void check_repository_format(void) { check_repository_format_gently(get_git_dir(), NULL); startup_info->have_repository = 1; }
static const char *setup_explicit_git_dir(const char *gitdirenv, char *cwd, int len, int *nongit_ok) { const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; if (PATH_MAX - 40 < strlen(gitdirenv)) 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 (nongit_ok) { *nongit_ok = 1; free(gitfile); return NULL; } die("Not a git repository: '%s'", gitdirenv); } if (check_repository_format_gently(gitdirenv, nongit_ok)) { free(gitfile); return NULL; } /* #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; } else if (git_work_tree_cfg) { /* #6, #14 */ 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; } if (!prefixcmp(cwd, worktree) && cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); cwd[len++] = '/'; cwd[len] = '\0'; free(gitfile); return cwd + strlen(worktree) + 1; } /* cwd outside worktree */ set_git_dir(gitdirenv); free(gitfile); return NULL; }