Skip to content

Commit 5193490

Browse files
rappazzogitster
authored andcommitted
worktree: add a function to get worktree details
The worktree structure provided for an individual worktree includes the absolute path of the worktree. The fuction to get the worktree details is a refactor of the find main/linked symref functions. Signed-off-by: Michael Rappazzo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1ceb7f9 commit 5193490

File tree

2 files changed

+130
-46
lines changed

2 files changed

+130
-46
lines changed

worktree.c

Lines changed: 108 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
#include "strbuf.h"
44
#include "worktree.h"
55

6+
void free_worktrees(struct worktree **worktrees)
7+
{
8+
int i = 0;
9+
10+
for (i = 0; worktrees[i]; i++) {
11+
free(worktrees[i]->path);
12+
free(worktrees[i]);
13+
}
14+
free (worktrees);
15+
}
16+
617
/*
718
* read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
819
* set is_detached to 1 (0) if the ref is detatched (is not detached).
@@ -38,87 +49,138 @@ static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
3849
return 0;
3950
}
4051

41-
static char *find_main_symref(const char *symref, const char *branch)
52+
/**
53+
* get the main worktree
54+
*/
55+
static struct worktree *get_main_worktree(void)
4256
{
43-
struct strbuf sb = STRBUF_INIT;
57+
struct worktree *worktree = NULL;
4458
struct strbuf path = STRBUF_INIT;
59+
struct strbuf worktree_path = STRBUF_INIT;
4560
struct strbuf gitdir = STRBUF_INIT;
46-
char *existing = NULL;
61+
struct strbuf head_ref = STRBUF_INIT;
4762

48-
strbuf_addf(&path, "%s/%s", get_git_common_dir(), symref);
49-
if (parse_ref(path.buf, &sb, NULL) < 0)
50-
goto done;
51-
if (strcmp(sb.buf, branch))
52-
goto done;
53-
strbuf_addstr(&gitdir, get_git_common_dir());
54-
strbuf_strip_suffix(&gitdir, ".git");
55-
existing = strbuf_detach(&gitdir, NULL);
56-
done:
63+
strbuf_addf(&gitdir, "%s", absolute_path(get_git_common_dir()));
64+
strbuf_addbuf(&worktree_path, &gitdir);
65+
if (!strbuf_strip_suffix(&worktree_path, "/.git"))
66+
strbuf_strip_suffix(&worktree_path, "/.");
67+
68+
strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
69+
70+
if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
71+
worktree = xmalloc(sizeof(struct worktree));
72+
worktree->path = strbuf_detach(&worktree_path, NULL);
73+
worktree->git_dir = strbuf_detach(&gitdir, NULL);
74+
}
5775
strbuf_release(&path);
58-
strbuf_release(&sb);
5976
strbuf_release(&gitdir);
60-
61-
return existing;
77+
strbuf_release(&worktree_path);
78+
strbuf_release(&head_ref);
79+
return worktree;
6280
}
6381

64-
static char *find_linked_symref(const char *symref, const char *branch,
65-
const char *id)
82+
static struct worktree *get_linked_worktree(const char *id)
6683
{
67-
struct strbuf sb = STRBUF_INIT;
84+
struct worktree *worktree = NULL;
6885
struct strbuf path = STRBUF_INIT;
86+
struct strbuf worktree_path = STRBUF_INIT;
6987
struct strbuf gitdir = STRBUF_INIT;
70-
char *existing = NULL;
88+
struct strbuf head_ref = STRBUF_INIT;
7189

7290
if (!id)
7391
die("Missing linked worktree name");
7492

75-
strbuf_addf(&path, "%s/worktrees/%s/%s", get_git_common_dir(), id, symref);
76-
77-
if (parse_ref(path.buf, &sb, NULL) < 0)
78-
goto done;
79-
if (strcmp(sb.buf, branch))
93+
strbuf_addf(&gitdir, "%s/worktrees/%s",
94+
absolute_path(get_git_common_dir()), id);
95+
strbuf_addf(&path, "%s/gitdir", gitdir.buf);
96+
if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
97+
/* invalid gitdir file */
8098
goto done;
99+
100+
strbuf_rtrim(&worktree_path);
101+
if (!strbuf_strip_suffix(&worktree_path, "/.git")) {
102+
strbuf_reset(&worktree_path);
103+
strbuf_addstr(&worktree_path, absolute_path("."));
104+
strbuf_strip_suffix(&worktree_path, "/.");
105+
}
106+
81107
strbuf_reset(&path);
82-
strbuf_addf(&path, "%s/worktrees/%s/gitdir", get_git_common_dir(), id);
83-
if (strbuf_read_file(&gitdir, path.buf, 0) <= 0)
84-
goto done;
85-
strbuf_rtrim(&gitdir);
86-
strbuf_strip_suffix(&gitdir, ".git");
108+
strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
109+
110+
if (parse_ref(path.buf, &head_ref, NULL) >= 0) {
111+
worktree = xmalloc(sizeof(struct worktree));
112+
worktree->path = strbuf_detach(&worktree_path, NULL);
113+
worktree->git_dir = strbuf_detach(&gitdir, NULL);
114+
}
87115

88-
existing = strbuf_detach(&gitdir, NULL);
89116
done:
90117
strbuf_release(&path);
91-
strbuf_release(&sb);
92118
strbuf_release(&gitdir);
93-
94-
return existing;
119+
strbuf_release(&worktree_path);
120+
strbuf_release(&head_ref);
121+
return worktree;
95122
}
96123

