diff options
author | Junio C Hamano <gitster@pobox.com> | 2015-08-12 14:09:56 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2015-08-12 14:09:56 -0700 |
commit | 53860f03927fea9c46d64b556a06fffe4b46e41f (patch) | |
tree | 356d50e67d39bc96390d50a81c3976fb831c012f /branch.c | |
parent | 7aa2da616208a51ec51ce3639fe6abd9631b74db (diff) | |
parent | 65f9b75dfe34a67cf4c6a8507f999c5710d36ba9 (diff) | |
download | git-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.c | 67 |
1 files changed, 67 insertions, 0 deletions
@@ -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); +} |