Skip to content

Commit ed89f84

Browse files
sunshinecogitster
authored andcommitted
branch: publish die_if_checked_out()
git-worktree currently conflates new branch creation, setting of HEAD in the new wortkree, and worktree population into a single sub-invocation of git-checkout. However, these operations will eventually be separated, and git-worktree itself will need to be able to detect if the branch is already checked out elsewhere, rather than relying upon git-branch to make this determination, so publish die_if_checked_out(). Signed-off-by: Eric Sunshine <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 746bbdc commit ed89f84

File tree

3 files changed

+74
-67
lines changed

3 files changed

+74
-67
lines changed

branch.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,70 @@ void remove_branch_state(void)
309309
unlink(git_path("MERGE_MODE"));
310310
unlink(git_path("SQUASH_MSG"));
311311
}
312+
313+
static void check_linked_checkout(const char *branch, const char *id)
314+
{
315+
struct strbuf sb = STRBUF_INIT;
316+
struct strbuf path = STRBUF_INIT;
317+
struct strbuf gitdir = STRBUF_INIT;
318+
319+
/*
320+
* $GIT_COMMON_DIR/HEAD is practically outside
321+
* $GIT_DIR so resolve_ref_unsafe() won't work (it
322+
* uses git_path). Parse the ref ourselves.
323+
*/
324+
if (id)
325+
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
326+
else
327+
strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
328+
329+
if (!strbuf_readlink(&sb, path.buf, 0)) {
330+
if (!starts_with(sb.buf, "refs/") ||
331+
check_refname_format(sb.buf, 0))
332+
goto done;
333+
} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
334+
starts_with(sb.buf, "ref:")) {
335+
strbuf_remove(&sb, 0, strlen("ref:"));
336+
strbuf_trim(&sb);
337+
} else
338+
goto done;
339+
if (strcmp(sb.buf, branch))
340+
goto done;
341+
if (id) {
342+
strbuf_reset(&path);
343+
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
344+
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
345+
goto done;
346+
strbuf_rtrim(&gitdir);
347+
} else
348+
strbuf_addstr(&gitdir, get_git_common_dir());
349+
skip_prefix(branch, "refs/heads/", &branch);
350+
strbuf_strip_suffix(&gitdir, ".git");
351+
die(_("'%s' is already checked out at '%s'"), branch, gitdir.buf);
352+
done:
353+
strbuf_release(&path);
354+
strbuf_release(&sb);
355+
strbuf_release(&gitdir);
356+
}
357+
358+
void die_if_checked_out(const char *branch)
359+
{
360+
struct strbuf path = STRBUF_INIT;
361+
DIR *dir;
362+
struct dirent *d;
363+
364+
check_linked_checkout(branch, NULL);
365+
366+
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
367+
dir = opendir(path.buf);
368+
strbuf_release(&path);
369+
if (!dir)
370+
return;
371+
372+
while ((d = readdir(dir)) != NULL) {
373+
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
374+
continue;
375+
check_linked_checkout(branch, d->d_name);
376+
}
377+
closedir(dir);
378+
}

branch.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,11 @@ extern void install_branch_config(int flag, const char *local, const char *origi
5252
*/
5353
extern int read_branch_desc(struct strbuf *, const char *branch_name);
5454

55+
/*
56+
* Check if a branch is checked out in the main worktree or any linked
57+
* worktree and die (with a message describing its checkout location) if
58+
* it is.
59+
*/
60+
extern void die_if_checked_out(const char *branch);
61+
5562
#endif

builtin/checkout.c

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -873,73 +873,6 @@ static const char *unique_tracking_name(const char *name, unsigned char *sha1)
873873
return NULL;
874874
}
875875

876-
static void check_linked_checkout(const char *branch, const char *id)
877-
{
878-
struct strbuf sb = STRBUF_INIT;
879-
struct strbuf path = STRBUF_INIT;
880-
struct strbuf gitdir = STRBUF_INIT;
881-
882-
/*
883-
* $GIT_COMMON_DIR/HEAD is practically outside
884-
* $GIT_DIR so resolve_ref_unsafe() won't work (it
885-
* uses git_path). Parse the ref ourselves.
886-
*/
887-
if (id)
888-
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
889-
else
890-
strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
891-
892-
if (!strbuf_readlink(&sb, path.buf, 0)) {
893-
if (!starts_with(sb.buf, "refs/") ||
894-
check_refname_format(sb.buf, 0))
895-
goto done;
896-
} else if (strbuf_read_file(&sb, path.buf, 0) >= 0 &&
897-
starts_with(sb.buf, "ref:")) {
898-
strbuf_remove(&sb, 0, strlen("ref:"));
899-
strbuf_trim(&sb);
900-
} else
901-
goto done;
902-
if (strcmp(sb.buf, branch))
903-
goto done;
904-
if (id) {
905-
strbuf_reset(&path);
906-
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
907-
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
908-
goto done;
909-
strbuf_rtrim(&gitdir);
910-
} else
911-
strbuf_addstr(&gitdir, get_git_common_dir());
912-
skip_prefix(branch, "refs/heads/", &branch);
913-
strbuf_strip_suffix(&gitdir, ".git");
914-
die(_("'%s' is already checked out at '%s'"), branch, gitdir.buf);
915-
done:
916-
strbuf_release(&path);
917-
strbuf_release(&sb);
918-
strbuf_release(&gitdir);
919-
}
920-
921-
static void die_if_checked_out(const char *branch)
922-
{
923-
struct strbuf path = STRBUF_INIT;
924-
DIR *dir;
925-
struct dirent *d;
926-
927-
check_linked_checkout(branch, NULL);
928-
929-
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
930-
dir = opendir(path.buf);
931-
strbuf_release(&path);
932-
if (!dir)
933-
return;
934-
935-
while ((d = readdir(dir)) != NULL) {
936-
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
937-
continue;
938-
check_linked_checkout(branch, d->d_name);
939-
}
940-
closedir(dir);
941-
}
942-
943876
static int parse_branchname_arg(int argc, const char **argv,
944877
int dwim_new_local_branch_ok,
945878
struct branch_info *new,

0 commit comments

Comments
 (0)