97-
char *find_shared_symref(const char *symref, const char *target)
124+
struct worktree **get_worktrees(void)
98125
{
126+
struct worktree **list = NULL;
99127
struct strbuf path = STRBUF_INIT;
100128
DIR *dir;
101129
struct dirent *d;
102-
char *existing;
130+
int counter = 0, alloc = 2;
131+
132+
list = xmalloc(alloc * sizeof(struct worktree *));
103133

104-
if ((existing = find_main_symref(symref, target)))
105-
return existing;
134+
if ((list[counter] = get_main_worktree()))
135+
counter++;
106136

107137
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
108138
dir = opendir(path.buf);
109139
strbuf_release(&path);
110-
if (!dir)
111-
return NULL;
140+
if (dir) {
141+
while ((d = readdir(dir)) != NULL) {
142+
struct worktree *linked = NULL;
143+
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
144+
continue;
112145

113-
while ((d = readdir(dir)) != NULL) {
114-
if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
146+
if ((linked = get_linked_worktree(d->d_name))) {
147+
ALLOC_GROW(list, counter + 1, alloc);
148+
list[counter++] = linked;
149+
}
150+
}
151+
closedir(dir);
152+
}
153+
ALLOC_GROW(list, counter + 1, alloc);
154+
list[counter] = NULL;
155+
return list;
156+
}
157+
158+
char *find_shared_symref(const char *symref, const char *target)
159+
{
160+
char *existing = NULL;
161+
struct strbuf path = STRBUF_INIT;
162+
struct strbuf sb = STRBUF_INIT;
163+
struct worktree **worktrees = get_worktrees();
164+
int i = 0;
165+
166+
for (i = 0; worktrees[i]; i++) {
167+
strbuf_reset(&path);
168+
strbuf_reset(&sb);
169+
strbuf_addf(&path, "%s/%s", worktrees[i]->git_dir, symref);
170+
171+
if (parse_ref(path.buf, &sb, NULL)) {
115172
continue;
116-
existing = find_linked_symref(symref, target, d->d_name);
117-
if (existing)
118-
goto done;
173+
}
174+
175+
if (!strcmp(sb.buf, target)) {
176+
existing = xstrdup(worktrees[i]->path);
177+
break;
178+
}
119179
}
120-
done:
121-
closedir(dir);
180+
181+
strbuf_release(&path);
182+
strbuf_release(&sb);
183+
free_worktrees(worktrees);
122184

123185
return existing;
124186
}

worktree.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
#ifndef WORKTREE_H
22
#define WORKTREE_H
33

4+
struct worktree {
5+
char *path;
6+
char *git_dir;
7+
};
8+
9+
/* Functions for acting on the information about worktrees. */
10+
11+
/*
12+
* Get the worktrees. The primary worktree will always be the first returned,
13+
* and linked worktrees will be pointed to by 'next' in each subsequent
14+
* worktree. No specific ordering is done on the linked worktrees.
15+
*
16+
* The caller is responsible for freeing the memory from the returned
17+
* worktree(s).
18+
*/
19+
extern struct worktree **get_worktrees(void);
20+
21+
/*
22+
* Free up the memory for worktree(s)
23+
*/
24+
extern void free_worktrees(struct worktree **);
25+
426
/*
527
* Check if a per-worktree symref points to a ref in the main worktree
628
* or any linked worktree, and return the path to the exising worktree

0 commit comments

Comments
 (0)