]> git.ipfire.org Git - thirdparty/git.git/commitdiff
wt-status: avoid passing NULL worktree
authorPhillip Wood <phillip.wood@dunelm.org.uk>
Thu, 19 Feb 2026 14:26:32 +0000 (14:26 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 19 Feb 2026 19:03:23 +0000 (11:03 -0800)
In preparation for removing the repository argument from
worktree_git_path() add a function to construct a "struct worktree"
from a "struct repository" using its "gitdir" and "worktree"
members. This function is then used to avoid passing a NULL worktree to
wt_status_check_bisect() and wt_status_check_rebase(). In general the
"struct worktree" returned may not correspond to the "current" worktree
defined by is_current_worktree() as that function uses "the_repository"
rather than "wt->repo" when deciding which worktree is "current". In
practice the "struct repository" we pass corresponds to "the_repository"
as we only ever operate on a single repository at the moment.

wt_status_check_bisect() and wt_status_check_rebase() have the following
callers:

 - branch.c:prepare_checked_out_branches() which loops over all
   worktrees.

 - worktree.c:is_worktree_being_rebased() which is called from
   builtin/branch.c:reject_rebase_or_bisect_branch() that loops over all
   worktrees and worktree.c:is_shared_symref() which dereferences wt
   earlier in the function.

 - wt-status:wt_status_get_state() which is updated to avoid passing a
   NULL worktree by this patch.

This updates the only callers that pass a NULL worktree to
worktree_git_path(). A new test is added to check that "git status"
detects a rebase in a linked worktree.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t7512-status-help.sh
worktree.c
worktree.h
wt-status.c

index 25e8e9711f8fefdaf935bdd163fd367f4c8b9f32..08e82f7914084196792f7e30438938edbe2be8df 100755 (executable)
@@ -594,6 +594,15 @@ EOF
        test_cmp expected actual
 '
 
+test_expect_success 'rebase in a linked worktree' '
+       test_might_fail git rebase --abort &&
+       git worktree add wt &&
+       test_when_finished "test_might_fail git -C wt rebase --abort;
+                               git worktree remove wt" &&
+       GIT_SEQUENCE_EDITOR="echo break >" git -C wt rebase -i HEAD &&
+       git -C wt status >actual &&
+       test_grep "interactive rebase in progress" actual
+'
 
 test_expect_success 'prepare am_session' '
        git reset --hard main &&
index 9308389cb6f0296b1cc21c33b95427211f840649..218c332a66dc5c2a47b3b1a92c055b423e15f8b9 100644 (file)
@@ -66,6 +66,26 @@ static int is_current_worktree(struct worktree *wt)
        return is_current;
 }
 
+struct worktree *get_worktree_from_repository(struct repository *repo)
+{
+       struct worktree *wt = xcalloc(1, sizeof(*wt));
+       char *gitdir = absolute_pathdup(repo->gitdir);
+       char *commondir = absolute_pathdup(repo->commondir);
+
+       wt->repo = repo;
+       wt->path = absolute_pathdup(repo->worktree ? repo->worktree
+                                                  : repo->gitdir);
+       wt->is_bare = !repo->worktree;
+       if (fspathcmp(gitdir, commondir))
+               wt->id = xstrdup(find_last_dir_sep(gitdir) + 1);
+       wt->is_current = is_current_worktree(wt);
+       add_head_info(wt);
+
+       free(gitdir);
+       free(commondir);
+       return wt;
+}
+
 /*
 * When in a secondary worktree, and when extensions.worktreeConfig
 * is true, only $commondir/config and $commondir/worktrees/<id>/
index e4bcccdc0aef5acdda732a0e24da667f7b2f99b7..06efe26b835a81adc9e78b74544c1a7f93884414 100644 (file)
@@ -38,6 +38,12 @@ struct worktree **get_worktrees(void);
  */
 struct worktree **get_worktrees_without_reading_head(void);
 
+/*
+ * Construct a struct worktree corresponding to repo->gitdir and
+ * repo->worktree.
+ */
+struct worktree *get_worktree_from_repository(struct repository *repo);
+
 /*
  * Returns 1 if linked worktrees exist, 0 otherwise.
  */
index e12adb26b9f8eb19ba7cf03537da4982b53f7a09..eceb41fb659746be7ccae12d18961b81ffd6da78 100644 (file)
@@ -1723,6 +1723,9 @@ int wt_status_check_rebase(const struct worktree *wt,
 {
        struct stat st;
 
+       if (!wt)
+               BUG("wt_status_check_rebase() called with NULL worktree");
+
        if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) {
                if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) {
                        state->am_in_progress = 1;
@@ -1750,6 +1753,9 @@ int wt_status_check_bisect(const struct worktree *wt,
 {
        struct stat st;
 
+       if (!wt)
+               BUG("wt_status_check_bisect() called with NULL worktree");
+
        if (!stat(worktree_git_path(the_repository, wt, "BISECT_LOG"), &st)) {
                state->bisect_in_progress = 1;
                state->bisecting_from = get_branch(wt, "BISECT_START");
@@ -1795,18 +1801,19 @@ void wt_status_get_state(struct repository *r,
        struct stat st;
        struct object_id oid;
        enum replay_action action;
+       struct worktree *wt = get_worktree_from_repository(r);
 
        if (!stat(git_path_merge_head(r), &st)) {
-               wt_status_check_rebase(NULL, state);
+               wt_status_check_rebase(wt, state);
                state->merge_in_progress = 1;
-       } else if (wt_status_check_rebase(NULL, state)) {
+       } else if (wt_status_check_rebase(wt, state)) {
                ;               /* all set */
        } else if (refs_ref_exists(get_main_ref_store(r), "CHERRY_PICK_HEAD") &&
                   !repo_get_oid(r, "CHERRY_PICK_HEAD", &oid)) {
                state->cherry_pick_in_progress = 1;
                oidcpy(&state->cherry_pick_head_oid, &oid);
        }
-       wt_status_check_bisect(NULL, state);
+       wt_status_check_bisect(wt, state);
        if (refs_ref_exists(get_main_ref_store(r), "REVERT_HEAD") &&
            !repo_get_oid(r, "REVERT_HEAD", &oid)) {
                state->revert_in_progress = 1;
@@ -1824,6 +1831,8 @@ void wt_status_get_state(struct repository *r,
        if (get_detached_from)
                wt_status_get_detached_from(r, state);
        wt_status_check_sparse_checkout(r, state);
+
+       free_worktree(wt);
 }
 
 static void wt_longstatus_print_state(struct wt_status *s)