Skip to content

Commit dd0aa81

Browse files
committed
Merge branch 'pr/4228'
2 parents 82e929a + f0848dd commit dd0aa81

File tree

5 files changed

+192
-31
lines changed

5 files changed

+192
-31
lines changed

include/git2/worktree.h

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,27 @@ GIT_EXTERN(void) git_worktree_free(git_worktree *wt);
7474
*/
7575
GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
7676

77+
typedef struct git_worktree_add_options {
78+
unsigned int version;
79+
80+
int lock; /**< lock newly created worktree */
81+
} git_worktree_add_options;
82+
83+
#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
84+
#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0}
85+
86+
/**
87+
* Initializes a `git_worktree_add_options` with default vaules.
88+
* Equivalent to creating an instance with
89+
* GIT_WORKTREE_ADD_OPTIONS_INIT.
90+
*
91+
* @param opts the struct to initialize
92+
* @param version Verison of struct; pass `GIT_WORKTREE_ADD_OPTIONS_VERSION`
93+
* @return Zero on success; -1 on failure.
94+
*/
95+
int git_worktree_add_init_options(git_worktree_add_options *opts,
96+
unsigned int version);
97+
7798
/**
7899
* Add a new working tree
79100
*
@@ -85,9 +106,12 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
85106
* @param repo Repository to create working tree for
86107
* @param name Name of the working tree
87108
* @param path Path to create working tree at
109+
* @param opts Options to modify default behavior. May be NULL
88110
* @return 0 or an error code
89111
*/
90-
GIT_EXTERN(int) git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *path);
112+
GIT_EXTERN(int) git_worktree_add(git_worktree **out, git_repository *repo,
113+
const char *name, const char *path,
114+
const git_worktree_add_options *opts);
91115

92116
/**
93117
* Lock worktree if not already locked
@@ -137,23 +161,44 @@ typedef enum {
137161
GIT_WORKTREE_PRUNE_WORKING_TREE = 1u << 2,
138162
} git_worktree_prune_t;
139163

164+
typedef struct git_worktree_prune_options {
165+
unsigned int version;
166+
167+
uint32_t flags;
168+
} git_worktree_prune_options;
169+
170+
#define GIT_WORKTREE_PRUNE_OPTIONS_VERSION 1
171+
#define GIT_WORKTREE_PRUNE_OPTIONS_INIT {GIT_WORKTREE_PRUNE_OPTIONS_VERSION,0}
172+
173+
/**
174+
* Initializes a `git_worktree_prune_options` with default vaules.
175+
* Equivalent to creating an instance with
176+
* GIT_WORKTREE_PRUNE_OPTIONS_INIT.
177+
*
178+
* @param opts the struct to initialize
179+
* @param version Verison of struct; pass `GIT_WORKTREE_PRUNE_OPTIONS_VERSION`
180+
* @return Zero on success; -1 on failure.
181+
*/
182+
GIT_EXTERN(int) git_worktree_prune_init_options(
183+
git_worktree_prune_options *opts,
184+
unsigned int version);
185+
140186
/**
141-
* Is the worktree prunable with the given set of flags?
187+
* Is the worktree prunable with the given options?
142188
*
143189
* A worktree is not prunable in the following scenarios:
144190
*
145191
* - the worktree is linking to a valid on-disk worktree. The
146-
* GIT_WORKTREE_PRUNE_VALID flag will cause this check to be
147-
* ignored.
148-
* - the worktree is not valid but locked. The
149-
* GIT_WORKRTEE_PRUNE_LOCKED flag will cause this check to be
150-
* ignored.
192+
* `valid` member will cause this check to be ignored.
193+
* - the worktree is locked. The `locked` flag will cause this
194+
* check to be ignored.
151195
*
152196
* If the worktree is not valid and not locked or if the above
153197
* flags have been passed in, this function will return a
154198
* positive value.
155199
*/
156-
GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt, unsigned flags);
200+
GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt,
201+
git_worktree_prune_options *opts);
157202

158203
/**
159204
* Prune working tree
@@ -163,10 +208,12 @@ GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt, unsigned flags);
163208
* `git_worktree_is_prunable` succeeds.
164209
*
165210
* @param wt Worktree to prune
166-
* @param flags git_worktree_prune_t flags
211+
* @param opts Specifies which checks to override. See
212+
* `git_worktree_is_prunable`. May be NULL
167213
* @return 0 or an error code
168214
*/
169-
GIT_EXTERN(int) git_worktree_prune(git_worktree *wt, unsigned flags);
215+
GIT_EXTERN(int) git_worktree_prune(git_worktree *wt,
216+
git_worktree_prune_options *opts);
170217

171218
/** @} */
172219
GIT_END_DECL

src/worktree.c

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,15 +269,32 @@ int git_worktree_validate(const git_worktree *wt)
269269
return err;
270270
}
271271

