]> git.proxmox.com Git - libgit2.git/blame - src/worktree.c
Bump debhelper compatibility level to 13
[libgit2.git] / src / worktree.c
CommitLineData
45f2b7a4
PS
1/*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
eae0bfdc 8#include "worktree.h"
dea7488e
PS
9
10#include "git2/branch.h"
11#include "git2/commit.h"
45f2b7a4
PS
12#include "git2/worktree.h"
13
45f2b7a4
PS
14#include "repository.h"
15
3e9c5d8a 16static bool is_worktree_dir(const char *dir)
45f2b7a4 17{
3e9c5d8a
PS
18 git_buf buf = GIT_BUF_INIT;
19 int error;
20
21 if (git_buf_sets(&buf, dir) < 0)
22 return -1;
23
24 error = git_path_contains_file(&buf, "commondir")
25 && git_path_contains_file(&buf, "gitdir")
26 && git_path_contains_file(&buf, "HEAD");
27
ac3d33df 28 git_buf_dispose(&buf);
3e9c5d8a 29 return error;
45f2b7a4
PS
30}
31
32int git_worktree_list(git_strarray *wts, git_repository *repo)
33{
34 git_vector worktrees = GIT_VECTOR_INIT;
35 git_buf path = GIT_BUF_INIT;
36 char *worktree;
22a2d3d5 37 size_t i, len;
45f2b7a4
PS
38 int error;
39
c25aa7cd
PP
40 GIT_ASSERT_ARG(wts);
41 GIT_ASSERT_ARG(repo);
45f2b7a4
PS
42
43 wts->count = 0;
44 wts->strings = NULL;
45
c25aa7cd 46 if ((error = git_buf_joinpath(&path, repo->commondir, "worktrees/")) < 0)
45f2b7a4
PS
47 goto exit;
48 if (!git_path_exists(path.ptr) || git_path_is_empty_dir(path.ptr))
49 goto exit;
50 if ((error = git_path_dirload(&worktrees, path.ptr, path.size, 0x0)) < 0)
51 goto exit;
52
53 len = path.size;
54
55 git_vector_foreach(&worktrees, i, worktree) {
56 git_buf_truncate(&path, len);
57 git_buf_puts(&path, worktree);
58
3e9c5d8a 59 if (!is_worktree_dir(path.ptr)) {
45f2b7a4
PS
60 git_vector_remove(&worktrees, i);
61 git__free(worktree);
62 }
63 }
64
65 wts->strings = (char **)git_vector_detach(&wts->count, NULL, &worktrees);
66
67exit:
ac3d33df 68 git_buf_dispose(&path);
45f2b7a4
PS
69
70 return error;
71}
d3bc09e8 72
39abd3ad 73char *git_worktree__read_link(const char *base, const char *file)
d3bc09e8
PS
74{
75 git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT;
76
c25aa7cd
PP
77 GIT_ASSERT_ARG_WITH_RETVAL(base, NULL);
78 GIT_ASSERT_ARG_WITH_RETVAL(file, NULL);
d3bc09e8
PS
79
80 if (git_buf_joinpath(&path, base, file) < 0)
81 goto err;
82 if (git_futils_readbuffer(&buf, path.ptr) < 0)
83 goto err;
ac3d33df 84 git_buf_dispose(&path);
d3bc09e8
PS
85
86 git_buf_rtrim(&buf);
87
88 if (!git_path_is_relative(buf.ptr))
89 return git_buf_detach(&buf);
90
91 if (git_buf_sets(&path, base) < 0)
92 goto err;
93 if (git_path_apply_relative(&path, buf.ptr) < 0)
94 goto err;
ac3d33df 95 git_buf_dispose(&buf);
d3bc09e8
PS
96
97 return git_buf_detach(&path);
98
99err:
ac3d33df
JK
100 git_buf_dispose(&buf);
101 git_buf_dispose(&path);
d3bc09e8
PS
102
103 return NULL;
104}
105
dea7488e
PS
106static int write_wtfile(const char *base, const char *file, const git_buf *buf)
107{
108 git_buf path = GIT_BUF_INIT;
109 int err;
110
c25aa7cd
PP
111 GIT_ASSERT_ARG(base);
112 GIT_ASSERT_ARG(file);
113 GIT_ASSERT_ARG(buf);
dea7488e
PS
114
115 if ((err = git_buf_joinpath(&path, base, file)) < 0)
116 goto out;
117
118 if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
119 goto out;
120
121out:
ac3d33df 122 git_buf_dispose(&path);
dea7488e
PS
123
124 return err;
125}
126
dfc98706 127static int open_worktree_dir(git_worktree **out, const char *parent, const char *dir, const char *name)
d3bc09e8 128{
dfc98706 129 git_buf gitdir = GIT_BUF_INIT;
d3bc09e8 130 git_worktree *wt = NULL;
dfc98706 131 int error = 0;
d3bc09e8 132
dfc98706 133 if (!is_worktree_dir(dir)) {
d3bc09e8
PS
134 error = -1;
135 goto out;
136 }
137
c25aa7cd
PP
138 if ((error = git_path_validate_workdir(NULL, dir)) < 0)
139 goto out;
140
4b3ec53c 141 if ((wt = git__calloc(1, sizeof(*wt))) == NULL) {
d3bc09e8
PS
142 error = -1;
143 goto out;
144 }
145
22a2d3d5
UG
146 if ((wt->name = git__strdup(name)) == NULL ||
147 (wt->commondir_path = git_worktree__read_link(dir, "commondir")) == NULL ||
148 (wt->gitlink_path = git_worktree__read_link(dir, "gitdir")) == NULL ||
149 (parent && (wt->parent_path = git__strdup(parent)) == NULL) ||
150 (wt->worktree_path = git_path_dirname(wt->gitlink_path)) == NULL) {
d3bc09e8
PS
151 error = -1;
152 goto out;
153 }
dfc98706
PS
154
155 if ((error = git_path_prettify_dir(&gitdir, dir, NULL)) < 0)
156 goto out;
157 wt->gitdir_path = git_buf_detach(&gitdir);
158
22a2d3d5
UG
159 if ((error = git_worktree_is_locked(NULL, wt)) < 0)
160 goto out;
161 wt->locked = !!error;
162 error = 0;
d3bc09e8 163
dfc98706
PS
164 *out = wt;
165
166out:
167 if (error)
168 git_worktree_free(wt);
ac3d33df 169 git_buf_dispose(&gitdir);
dfc98706
PS
170
171 return error;
172}
173
174int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name)
175{
176 git_buf path = GIT_BUF_INIT;
177 git_worktree *wt = NULL;
178 int error;
179
c25aa7cd
PP
180 GIT_ASSERT_ARG(repo);
181 GIT_ASSERT_ARG(name);
dfc98706
PS
182
183 *out = NULL;
184
c25aa7cd 185 if ((error = git_buf_join3(&path, '/', repo->commondir, "worktrees", name)) < 0)
dfc98706
PS
186 goto out;
187
20a368e2 188 if ((error = (open_worktree_dir(out, git_repository_workdir(repo), path.ptr, name))) < 0)
dfc98706 189 goto out;
d3bc09e8
PS
190
191out:
ac3d33df 192 git_buf_dispose(&path);
d3bc09e8
PS
193
194 if (error)
195 git_worktree_free(wt);
196
197 return error;
198}
199
3017ba94
PS
200int git_worktree_open_from_repository(git_worktree **out, git_repository *repo)
201{
202 git_buf parent = GIT_BUF_INIT;
203 const char *gitdir, *commondir;
204 char *name = NULL;
205 int error = 0;
206
207 if (!git_repository_is_worktree(repo)) {
ac3d33df 208 git_error_set(GIT_ERROR_WORKTREE, "cannot open worktree of a non-worktree repo");
3017ba94
PS
209 error = -1;
210 goto out;
211 }
212
213 gitdir = git_repository_path(repo);
214 commondir = git_repository_commondir(repo);
215
20a368e2 216 if ((error = git_path_prettify_dir(&parent, "..", commondir)) < 0)
3017ba94
PS
217 goto out;
218
219 /* The name is defined by the last component in '.git/worktree/%s' */
220 name = git_path_basename(gitdir);
221
222 if ((error = open_worktree_dir(out, parent.ptr, gitdir, name)) < 0)
223 goto out;
224
225out:
9be4c303 226 git__free(name);
ac3d33df 227 git_buf_dispose(&parent);
3017ba94
PS
228
229 return error;
230}
231
d3bc09e8
PS
232void git_worktree_free(git_worktree *wt)
233{
234 if (!wt)
235 return;
236
237 git__free(wt->commondir_path);
ac3d33df 238 git__free(wt->worktree_path);
d3bc09e8
PS
239 git__free(wt->gitlink_path);
240 git__free(wt->gitdir_path);
241 git__free(wt->parent_path);
242 git__free(wt->name);
243 git__free(wt);
244}
372dc9ff
PS
245
246int git_worktree_validate(const git_worktree *wt)
247{
c25aa7cd 248 GIT_ASSERT_ARG(wt);
372dc9ff 249
ac3d33df
JK
250 if (!is_worktree_dir(wt->gitdir_path)) {
251 git_error_set(GIT_ERROR_WORKTREE,
22a2d3d5 252 "worktree gitdir ('%s') is not valid",
372dc9ff 253 wt->gitlink_path);
ac3d33df 254 return GIT_ERROR;
372dc9ff
PS
255 }
256
ac3d33df
JK
257 if (wt->parent_path && !git_path_exists(wt->parent_path)) {
258 git_error_set(GIT_ERROR_WORKTREE,
22a2d3d5 259 "worktree parent directory ('%s') does not exist ",
372dc9ff 260 wt->parent_path);
ac3d33df 261 return GIT_ERROR;
372dc9ff
PS
262 }
263
264 if (!git_path_exists(wt->commondir_path)) {
ac3d33df 265 git_error_set(GIT_ERROR_WORKTREE,
22a2d3d5 266 "worktree common directory ('%s') does not exist ",
372dc9ff 267 wt->commondir_path);
ac3d33df 268 return GIT_ERROR;
372dc9ff
PS
269 }
270
c25aa7cd
PP
271 if (!git_path_exists(wt->worktree_path)) {
272 git_error_set(GIT_ERROR_WORKTREE,
273 "worktree directory '%s' does not exist",
274 wt->worktree_path);
275 return GIT_ERROR;
276 }
277
ac3d33df 278 return 0;
372dc9ff 279}
dea7488e 280
22a2d3d5 281int git_worktree_add_options_init(git_worktree_add_options *opts,
a7aa73a5
PS
282 unsigned int version)
283{
284 GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
285 git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT);
286 return 0;
287}
288
22a2d3d5
UG
289#ifndef GIT_DEPRECATE_HARD
290int git_worktree_add_init_options(git_worktree_add_options *opts,
291 unsigned int version)
292{
293 return git_worktree_add_options_init(opts, version);
294}
295#endif
296
a7aa73a5
PS
297int git_worktree_add(git_worktree **out, git_repository *repo,
298 const char *name, const char *worktree,
299 const git_worktree_add_options *opts)
dea7488e 300{
8f154be3 301 git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT;
dea7488e
PS
302 git_reference *ref = NULL, *head = NULL;
303 git_commit *commit = NULL;
304 git_repository *wt = NULL;
305 git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT;
a7aa73a5 306 git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT;
dea7488e
PS
307 int err;
308
ac3d33df 309 GIT_ERROR_CHECK_VERSION(
a7aa73a5
PS
310 opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options");
311
312 if (opts)
313 memcpy(&wtopts, opts, sizeof(wtopts));
314
c25aa7cd
PP
315 GIT_ASSERT_ARG(out);
316 GIT_ASSERT_ARG(repo);
317 GIT_ASSERT_ARG(name);
318 GIT_ASSERT_ARG(worktree);
dea7488e
PS
319
320 *out = NULL;
321
22a2d3d5
UG
322 if (wtopts.ref) {
323 if (!git_reference_is_branch(wtopts.ref)) {
324 git_error_set(GIT_ERROR_WORKTREE, "reference is not a branch");
325 err = -1;
326 goto out;
327 }
328
329 if (git_branch_is_checked_out(wtopts.ref)) {
330 git_error_set(GIT_ERROR_WORKTREE, "reference is already checked out");
331 err = -1;
332 goto out;
333 }
334 }
335
7cf7a407
PS
336 /* Create gitdir directory ".git/worktrees/<name>" */
337 if ((err = git_buf_joinpath(&gitdir, repo->commondir, "worktrees")) < 0)
dea7488e 338 goto out;
7cf7a407
PS
339 if (!git_path_exists(gitdir.ptr))
340 if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
dea7488e 341 goto out;
7cf7a407 342 if ((err = git_buf_joinpath(&gitdir, gitdir.ptr, name)) < 0)
dea7488e 343 goto out;
7cf7a407 344 if ((err = git_futils_mkdir(gitdir.ptr, 0755, GIT_MKDIR_EXCL)) < 0)
dea7488e 345 goto out;
8f154be3
PS
346 if ((err = git_path_prettify_dir(&gitdir, gitdir.ptr, NULL)) < 0)
347 goto out;
dea7488e
PS
348
349 /* Create worktree work dir */
350 if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0)
351 goto out;
8f154be3
PS
352 if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
353 goto out;
dea7488e 354
8264a30f
PS
355 if (wtopts.lock) {
356 int fd;
357
358 if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0)
359 goto out;
360
361 if ((fd = p_creat(buf.ptr, 0644)) < 0) {
362 err = fd;
363 goto out;
364 }
365
366 p_close(fd);
367 git_buf_clear(&buf);
368 }
369
dea7488e 370 /* Create worktree .git file */
7cf7a407 371 if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
dea7488e 372 goto out;
8f154be3 373 if ((err = write_wtfile(wddir.ptr, ".git", &buf)) < 0)
dea7488e
PS
374 goto out;
375
7cf7a407 376 /* Create gitdir files */
8f154be3 377 if ((err = git_path_prettify_dir(&buf, repo->commondir, NULL) < 0)
dea7488e 378 || (err = git_buf_putc(&buf, '\n')) < 0
7cf7a407 379 || (err = write_wtfile(gitdir.ptr, "commondir", &buf)) < 0)
dea7488e 380 goto out;
8f154be3 381 if ((err = git_buf_joinpath(&buf, wddir.ptr, ".git")) < 0
dea7488e 382 || (err = git_buf_putc(&buf, '\n')) < 0
7cf7a407 383 || (err = write_wtfile(gitdir.ptr, "gitdir", &buf)) < 0)
dea7488e
PS
384 goto out;
385
ac3d33df
JK
386 /* Set up worktree reference */
387 if (wtopts.ref) {
ac3d33df
JK
388 if ((err = git_reference_dup(&ref, wtopts.ref)) < 0)
389 goto out;
390 } else {
391 if ((err = git_repository_head(&head, repo)) < 0)
392 goto out;
393 if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0)
394 goto out;
395 if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0)
396 goto out;
397 }
dea7488e
PS
398
399 /* Set worktree's HEAD */
7cf7a407 400 if ((err = git_repository_create_head(gitdir.ptr, git_reference_name(ref))) < 0)
dea7488e 401 goto out;
8f154be3 402 if ((err = git_repository_open(&wt, wddir.ptr)) < 0)
dea7488e
PS
403 goto out;
404
405 /* Checkout worktree's HEAD */
406 coopts.checkout_strategy = GIT_CHECKOUT_FORCE;
407 if ((err = git_checkout_head(wt, &coopts)) < 0)
408 goto out;
409
410 /* Load result */
411 if ((err = git_worktree_lookup(out, repo, name)) < 0)
412 goto out;
413
414out:
ac3d33df
JK
415 git_buf_dispose(&gitdir);
416 git_buf_dispose(&wddir);
417 git_buf_dispose(&buf);
dea7488e
PS
418 git_reference_free(ref);
419 git_reference_free(head);
420 git_commit_free(commit);
421 git_repository_free(wt);
422
423 return err;
424}
2a503485 425
eae0bfdc 426int git_worktree_lock(git_worktree *wt, const char *reason)
2a503485
PS
427{
428 git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT;
22a2d3d5 429 int error;
2a503485 430
c25aa7cd 431 GIT_ASSERT_ARG(wt);
2a503485 432
22a2d3d5
UG
433 if ((error = git_worktree_is_locked(NULL, wt)) < 0)
434 goto out;
435 if (error) {
436 error = GIT_ELOCKED;
2a503485 437 goto out;
22a2d3d5 438 }
2a503485 439
22a2d3d5 440 if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
2a503485
PS
441 goto out;
442
eae0bfdc
PP
443 if (reason)
444 git_buf_attach_notowned(&buf, reason, strlen(reason));
2a503485 445
22a2d3d5 446 if ((error = git_futils_writebuffer(&buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0)
2a503485
PS
447 goto out;
448
449 wt->locked = 1;
450
451out:
ac3d33df 452 git_buf_dispose(&path);
2a503485 453
22a2d3d5 454 return error;
2a503485
PS
455}
456
457int git_worktree_unlock(git_worktree *wt)
458{
459 git_buf path = GIT_BUF_INIT;
22a2d3d5 460 int error;
2a503485 461
c25aa7cd 462 GIT_ASSERT_ARG(wt);
2a503485 463
22a2d3d5
UG
464 if ((error = git_worktree_is_locked(NULL, wt)) < 0)
465 return error;
466 if (!error)
6c7cee42 467 return 1;
2a503485
PS
468
469 if (git_buf_joinpath(&path, wt->gitdir_path, "locked") < 0)
470 return -1;
471
472 if (p_unlink(path.ptr) != 0) {
ac3d33df 473 git_buf_dispose(&path);
2a503485
PS
474 return -1;
475 }
476
477 wt->locked = 0;
478
ac3d33df 479 git_buf_dispose(&path);
2a503485
PS
480
481 return 0;
482}
483
484int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
485{
486 git_buf path = GIT_BUF_INIT;
22a2d3d5 487 int error, locked;
2a503485 488
c25aa7cd 489 GIT_ASSERT_ARG(wt);
2a503485
PS
490
491 if (reason)
492 git_buf_clear(reason);
493
22a2d3d5
UG
494 if ((error = git_buf_joinpath(&path, wt->gitdir_path, "locked")) < 0)
495 goto out;
496 locked = git_path_exists(path.ptr);
497 if (locked && reason &&
498 (error = git_futils_readbuffer(reason, path.ptr)) < 0)
2a503485 499 goto out;
2a503485 500
22a2d3d5 501 error = locked;
2a503485 502out:
ac3d33df 503 git_buf_dispose(&path);
2a503485 504
22a2d3d5 505 return error;
2a503485 506}
f0cfc341 507
ac3d33df
JK
508const char *git_worktree_name(const git_worktree *wt)
509{
c25aa7cd 510 GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL);
ac3d33df
JK
511 return wt->name;
512}
513
514const char *git_worktree_path(const git_worktree *wt)
515{
c25aa7cd 516 GIT_ASSERT_ARG_WITH_RETVAL(wt, NULL);
ac3d33df
JK
517 return wt->worktree_path;
518}
519
22a2d3d5 520int git_worktree_prune_options_init(
883eeb5f
PS
521 git_worktree_prune_options *opts,
522 unsigned int version)
523{
524 GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
525 git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT);
526 return 0;
527}
528
22a2d3d5
UG
529#ifndef GIT_DEPRECATE_HARD
530int git_worktree_prune_init_options(git_worktree_prune_options *opts,
531 unsigned int version)
532{
533 return git_worktree_prune_options_init(opts, version);
534}
535#endif
536
883eeb5f
PS
537int git_worktree_is_prunable(git_worktree *wt,
538 git_worktree_prune_options *opts)
f0cfc341 539{
883eeb5f
PS
540 git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
541
ac3d33df 542 GIT_ERROR_CHECK_VERSION(
883eeb5f
PS
543 opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
544 "git_worktree_prune_options");
545
546 if (opts)
547 memcpy(&popts, opts, sizeof(popts));
f0cfc341 548
22a2d3d5
UG
549 if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0) {
550 git_buf reason = GIT_BUF_INIT;
551 int error;
f0cfc341 552
22a2d3d5
UG
553 if ((error = git_worktree_is_locked(&reason, wt)) < 0)
554 return error;
555
556 if (error) {
557 if (!reason.size)
558 git_buf_attach_notowned(&reason, "no reason given", 15);
559 git_error_set(GIT_ERROR_WORKTREE, "not pruning locked working tree: '%s'", reason.ptr);
560 git_buf_dispose(&reason);
561 return 0;
562 }
f0cfc341
PS
563 }
564
883eeb5f 565 if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
22a2d3d5
UG
566 git_worktree_validate(wt) == 0) {
567 git_error_set(GIT_ERROR_WORKTREE, "not pruning valid working tree");
1ba242c9
PS
568 return 0;
569 }
570
571 return 1;
572}
573
883eeb5f
PS
574int git_worktree_prune(git_worktree *wt,
575 git_worktree_prune_options *opts)
1ba242c9 576{
883eeb5f 577 git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
1ba242c9
PS
578 git_buf path = GIT_BUF_INIT;
579 char *wtpath;
580 int err;
581
ac3d33df 582 GIT_ERROR_CHECK_VERSION(
883eeb5f
PS
583 opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
584 "git_worktree_prune_options");
585
586 if (opts)
587 memcpy(&popts, opts, sizeof(popts));
588
589 if (!git_worktree_is_prunable(wt, &popts)) {
f0cfc341
PS
590 err = -1;
591 goto out;
592 }
593
594 /* Delete gitdir in parent repository */
c25aa7cd 595 if ((err = git_buf_join3(&path, '/', wt->commondir_path, "worktrees", wt->name)) < 0)
f0cfc341
PS
596 goto out;
597 if (!git_path_exists(path.ptr))
598 {
22a2d3d5 599 git_error_set(GIT_ERROR_WORKTREE, "worktree gitdir '%s' does not exist", path.ptr);
f0cfc341
PS
600 err = -1;
601 goto out;
602 }
603 if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
604 goto out;
605
606 /* Skip deletion of the actual working tree if it does
607 * not exist or deletion was not requested */
883eeb5f 608 if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 ||
f0cfc341
PS
609 !git_path_exists(wt->gitlink_path))
610 {
611 goto out;
612 }
613
614 if ((wtpath = git_path_dirname(wt->gitlink_path)) == NULL)
615 goto out;
616 git_buf_attach(&path, wtpath, 0);
617 if (!git_path_exists(path.ptr))
618 {
22a2d3d5 619 git_error_set(GIT_ERROR_WORKTREE, "working tree '%s' does not exist", path.ptr);
f0cfc341
PS
620 err = -1;
621 goto out;
622 }
623 if ((err = git_futils_rmdir_r(path.ptr, NULL, GIT_RMDIR_REMOVE_FILES)) < 0)
624 goto out;
625
626out:
ac3d33df 627 git_buf_dispose(&path);
f0cfc341
PS
628
629 return err;
630}