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 <rappazzo@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Rappazzo committed
Oct 8, 2015 at 13:01 UTC
51934904425e55a190b05f0a7a3de40ea486f0e5
2 files changed
+130
-46
worktree.c
+108
-46
@@ -3,6 +3,17 @@
3
#include "strbuf.h"
4
#include "worktree.h"
5
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
+
17
/*
18
* read 'path_to_ref' into 'ref'. Also if is_detached is not NULL,
19
* 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)
49
return 0;
50
}
51
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)
56
{
43
- struct strbuf sb = STRBUF_INIT;
57
+ struct worktree *worktree = NULL;
58
struct strbuf path = STRBUF_INIT;
59
+ struct strbuf worktree_path = STRBUF_INIT;
60
struct strbuf gitdir = STRBUF_INIT;
46
- char *existing = NULL;
61
+ struct strbuf head_ref = STRBUF_INIT;
62
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
+ }
75
strbuf_release(&path);
58
- strbuf_release(&sb);
76
strbuf_release(&gitdir);
60
-
61
- return existing;
77
+ strbuf_release(&worktree_path);
78
+ strbuf_release(&head_ref);
79
+ return worktree;
80
}
81
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)
83
{
67
- struct strbuf sb = STRBUF_INIT;
84
+ struct worktree *worktree = NULL;
85
struct strbuf path = STRBUF_INIT;
86
+ struct strbuf worktree_path = STRBUF_INIT;
87
struct strbuf gitdir = STRBUF_INIT;
70
- char *existing = NULL;
88
+ struct strbuf head_ref = STRBUF_INIT;
89
90
if (!id)
91
die("Missing linked worktree name");
92
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 */
98
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
+
107
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
+ }
115
88
- existing = strbuf_detach(&gitdir, NULL);
116
done:
117
strbuf_release(&path);
91
- strbuf_release(&sb);
118
strbuf_release(&gitdir);
93
-
94
- return existing;
119
+ strbuf_release(&worktree_path);
120
+ strbuf_release(&head_ref);
121
+ return worktree;
122
}
123
97
-char *find_shared_symref(const char *symref, const char *target)
124
+struct worktree **get_worktrees(void)
125
{
126
+ struct worktree **list = NULL;
127
struct strbuf path = STRBUF_INIT;
128
DIR *dir;
129
struct dirent *d;
102
- char *existing;
130
+ int counter = 0, alloc = 2;
131
+
132
+ list = xmalloc(alloc * sizeof(struct worktree *));
133
104
- if ((existing = find_main_symref(symref, target)))
105
- return existing;
134
+ if ((list[counter] = get_main_worktree()))
135
+ counter++;
136
137
strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
138
dir = opendir(path.buf);
139
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;
145
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)) {
172
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
+ }
179
}
120
-done:
121
- closedir(dir);
180
+
181
+ strbuf_release(&path);
182
+ strbuf_release(&sb);
183
+ free_worktrees(worktrees);
184
185
return existing;
186
}
worktree.h
+22
@@ -1,6 +1,28 @@
1
#ifndef WORKTREE_H
2
#define WORKTREE_H
3
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
+
26
/*
27
* Check if a per-worktree symref points to a ref in the main worktree
28
* or any linked worktree, and return the path to the exising worktree