272-
int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree)
272+
int git_worktree_add_init_options(git_worktree_add_options *opts,
273+
unsigned int version)
274+
{
275+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
276+
git_worktree_add_options, GIT_WORKTREE_ADD_OPTIONS_INIT);
277+
return 0;
278+
}
279+
280+
int git_worktree_add(git_worktree **out, git_repository *repo,
281+
const char *name, const char *worktree,
282+
const git_worktree_add_options *opts)
273283
{
274284
git_buf gitdir = GIT_BUF_INIT, wddir = GIT_BUF_INIT, buf = GIT_BUF_INIT;
275285
git_reference *ref = NULL, *head = NULL;
276286
git_commit *commit = NULL;
277287
git_repository *wt = NULL;
278288
git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT;
289+
git_worktree_add_options wtopts = GIT_WORKTREE_ADD_OPTIONS_INIT;
279290
int err;
280291

292+
GITERR_CHECK_VERSION(
293+
opts, GIT_WORKTREE_ADD_OPTIONS_VERSION, "git_worktree_add_options");
294+
295+
if (opts)
296+
memcpy(&wtopts, opts, sizeof(wtopts));
297+
281298
assert(out && repo && name && worktree);
282299

283300
*out = NULL;
@@ -301,6 +318,21 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
301318
if ((err = git_path_prettify_dir(&wddir, worktree, NULL)) < 0)
302319
goto out;
303320

321+
if (wtopts.lock) {
322+
int fd;
323+
324+
if ((err = git_buf_joinpath(&buf, gitdir.ptr, "locked")) < 0)
325+
goto out;
326+
327+
if ((fd = p_creat(buf.ptr, 0644)) < 0) {
328+
err = fd;
329+
goto out;
330+
}
331+
332+
p_close(fd);
333+
git_buf_clear(&buf);
334+
}
335+
304336
/* Create worktree .git file */
305337
if ((err = git_buf_printf(&buf, "gitdir: %s\n", gitdir.ptr)) < 0)
306338
goto out;
@@ -424,11 +456,29 @@ int git_worktree_is_locked(git_buf *reason, const git_worktree *wt)
424456
return ret;
425457
}
426458

427-
int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
459+
int git_worktree_prune_init_options(
460+
git_worktree_prune_options *opts,
461+
unsigned int version)
462+
{
463+
GIT_INIT_STRUCTURE_FROM_TEMPLATE(opts, version,
464+
git_worktree_prune_options, GIT_WORKTREE_PRUNE_OPTIONS_INIT);
465+
return 0;
466+
}
467+
468+
int git_worktree_is_prunable(git_worktree *wt,
469+
git_worktree_prune_options *opts)
428470
{
429471
git_buf reason = GIT_BUF_INIT;
472+
git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
473+
474+
GITERR_CHECK_VERSION(
475+
opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
476+
"git_worktree_prune_options");
477+
478+
if (opts)
479+
memcpy(&popts, opts, sizeof(popts));
430480

431-
if ((flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 &&
481+
if ((popts.flags & GIT_WORKTREE_PRUNE_LOCKED) == 0 &&
432482
git_worktree_is_locked(&reason, wt))
433483
{
434484
if (!reason.size)
@@ -439,7 +489,7 @@ int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
439489
return 0;
440490
}
441491

442-
if ((flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
492+
if ((popts.flags & GIT_WORKTREE_PRUNE_VALID) == 0 &&
443493
git_worktree_validate(wt) == 0)
444494
{
445495
giterr_set(GITERR_WORKTREE, "Not pruning valid working tree");
@@ -449,13 +499,22 @@ int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
449499
return 1;
450500
}
451501

452-
int git_worktree_prune(git_worktree *wt, unsigned flags)
502+
int git_worktree_prune(git_worktree *wt,
503+
git_worktree_prune_options *opts)
453504
{
505+
git_worktree_prune_options popts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
454506
git_buf path = GIT_BUF_INIT;
455507
char *wtpath;
456508
int err;
457509

458-
if (!git_worktree_is_prunable(wt, flags)) {
510+
GITERR_CHECK_VERSION(
511+
opts, GIT_WORKTREE_PRUNE_OPTIONS_VERSION,
512+
"git_worktree_prune_options");
513+
514+
if (opts)
515+
memcpy(&popts, opts, sizeof(popts));
516+
517+
if (!git_worktree_is_prunable(wt, &popts)) {
459518
err = -1;
460519
goto out;
461520
}
@@ -474,7 +533,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags)
474533

475534
/* Skip deletion of the actual working tree if it does
476535
* not exist or deletion was not requested */
477-
if ((flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 ||
536+
if ((popts.flags & GIT_WORKTREE_PRUNE_WORKING_TREE) == 0 ||
478537
!git_path_exists(wt->gitlink_path))
479538
{
480539
goto out;

tests/worktree/refs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ void test_worktree_refs__delete_fails_for_checked_out_branch(void)
118118

119119
void test_worktree_refs__delete_succeeds_after_pruning_worktree(void)
120120
{
121+
git_worktree_prune_options opts = GIT_WORKTREE_PRUNE_OPTIONS_INIT;
121122
git_reference *branch;
122123
git_worktree *worktree;
123124

125+
opts.flags = GIT_WORKTREE_PRUNE_VALID;
126+
124127
cl_git_pass(git_worktree_lookup(&worktree, fixture.repo, fixture.worktreename));
125-
cl_git_pass(git_worktree_prune(worktree, GIT_WORKTREE_PRUNE_VALID));
128+
cl_git_pass(git_worktree_prune(worktree, &opts));
126129
git_worktree_free(worktree);
127130

128131
cl_git_pass(git_branch_lookup(&branch, fixture.repo,

tests/worktree/submodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void test_worktree_submodule__resolve_relative_url(void)
7474
cl_git_pass(git_repository_open(&child.repo, WORKTREE_CHILD));
7575

7676
/* Create worktree of submodule repository */
77-
cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr));
77+
cl_git_pass(git_worktree_add(&wt, child.repo, "subdir", wt_path.ptr, NULL));
7878
cl_git_pass(git_repository_open_from_worktree(&repo, wt));
7979

8080
cl_git_pass(git_submodule_resolve_url(&sm_relative_path, repo,

0 commit comments

Comments
 (0)