summaryrefslogtreecommitdiff
path: root/branch.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2015-08-12 14:09:56 -0700
committerJunio C Hamano <gitster@pobox.com>2015-08-12 14:09:56 -0700
commit53860f03927fea9c46d64b556a06fffe4b46e41f (patch)
tree356d50e67d39bc96390d50a81c3976fb831c012f /branch.c
parent7aa2da616208a51ec51ce3639fe6abd9631b74db (diff)
parent65f9b75dfe34a67cf4c6a8507f999c5710d36ba9 (diff)
downloadgit-53860f03927fea9c46d64b556a06fffe4b46e41f.tar.gz
Merge branch 'es/worktree-add-cleanup'
The "new-worktree-mode" hack in "checkout" that was added in nd/multiple-work-trees topic has been removed by updating the implementation of new "worktree add". * es/worktree-add-cleanup: (25 commits) Documentation/git-worktree: fix duplicated 'from' Documentation/config: mention "now" and "never" for 'expire' settings Documentation/git-worktree: fix broken 'linkgit' invocation checkout: drop intimate knowledge of newly created worktree worktree: populate via "git reset --hard" rather than "git checkout" worktree: avoid resolving HEAD unnecessarily worktree: make setup of new HEAD distinct from worktree population worktree: detect branch-name/detached and error conditions locally worktree: add_worktree: construct worktree-population command locally worktree: elucidate environment variables intended for child processes worktree: make branch creation distinct from worktree population worktree: add: suppress auto-vivication with --detach and no <branch> worktree: make --detach mutually exclusive with -b/-B worktree: introduce options container worktree: simplify new branch (-b/-B) option checking worktree: improve worktree setup message branch: publish die_if_checked_out() checkout: teach check_linked_checkout() about symbolic link HEAD checkout: check_linked_checkout: simplify symref parsing checkout: check_linked_checkout: improve "already checked out" aesthetic ...
Diffstat (limited to 'branch.c')
-rw-r--r--branch.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/branch.c b/branch.c
index b0024353f4..c85be0785b 100644
--- a/branch.c
+++ b/branch.c
@@ -310,3 +310,70 @@ void remove_branch_state(void)
unlink(git_path("MERGE_MODE"));
unlink(git_path("SQUASH_MSG"));
}
+
+static void check_linked_checkout(const char *branch, const char *id)
+{
+ struct strbuf sb = STRBUF_INIT;
+ struct strbuf path = STRBUF_INIT;
+ struct strbuf gitdir = STRBUF_INIT;
+
+ /*
+ * $GIT_COMMON_DIR/HEAD is practically outside
+ * $GIT_DIR so resolve_ref_unsafe() won't work (it
+ * uses git_path). Parse the ref ourselves.
+ */
+ if (id)
+ strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
+ else
+ strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
+
+ if (!strbuf_readlink(&sb, path.buf, 0)) {
+ if (!starts_with(sb.buf, "refs/") ||
+ check_refname_format(sb.buf, 0))
+ goto done;
+ } else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
+ starts_with(sb.buf, "ref:")) {
+ strbuf_remove(&sb, 0, strlen("ref:"));
+ strbuf_trim(&sb);
+ } else
+ goto done;
+ if (strcmp(sb.buf, branch))
+ goto done;
+ if (id) {
+ strbuf_reset(&path);
+ strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
+ if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
+ goto done;
+ strbuf_rtrim(&gitdir);
+ } else
+ strbuf_addstr(&gitdir, get_git_common_dir());
+ skip_prefix(branch, "refs/heads/", &branch);
+ strbuf_strip_suffix(&gitdir, ".git");
+ die(_("'%s' is already checked out at '%s'"), branch, gitdir.buf);
+done:
+ strbuf_release(&path);
+ strbuf_release(&sb);
+ strbuf_release(&gitdir);
+}
+
+void die_if_checked_out(const char *branch)
+{
+ struct strbuf path = STRBUF_INIT;
+ DIR *dir;
+ struct dirent *d;
+
+ check_linked_checkout(branch, NULL);
+
+ strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+ dir = opendir(path.buf);
+ strbuf_release(&path);
+ if (!dir)
+ return;
+
+ while ((d = readdir(dir)) != NULL) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+ check_linked_checkout(branch, d->d_name);
+ }
+ closedir(dir);
+}