From: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, karthik.188@gmail.com,
Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
Subject: [RFC][PATCH 2/2] worktree: stop passing NULL as primary worktree
Date: Fri, 13 Feb 2026 17:29:54 +0530 [thread overview]
Message-ID: <20260213120529.15475-3-shreyanshpaliwalcmsmn@gmail.com> (raw)
In-Reply-To: <20260213120529.15475-1-shreyanshpaliwalcmsmn@gmail.com>
Some functions like repo_git_pathv() in path.c, wt_status_check_rebase()
and wt_status_check_bisect() in wt-status.c, get_worktree_git_dir() in
builtin/worktree.c are called with a NULL worktree. This makes it difficult
to access fields like `wt->repo` and add extra handling for checking wt is
defined.
Add a helper function of get_worktrees_internal() as get_worktrees_repo()
and pass struct repository down the callstack to get_main_worktree()
function so that the primary worktree of a specific repository can be
accessed instead of just the_repository.
Access the primary worktree by the help of get_worktrees_repo() and pass it
to the functions as struct worktree instead of passing NULL.
Further `worktree_git_path()` no longer needs a separate
`struct repository *` parameter. Use `wt->repo` instead and update its
callers accordingly.
while at, replace any unecessary checks for wt to be defined with
is_main_worktree(wt).
Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
---
builtin/fsck.c | 2 +-
builtin/worktree.c | 10 +++++++---
path.c | 27 +++++++++++++--------------
path.h | 9 +++------
refs.c | 4 ++--
revision.c | 6 ++++--
worktree.c | 29 ++++++++++++++++-------------
worktree.h | 7 +++++++
wt-status.c | 22 ++++++++++++----------
9 files changed, 65 insertions(+), 51 deletions(-)
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 0512f78a87..42ba0afb91 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -1137,7 +1137,7 @@ int cmd_fsck(int argc,
* and may get overwritten by other calls
* while we're examining the index.
*/
- path = xstrdup(worktree_git_path(the_repository, wt, "index"));
+ path = xstrdup(worktree_git_path(wt, "index"));
wt_gitdir = get_worktree_git_dir(wt);
read_index_from(&istate, path, wt_gitdir);
diff --git a/builtin/worktree.c b/builtin/worktree.c
index fbdaf2eb2e..27c5889c89 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -328,6 +328,8 @@ static void check_candidate_path(const char *path,
wt = find_worktree_by_path(worktrees, path);
if (!wt)
return;
+ if(is_main_worktree(wt))
+ die(_("'%s' is the main worktree"), path);
locked = !!worktree_lock_reason(wt);
if ((!locked && force) || (locked && force > 1)) {
@@ -660,7 +662,8 @@ static int can_use_local_refs(const struct add_opts *opts)
if (!opts->quiet) {
struct strbuf path = STRBUF_INIT;
struct strbuf contents = STRBUF_INIT;
- char *wt_gitdir = get_worktree_git_dir(NULL);
+ struct worktree **worktrees = get_worktrees_repo(the_repository);
+ char *wt_gitdir = get_worktree_git_dir(worktrees[0]);
strbuf_add_real_path(&path, wt_gitdir);
strbuf_addstr(&path, "/HEAD");
@@ -675,6 +678,7 @@ static int can_use_local_refs(const struct add_opts *opts)
strbuf_release(&path);
strbuf_release(&contents);
free(wt_gitdir);
+ free_worktrees(worktrees);
}
return 1;
}
@@ -1191,14 +1195,14 @@ static void validate_no_submodules(const struct worktree *wt)
wt_gitdir = get_worktree_git_dir(wt);
- if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
+ if (is_directory(worktree_git_path(wt, "modules"))) {
/*
* There could be false positives, e.g. the "modules"
* directory exists but is empty. But it's a rare case and
* this simpler check is probably good enough for now.
*/
found_submodules = 1;
- } else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
+ } else if (read_index_from(&istate, worktree_git_path(wt, "index"),
wt_gitdir) > 0) {
for (i = 0; i < istate.cache_nr; i++) {
struct cache_entry *ce = istate.cache[i];
diff --git a/path.c b/path.c
index d726537622..4ac86e1e58 100644
--- a/path.c
+++ b/path.c
@@ -408,9 +408,7 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
const struct repository *repo,
const struct worktree *wt)
{
- if (!wt)
- strbuf_addstr(buf, repo->gitdir);
- else if (!wt->id)
+ if (is_main_worktree(wt))
strbuf_addstr(buf, repo->commondir);
else
repo_common_path_append(repo, buf, "worktrees/%s", wt->id);
@@ -426,7 +424,7 @@ static void repo_git_pathv(struct repository *repo,
strbuf_addch(buf, '/');
gitdir_len = buf->len;
strbuf_vaddf(buf, fmt, args);
- if (!wt)
+ if (is_main_worktree(wt))
adjust_git_path(repo, buf, gitdir_len);
strbuf_cleanup_path(buf);
}
@@ -437,8 +435,10 @@ char *repo_git_path(struct repository *repo,
struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
- repo_git_pathv(repo, NULL, &path, fmt, args);
+ struct worktree **worktrees = get_worktrees_repo(repo);
+ repo_git_pathv(repo, worktrees[0], &path, fmt, args);
va_end(args);
+ free_worktrees(worktrees);
return strbuf_detach(&path, NULL);
}
@@ -448,8 +448,10 @@ const char *repo_git_path_append(struct repository *repo,
{
va_list args;
va_start(args, fmt);
- repo_git_pathv(repo, NULL, sb, fmt, args);
+ struct worktree **worktrees = get_worktrees_repo(repo);
+ repo_git_pathv(repo, worktrees[0], sb, fmt, args);
va_end(args);
+ free_worktrees(worktrees);
return sb->buf;
}
@@ -460,8 +462,10 @@ const char *repo_git_path_replace(struct repository *repo,
va_list args;
strbuf_reset(sb);
va_start(args, fmt);
- repo_git_pathv(repo, NULL, sb, fmt, args);
+ struct worktree **worktrees = get_worktrees_repo(repo);
+ repo_git_pathv(repo, worktrees[0], sb, fmt, args);
va_end(args);
+ free_worktrees(worktrees);
return sb->buf;
}
@@ -486,17 +490,12 @@ const char *mkpath(const char *fmt, ...)
return cleanup_path(pathname->buf);
}
-const char *worktree_git_path(struct repository *r,
- const struct worktree *wt, const char *fmt, ...)
+const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
{
struct strbuf *pathname = get_pathname();
va_list args;
-
- if (wt && wt->repo != r)
- BUG("worktree not connected to expected repository");
-
va_start(args, fmt);
- repo_git_pathv(r, wt, pathname, fmt, args);
+ repo_git_pathv(wt->repo, wt, pathname, fmt, args);
va_end(args);
return pathname->buf;
}
diff --git a/path.h b/path.h
index 0ec95a0b07..54e09b2883 100644
--- a/path.h
+++ b/path.h
@@ -66,13 +66,10 @@ const char *repo_git_path_replace(struct repository *repo,
/*
* Similar to repo_git_path() but can produce paths for a specified
- * worktree instead of current one. When no worktree is given, then the path is
- * computed relative to main worktree of the given repository.
+ * worktree instead of current one.
*/
-const char *worktree_git_path(struct repository *r,
- const struct worktree *wt,
- const char *fmt, ...)
- __attribute__((format (printf, 3, 4)));
+const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
/*
* The `repo_worktree_path` family of functions will construct a path into a
diff --git a/refs.c b/refs.c
index 627b7f8698..98df2235e7 100644
--- a/refs.c
+++ b/refs.c
@@ -2324,12 +2324,12 @@ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
if (wt->is_current)
return get_main_ref_store(wt->repo);
- id = wt->id ? wt->id : "/";
+ id = wt->id;
refs = lookup_ref_store_map(&wt->repo->worktree_ref_stores, id);
if (refs)
return refs;
- if (wt->id) {
+ if (!is_main_worktree(wt)) {
struct strbuf common_path = STRBUF_INIT;
repo_common_path_append(wt->repo, &common_path,
"worktrees/%s", wt->id);
diff --git a/revision.c b/revision.c
index 9b131670f7..a9d4f796ed 100644
--- a/revision.c
+++ b/revision.c
@@ -1730,12 +1730,14 @@ void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
cb.all_revs = revs;
cb.all_flags = flags;
- cb.wt = NULL;
+ struct worktree **worktrees = get_worktrees_repo(the_repository);
+ cb.wt = worktrees[0];
refs_for_each_reflog(get_main_ref_store(the_repository),
handle_one_reflog, &cb);
if (!revs->single_worktree)
add_other_reflogs_to_pending(&cb);
+ free_worktrees(worktrees);
}
static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
@@ -1847,7 +1849,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
wt_gitdir = get_worktree_git_dir(wt);
if (read_index_from(&istate,
- worktree_git_path(the_repository, wt, "index"),
+ worktree_git_path(wt, "index"),
wt_gitdir) > 0)
do_add_index_objects_to_pending(revs, &istate, flags);
diff --git a/worktree.c b/worktree.c
index b29934407f..1059c18115 100644
--- a/worktree.c
+++ b/worktree.c
@@ -91,16 +91,16 @@ static int is_main_worktree_bare(struct repository *repo)
/**
* get the main worktree
*/
-static struct worktree *get_main_worktree(int skip_reading_head)
+static struct worktree *get_main_worktree(struct repository *repo, int skip_reading_head)
{
struct worktree *worktree = NULL;
struct strbuf worktree_path = STRBUF_INIT;
- strbuf_add_real_path(&worktree_path, repo_get_common_dir(the_repository));
+ strbuf_add_real_path(&worktree_path, repo_get_common_dir(repo));
strbuf_strip_suffix(&worktree_path, "/.git");
CALLOC_ARRAY(worktree, 1);
- worktree->repo = the_repository;
+ worktree->repo = repo;
worktree->id = xstrdup("/");
worktree->path = strbuf_detach(&worktree_path, NULL);
worktree->is_current = is_current_worktree(worktree);
@@ -112,7 +112,7 @@ static struct worktree *get_main_worktree(int skip_reading_head)
* This check is unnecessary if we're currently in the main worktree,
* as prior checks already consulted all configs of the current worktree.
*/
- (!worktree->is_current && is_main_worktree_bare(the_repository));
+ (!worktree->is_current && is_main_worktree_bare(repo));
if (!skip_reading_head)
add_head_info(worktree);
@@ -165,7 +165,7 @@ struct worktree *get_linked_worktree(const char *id,
* retrieving worktree metadata that could be used when the worktree is known
* to not be in a healthy state, e.g. when creating or repairing it.
*/
-static struct worktree **get_worktrees_internal(int skip_reading_head)
+static struct worktree **get_worktrees_internal(struct repository *repo, int skip_reading_head)
{
struct worktree **list = NULL;
struct strbuf path = STRBUF_INIT;
@@ -175,9 +175,9 @@ static struct worktree **get_worktrees_internal(int skip_reading_head)
ALLOC_ARRAY(list, alloc);
- list[counter++] = get_main_worktree(skip_reading_head);
+ list[counter++] = get_main_worktree(repo, skip_reading_head);
- strbuf_addf(&path, "%s/worktrees", repo_get_common_dir(the_repository));
+ strbuf_addf(&path, "%s/worktrees", repo_get_common_dir(repo));
dir = opendir(path.buf);
strbuf_release(&path);
if (dir) {
@@ -199,12 +199,15 @@ static struct worktree **get_worktrees_internal(int skip_reading_head)
struct worktree **get_worktrees(void)
{
- return get_worktrees_internal(0);
+ return get_worktrees_repo(the_repository);
+}
+struct worktree **get_worktrees_repo(struct repository *repo)
+{
+ return get_worktrees_internal(repo, 0);
}
-
struct worktree **get_worktrees_without_reading_head(void)
{
- return get_worktrees_internal(1);
+ return get_worktrees_internal(the_repository, 1);
}
char *get_worktree_git_dir(const struct worktree *wt)
@@ -289,7 +292,7 @@ const char *worktree_lock_reason(struct worktree *wt)
if (!wt->lock_reason_valid) {
struct strbuf path = STRBUF_INIT;
- strbuf_addstr(&path, worktree_git_path(the_repository, wt, "locked"));
+ strbuf_addstr(&path, worktree_git_path(wt, "locked"));
if (file_exists(path.buf)) {
struct strbuf lock_reason = STRBUF_INIT;
if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
@@ -690,7 +693,7 @@ static void repair_noop(int iserr UNUSED,
void repair_worktrees(worktree_repair_fn fn, void *cb_data, int use_relative_paths)
{
- struct worktree **worktrees = get_worktrees_internal(1);
+ struct worktree **worktrees = get_worktrees_internal(the_repository, 1);
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
if (!fn)
@@ -735,7 +738,7 @@ void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path
void repair_worktrees_after_gitdir_move(const char *old_path)
{
- struct worktree **worktrees = get_worktrees_internal(1);
+ struct worktree **worktrees = get_worktrees_internal(the_repository, 1);
struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
for (; *wt; wt++)
diff --git a/worktree.h b/worktree.h
index e4bcccdc0a..fc5f87b5b1 100644
--- a/worktree.h
+++ b/worktree.h
@@ -30,6 +30,13 @@ struct worktree {
*/
struct worktree **get_worktrees(void);
+/*
+ * Like `get_worktrees`, but it returns the worktrees for the given repository.
+ * This is useful for cases where local repository context is used rather than
+ * the_repository global.
+ */
+struct worktree **get_worktrees_repo(struct repository *repo);
+
/*
* Like `get_worktrees`, but does not read HEAD. Skip reading HEAD allows to
* get the worktree without worrying about failures pertaining to parsing
diff --git a/wt-status.c b/wt-status.c
index e12adb26b9..11aea61c81 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1624,7 +1624,7 @@ static char *get_branch(const struct worktree *wt, const char *path)
struct object_id oid;
const char *branch_name;
- if (strbuf_read_file(&sb, worktree_git_path(the_repository, wt, "%s", path), 0) <= 0)
+ if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
goto got_nothing;
while (sb.len && sb.buf[sb.len - 1] == '\n')
@@ -1723,18 +1723,18 @@ int wt_status_check_rebase(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) {
- if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) {
+ if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
+ if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
state->am_in_progress = 1;
- if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/patch"), &st) && !st.st_size)
+ if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
state->am_empty_patch = 1;
} else {
state->rebase_in_progress = 1;
state->branch = get_branch(wt, "rebase-apply/head-name");
state->onto = get_branch(wt, "rebase-apply/onto");
}
- } else if (!stat(worktree_git_path(the_repository, wt, "rebase-merge"), &st)) {
- if (!stat(worktree_git_path(the_repository, wt, "rebase-merge/interactive"), &st))
+ } else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
+ if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
state->rebase_interactive_in_progress = 1;
else
state->rebase_in_progress = 1;
@@ -1750,7 +1750,7 @@ int wt_status_check_bisect(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(the_repository, wt, "BISECT_LOG"), &st)) {
+ if (!stat(worktree_git_path(wt, "BISECT_LOG"), &st)) {
state->bisect_in_progress = 1;
state->bisecting_from = get_branch(wt, "BISECT_START");
return 1;
@@ -1795,18 +1795,19 @@ void wt_status_get_state(struct repository *r,
struct stat st;
struct object_id oid;
enum replay_action action;
+ struct worktree **worktrees = get_worktrees_repo(r);
if (!stat(git_path_merge_head(r), &st)) {
- wt_status_check_rebase(NULL, state);
+ wt_status_check_rebase(worktrees[0], state);
state->merge_in_progress = 1;
- } else if (wt_status_check_rebase(NULL, state)) {
+ } else if (wt_status_check_rebase(worktrees[0], 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(worktrees[0], 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 +1825,7 @@ 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_worktrees(worktrees);
}
static void wt_longstatus_print_state(struct wt_status *s)
--
2.53.0
next prev parent reply other threads:[~2026-02-13 12:06 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-13 11:59 [RFC][PATCH 0/2] worktree: change representation and usage of primary worktree Shreyansh Paliwal
2026-02-13 11:59 ` [RFC][PATCH 1/2] worktree: represent the primary worktree with '/' instead of NULL Shreyansh Paliwal
2026-02-13 21:35 ` Junio C Hamano
2026-02-14 9:54 ` Shreyansh Paliwal
2026-02-13 11:59 ` Shreyansh Paliwal [this message]
2026-02-13 22:29 ` [RFC][PATCH 2/2] worktree: stop passing NULL as primary worktree Junio C Hamano
2026-02-14 9:59 ` Shreyansh Paliwal
2026-02-14 14:30 ` Phillip Wood
2026-02-14 15:34 ` Junio C Hamano
2026-02-15 8:56 ` Shreyansh Paliwal
2026-02-16 16:18 ` Phillip Wood
2026-02-17 5:21 ` Junio C Hamano
2026-02-17 10:09 ` Shreyansh Paliwal
2026-02-16 16:18 ` [PATCH 0/2] worktree_git_path(): remove repository argument Phillip Wood
2026-02-16 16:18 ` [PATCH 1/2] wt-status: avoid passing NULL worktree Phillip Wood
2026-02-17 9:23 ` Phillip Wood
2026-02-17 10:18 ` Shreyansh Paliwal
2026-02-17 15:20 ` Phillip Wood
2026-02-17 16:38 ` Shreyansh Paliwal
2026-02-17 18:29 ` Junio C Hamano
2026-02-17 17:46 ` Karthik Nayak
2026-02-18 14:19 ` Phillip Wood
2026-02-17 18:47 ` Junio C Hamano
2026-02-18 14:18 ` Phillip Wood
2026-02-16 16:18 ` [PATCH 2/2] path: remove repository argument from worktree_git_path() Phillip Wood
2026-02-17 17:48 ` Karthik Nayak
2026-02-17 10:12 ` [PATCH 0/2] worktree_git_path(): remove repository argument Shreyansh Paliwal
2026-02-17 15:22 ` Phillip Wood
2026-02-17 16:45 ` Shreyansh Paliwal
2026-02-19 14:26 ` [PATCH v2 " Phillip Wood
2026-02-19 14:26 ` [PATCH v2 1/2] wt-status: avoid passing NULL worktree Phillip Wood
2026-02-19 19:30 ` Junio C Hamano
2026-02-19 20:37 ` Junio C Hamano
2026-02-25 16:39 ` Phillip Wood
2026-02-25 17:11 ` Junio C Hamano
2026-02-26 16:09 ` Phillip Wood
2026-02-26 16:15 ` Junio C Hamano
2026-02-19 14:26 ` [PATCH v2 2/2] path: remove repository argument from worktree_git_path() Phillip Wood
2026-02-19 19:34 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260213120529.15475-3-shreyanshpaliwalcmsmn@gmail.com \
--to=shreyanshpaliwalcmsmn@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=karthik.188@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox