In a later patch we want to move around the the git directory of
a submodule. Both submodules as well as worktrees are involved in
placing git directories at unusual places, so their functionality
may collide. To react appropriately to situations where worktrees
in submodules are in use, offer a new function to query the
worktrees for submodules.

Signed-off-by: Stefan Beller <sbel...@google.com>
---
 worktree.c | 40 ++++++++++++++++++++++++++++++----------
 worktree.h |  5 +++++
 2 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/worktree.c b/worktree.c
index f7869f8d60..fb1f72bbf3 100644
--- a/worktree.c
+++ b/worktree.c
@@ -72,7 +72,7 @@ static void add_head_info(struct strbuf *head_ref, struct 
worktree *worktree)
 /**
  * get the main worktree
  */
-static struct worktree *get_main_worktree(void)
+static struct worktree *get_main_worktree(const char *git_common_dir)
 {
        struct worktree *worktree = NULL;
        struct strbuf path = STRBUF_INIT;
@@ -81,12 +81,12 @@ static struct worktree *get_main_worktree(void)
        int is_bare = 0;
        int is_detached = 0;
 
-       strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
+       strbuf_add_absolute_path(&worktree_path, git_common_dir);
        is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
        if (is_bare)
                strbuf_strip_suffix(&worktree_path, "/.");
 
-       strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
+       strbuf_addf(&path, "%s/HEAD", git_common_dir);
 
        if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
                goto done;
@@ -109,7 +109,8 @@ static struct worktree *get_main_worktree(void)
        return worktree;
 }
 
-static struct worktree *get_linked_worktree(const char *id)
+static struct worktree *get_linked_worktree(const char *git_common_dir,
+                                           const char *id)
 {
        struct worktree *worktree = NULL;
        struct strbuf path = STRBUF_INIT;
@@ -120,7 +121,7 @@ static struct worktree *get_linked_worktree(const char *id)
        if (!id)
                die("Missing linked worktree name");
 
-       strbuf_git_common_path(&path, "worktrees/%s/gitdir", id);
+       strbuf_addf(&path, "%s/worktrees/%s/gitdir", git_common_dir, id);
        if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
                /* invalid gitdir file */
                goto done;
@@ -133,7 +134,7 @@ static struct worktree *get_linked_worktree(const char *id)
        }
 
        strbuf_reset(&path);
-       strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
+       strbuf_addf(&path, "%s/worktrees/%s/HEAD", git_common_dir, id);
 
        if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
                goto done;
@@ -173,7 +174,7 @@ static void mark_current_worktree(struct worktree 
**worktrees)
        free(git_dir);
 }
 
-struct worktree **get_worktrees(void)
+struct worktree **get_worktrees_internal(const char *git_common_dir)
 {
        struct worktree **list = NULL;
        struct strbuf path = STRBUF_INIT;
@@ -183,10 +184,10 @@ struct worktree **get_worktrees(void)
 
        list = xmalloc(alloc * sizeof(struct worktree *));
 
-       if ((list[counter] = get_main_worktree()))
+       if ((list[counter] = get_main_worktree(git_common_dir)))
                counter++;
 
-       strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
+       strbuf_addf(&path, "%s/worktrees", git_common_dir);
        dir = opendir(path.buf);
        strbuf_release(&path);
        if (dir) {
@@ -195,7 +196,7 @@ struct worktree **get_worktrees(void)
                        if (is_dot_or_dotdot(d->d_name))
                                continue;
 
-                       if ((linked = get_linked_worktree(d->d_name))) {
+                       if ((linked = get_linked_worktree(git_common_dir, 
d->d_name))) {
                                ALLOC_GROW(list, counter + 1, alloc);
                                list[counter++] = linked;
                        }
@@ -209,6 +210,25 @@ struct worktree **get_worktrees(void)
        return list;
 }
 
+struct worktree **get_worktrees(void)
+{
+       return get_worktrees_internal(get_git_common_dir());
+}
+
+struct worktree **get_submodule_worktrees(const char *path)
+{
+       const char *submodule_common_dir;
+       struct strbuf sb = STRBUF_INIT;
+       struct worktree **ret;
+       strbuf_addf(&sb, "%s/.git", path);
+       submodule_common_dir = resolve_gitdir(sb.buf);
+
+       ret = get_worktrees_internal(submodule_common_dir);
+
+       strbuf_release(&sb);
+       return ret;
+}
+
 const char *get_worktree_git_dir(const struct worktree *wt)
 {
        if (!wt)
diff --git a/worktree.h b/worktree.h
index 90e1311fa7..c93845516c 100644
--- a/worktree.h
+++ b/worktree.h
@@ -25,6 +25,11 @@ struct worktree {
  */
 extern struct worktree **get_worktrees(void);
 
+/*
+ * Get the worktrees of a submodule named by `path`.
+ */
+extern struct worktree **get_submodule_worktrees(const char *path);
+
 /*
  * Return git dir of the worktree. Note that the path may be relative.
  * If wt is NULL, git dir of current worktree is returned.
-- 
2.10.2.613.g22f2156

Reply via email to