checkout: improve die_if_checked_out() robustness
[gitweb.git] / builtin / checkout.c
index 01c7c30d54f475ab50fc2cae7f9d33e94b0f2a98..1992c41d484e0755858bbe0be80618f3322b8349 100644 (file)
@@ -35,6 +35,7 @@ struct checkout_opts {
        int writeout_stage;
        int overwrite_ignore;
        int ignore_skipworktree;
+       int ignore_other_worktrees;
 
        const char *new_branch;
        const char *new_branch_force;
@@ -879,6 +880,11 @@ static void check_linked_checkout(struct branch_info *new, const char *id)
        struct strbuf gitdir = STRBUF_INIT;
        const char *start, *end;
 
+       /*
+        * $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
@@ -902,33 +908,27 @@ static void check_linked_checkout(struct branch_info *new, const char *id)
                strbuf_rtrim(&gitdir);
        } else
                strbuf_addstr(&gitdir, get_git_common_dir());
-       die(_("'%s' is already checked out at '%s'; use --force to override"),
-           new->name, gitdir.buf);
+       die(_("'%s' is already checked out at '%s'"), new->name, gitdir.buf);
 done:
        strbuf_release(&path);
        strbuf_release(&sb);
        strbuf_release(&gitdir);
 }
 
-static void check_linked_checkouts(struct branch_info *new)
+static void die_if_checked_out(struct branch_info *new)
 {
        struct strbuf path = STRBUF_INIT;
        DIR *dir;
        struct dirent *d;
 
+       check_linked_checkout(new, NULL);
+
        strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
        if ((dir = opendir(path.buf)) == NULL) {
                strbuf_release(&path);
                return;
        }
 
-       /*
-        * $GIT_COMMON_DIR/HEAD is practically outside
-        * $GIT_DIR so resolve_ref_unsafe() won't work (it
-        * uses git_path). Parse the ref ourselves.
-        */
-       check_linked_checkout(new, NULL);
-
        while ((d = readdir(dir)) != NULL) {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                        continue;
@@ -1145,14 +1145,14 @@ static int checkout_branch(struct checkout_opts *opts,
                die(_("Cannot switch branch to a non-commit '%s'"),
                    new->name);
 
-       if (new->path && !opts->force_detach && !opts->new_branch) {
+       if (new->path && !opts->force_detach && !opts->new_branch &&
+           !opts->ignore_other_worktrees) {
                unsigned char sha1[20];
                int flag;
                char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
                if (head_ref &&
-                   (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
-                   !opts->force)
-                       check_linked_checkouts(new);
+                   (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
+                       die_if_checked_out(new);
                free(head_ref);
        }
 
@@ -1198,6 +1198,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                         N_("do not limit pathspecs to sparse entries only")),
                OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
                                N_("second guess 'git checkout no-such-branch'")),
+               OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
+                        N_("do not check if another worktree is holding the given ref")),
                OPT_END(),
        };