diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-05-11 21:23:39 (GMT) |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-05-11 21:23:39 (GMT) |
commit | 68a2e6a2c80303144807c8c91a087427e3c8e727 (patch) | |
tree | 96f1e79d314e0250141fe7bc88995361ebd21c18 /setup.c | |
parent | 17c7f4d8e4e0e54148f77db4cf73e07aae484ae9 (diff) | |
parent | 562bc080934b1bd16099723e80cc82a0dc6356b7 (diff) | |
download | git-68a2e6a2c80303144807c8c91a087427e3c8e727.zip git-68a2e6a2c80303144807c8c91a087427e3c8e727.tar.gz git-68a2e6a2c80303144807c8c91a087427e3c8e727.tar.bz2 |
Merge branch 'nd/multiple-work-trees'
A replacement for contrib/workdir/git-new-workdir that does not
rely on symbolic links and make sharing of objects and refs safer
by making the borrowee and borrowers aware of each other.
* nd/multiple-work-trees: (41 commits)
prune --worktrees: fix expire vs worktree existence condition
t1501: fix test with split index
t2026: fix broken &&-chain
t2026 needs procondition SANITY
git-checkout.txt: a note about multiple checkout support for submodules
checkout: add --ignore-other-wortrees
checkout: pass whole struct to parse_branchname_arg instead of individual flags
git-common-dir: make "modules/" per-working-directory directory
checkout: do not fail if target is an empty directory
t2025: add a test to make sure grafts is working from a linked checkout
checkout: don't require a work tree when checking out into a new one
git_path(): keep "info/sparse-checkout" per work-tree
count-objects: report unused files in $GIT_DIR/worktrees/...
gc: support prune --worktrees
gc: factor out gc.pruneexpire parsing code
gc: style change -- no SP before closing parenthesis
checkout: clean up half-prepared directories in --to mode
checkout: reject if the branch is already checked out elsewhere
prune: strategies for linked checkouts
checkout: support checking out into a new working directory
...
Diffstat (limited to 'setup.c')
-rw-r--r-- | setup.c | 124 |
1 files changed, 97 insertions, 27 deletions
@@ -224,6 +224,36 @@ void verify_non_filename(const char *prefix, const char *arg) "'git <command> [<revision>...] -- [<file>...]'", arg); } +int get_common_dir(struct strbuf *sb, const char *gitdir) +{ + struct strbuf data = STRBUF_INIT; + struct strbuf path = STRBUF_INIT; + const char *git_common_dir = getenv(GIT_COMMON_DIR_ENVIRONMENT); + int ret = 0; + if (git_common_dir) { + strbuf_addstr(sb, git_common_dir); + return 1; + } + strbuf_addf(&path, "%s/commondir", gitdir); + if (file_exists(path.buf)) { + if (strbuf_read_file(&data, path.buf, 0) <= 0) + die_errno(_("failed to read %s"), path.buf); + while (data.len && (data.buf[data.len - 1] == '\n' || + data.buf[data.len - 1] == '\r')) + data.len--; + data.buf[data.len] = '\0'; + strbuf_reset(&path); + if (!is_absolute_path(data.buf)) + strbuf_addf(&path, "%s/", gitdir); + strbuf_addbuf(&path, &data); + strbuf_addstr(sb, real_path(path.buf)); + ret = 1; + } else + strbuf_addstr(sb, gitdir); + strbuf_release(&data); + strbuf_release(&path); + return ret; +} /* * Test if it looks like we're at a git directory. @@ -238,31 +268,40 @@ void verify_non_filename(const char *prefix, const char *arg) */ int is_git_directory(const char *suspect) { - char path[PATH_MAX]; - size_t len = strlen(suspect); + struct strbuf path = STRBUF_INIT; + int ret = 0; + size_t len; - if (PATH_MAX <= len + strlen("/objects")) - die("Too long path: %.*s", 60, suspect); - strcpy(path, suspect); + /* Check worktree-related signatures */ + strbuf_addf(&path, "%s/HEAD", suspect); + if (validate_headref(path.buf)) + goto done; + + strbuf_reset(&path); + get_common_dir(&path, suspect); + len = path.len; + + /* Check non-worktree-related signatures */ if (getenv(DB_ENVIRONMENT)) { if (access(getenv(DB_ENVIRONMENT), X_OK)) - return 0; + goto done; } else { - strcpy(path + len, "/objects"); - if (access(path, X_OK)) - return 0; + strbuf_setlen(&path, len); + strbuf_addstr(&path, "/objects"); + if (access(path.buf, X_OK)) + goto done; } - strcpy(path + len, "/refs"); - if (access(path, X_OK)) - return 0; - - strcpy(path + len, "/HEAD"); - if (validate_headref(path)) - return 0; + strbuf_setlen(&path, len); + strbuf_addstr(&path, "/refs"); + if (access(path.buf, X_OK)) + goto done; - return 1; + ret = 1; +done: + strbuf_release(&path); + return ret; } int is_inside_git_dir(void) @@ -304,9 +343,28 @@ void setup_work_tree(void) initialized = 1; } +static int check_repo_format(const char *var, const char *value, void *cb) +{ + if (strcmp(var, "core.repositoryformatversion") == 0) + repository_format_version = git_config_int(var, value); + else if (strcmp(var, "core.sharedrepository") == 0) + shared_repository = git_config_perm(var, value); + return 0; +} + static int check_repository_format_gently(const char *gitdir, int *nongit_ok) { - char repo_config[PATH_MAX+1]; + struct strbuf sb = STRBUF_INIT; + const char *repo_config; + config_fn_t fn; + int ret = 0; + + if (get_common_dir(&sb, gitdir)) + fn = check_repo_format; + else + fn = check_repository_format_version; + strbuf_addstr(&sb, "/config"); + repo_config = sb.buf; /* * git_config() can't be used here because it calls git_pathdup() @@ -317,8 +375,7 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) * 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); + git_config_early(fn, NULL, repo_config); if (GIT_REPO_VERSION < repository_format_version) { if (!nongit_ok) die ("Expected git repo version <= %d, found %d", @@ -327,9 +384,21 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok) GIT_REPO_VERSION, repository_format_version); warning("Please upgrade Git"); *nongit_ok = -1; - return -1; + ret = -1; } - return 0; + strbuf_release(&sb); + return ret; +} + +static void update_linked_gitdir(const char *gitfile, const char *gitdir) +{ + struct strbuf path = STRBUF_INIT; + struct stat st; + + strbuf_addf(&path, "%s/gitfile", gitdir); + if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL)) + write_file(path.buf, 0, "%s\n", gitfile); + strbuf_release(&path); } /* @@ -380,6 +449,8 @@ const char *read_gitfile(const char *path) if (!is_git_directory(dir)) die("Not a git repository: %s", dir); + + update_linked_gitdir(path, dir); path = real_path(dir); free(buf); @@ -799,11 +870,10 @@ int git_config_perm(const char *var, const char *value) int check_repository_format_version(const char *var, const char *value, void *cb) { - if (strcmp(var, "core.repositoryformatversion") == 0) - repository_format_version = git_config_int(var, value); - else if (strcmp(var, "core.sharedrepository") == 0) - shared_repository = git_config_perm(var, value); - else if (strcmp(var, "core.bare") == 0) { + int ret = check_repo_format(var, value, cb); + if (ret) + return ret; + if (strcmp(var, "core.bare") == 0) { is_bare_repository_cfg = git_config_bool(var, value); if (is_bare_repository_cfg == 1) inside_work_tree = -1; |