67
rmdir(git_path("worktrees")); /* ignore failed removal */
68
}
69
70
-static int should_prune_worktree(const char *id, struct strbuf *reason)
70
+/*
71
+ * Return true if worktree entry should be pruned, along with the reason for
72
+ * pruning. Otherwise, return false and the worktree's path, or NULL if it
73
+ * cannot be determined. Caller is responsible for freeing returned path.
74
+ */
75
+static int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath)
76
{
77
struct stat st;
78
char *path;
80
size_t len;
81
ssize_t read_result;
82
83
+ *wtpath = NULL;
84
if (!is_directory(git_path("worktrees/%s", id))) {
85
strbuf_addstr(reason, _("not a valid directory"));
86
return 1;
126
}
127
path[len] = '\0';
128
if (!file_exists(path)) {
123
- free(path);
129
if (stat(git_path("worktrees/%s/index", id), &st) ||
130
st.st_mtime <= expire) {
131
strbuf_addstr(reason, _("gitdir file points to non-existent location"));
132
+ free(path);
133
return 1;
134
} else {
135
+ *wtpath = path;
136
return 0;
137
}
138
}
132
- free(path);
139
+ *wtpath = path;
140
return 0;
141
}
142
148
delete_git_dir(id);
149
}
150
151
+static int prune_cmp(const void *a, const void *b)
152
+{
153
+ const struct string_list_item *x = a;
154
+ const struct string_list_item *y = b;
155
+ int c;
156
+
157
+ if ((c = fspathcmp(x->string, y->string)))
158
+ return c;
159
+ /* paths same; sort by .git/worktrees/<id> */
160
+ return strcmp(x->util, y->util);
161
+}
162
+
163
+static void prune_dups(struct string_list *l)
164
+{
165
+ int i;
166
+
167
+ QSORT(l->items, l->nr, prune_cmp);
168
+ for (i = 1; i < l->nr; i++) {
169
+ if (!fspathcmp(l->items[i].string, l->items[i - 1].string))
170
+ prune_worktree(l->items[i].util, "duplicate entry");
171
+ }
172
+}
173
+
174
static void prune_worktrees(void)
175
{
176
struct strbuf reason = STRBUF_INIT;
177
+ struct string_list kept = STRING_LIST_INIT_NODUP;
178
DIR *dir = opendir(git_path("worktrees"));
179
struct dirent *d;
180
if (!dir)
181
return;
182
while ((d = readdir(dir)) != NULL) {
183
+ char *path;
184
if (is_dot_or_dotdot(d->d_name))
185
continue;
186
strbuf_reset(&reason);
155
- if (!should_prune_worktree(d->d_name, &reason))
156
- continue;
157
- prune_worktree(d->d_name, reason.buf);
187
+ if (should_prune_worktree(d->d_name, &reason, &path))
188
+ prune_worktree(d->d_name, reason.buf);
189
+ else if (path)
190
+ string_list_append(&kept, path)->util = xstrdup(d->d_name);
191
}
192
closedir(dir);
193
+
194
+ prune_dups(&kept);
195
+ string_list_clear(&kept, 1);
196
+
197
if (!show_only)
198
delete_worktrees_dir_if_empty();
199
strbuf_release(&reason);