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
  ...
This commit is contained in:
Junio C Hamano
2015-08-12 14:09:56 -07:00
7 changed files with 212 additions and 125 deletions

View File

@ -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);
}