Skip to content

Commit aaad2c9

Browse files
sunshinecogitster
authored andcommitted
checkout: improve die_if_checked_out() robustness
die_if_checked_out() is intended to check if the branch about to be checked out is already checked out either in the main worktree or in a linked worktree. However, if .git/worktrees directory does not exist, then it never bothers checking the main worktree, even though the specified branch might indeed be checked out there, which is fragile behavior. This hasn't been a problem in practice since the current implementation of "git worktree add" (and, earlier, "git checkout --to") always creates .git/worktrees before die_if_checked_out() is called by the child "git checkout" invocation which populates the new worktree. However, git-worktree will eventually want to call die_if_checked_out() itself rather than only doing so indirectly as a side-effect of invoking git-checkout, and reliance upon order of operations (creating .git/worktrees before checking if a branch is already checked out) is fragile. As a general function, callers should not be expected to abide by this undocumented and unwarranted restriction. Therefore, make die_if_checked_out() more robust by checking the main worktree whether .git/worktrees exists or not. While here, also move a comment explaining why die_if_checked_out()'s helper parses HEAD manually. Such information resides more naturally with the helper itself rather than at its first point of call. Signed-off-by: Eric Sunshine <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e13d370 commit aaad2c9

File tree

1 file changed

+7
-7
lines changed

1 file changed

+7
-7
lines changed

builtin/checkout.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,11 @@ static void check_linked_checkout(struct branch_info *new, const char *id)
880880
struct strbuf gitdir = STRBUF_INIT;
881881
const char *start, *end;
882882

883+
/*
884+
* $GIT_COMMON_DIR/HEAD is practically outside
885+
* $GIT_DIR so resolve_ref_unsafe() won't work (it
886+
* uses git_path). Parse the ref ourselves.
887+
*/
883888
if (id)
884889
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
885890
else
@@ -916,19 +921,14 @@ static void die_if_checked_out(struct branch_info *new)
916921
DIR *dir;
917922
struct dirent *d;
918923

924+
check_linked_checkout(new, NULL);
925+
919926
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
920927
if ((dir = opendir(path.buf)) == NULL) {
921928
strbuf_release(&path);
922929
return;
923930
}
924931

925-
/*
926-
* $GIT_COMMON_DIR/HEAD is practically outside
927-
* $GIT_DIR so resolve_ref_unsafe() won't work (it
928-
* uses git_path). Parse the ref ourselves.
929-
*/
930-
check_linked_checkout(new, NULL);
931-
932932
while ((d = readdir(dir)) != NULL) {
933933
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
934934
continue;

0 commit comments

Comments
 (0)