Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
dd0aa811
Commit
dd0aa811
authored
Jun 04, 2017
by
Edward Thomson
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'pr/4228'
parents
82e929a8
f0848dd7
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
192 additions
and
31 deletions
+192
-31
include/git2/worktree.h
+57
-10
src/worktree.c
+66
-7
tests/worktree/refs.c
+4
-1
tests/worktree/submodule.c
+1
-1
tests/worktree/worktree.c
+64
-12
No files found.
include/git2/worktree.h
View file @
dd0aa811
...
...
@@ -74,6 +74,27 @@ GIT_EXTERN(void) git_worktree_free(git_worktree *wt);
*/
GIT_EXTERN
(
int
)
git_worktree_validate
(
const
git_worktree
*
wt
);
typedef
struct
git_worktree_add_options
{
unsigned
int
version
;
int
lock
;
/**< lock newly created worktree */
}
git_worktree_add_options
;
#define GIT_WORKTREE_ADD_OPTIONS_VERSION 1
#define GIT_WORKTREE_ADD_OPTIONS_INIT {GIT_WORKTREE_ADD_OPTIONS_VERSION,0}
/**
* Initializes a `git_worktree_add_options` with default vaules.
* Equivalent to creating an instance with
* GIT_WORKTREE_ADD_OPTIONS_INIT.
*
* @param opts the struct to initialize
* @param version Verison of struct; pass `GIT_WORKTREE_ADD_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
int
git_worktree_add_init_options
(
git_worktree_add_options
*
opts
,
unsigned
int
version
);
/**
* Add a new working tree
*
...
...
@@ -85,9 +106,12 @@ GIT_EXTERN(int) git_worktree_validate(const git_worktree *wt);
* @param repo Repository to create working tree for
* @param name Name of the working tree
* @param path Path to create working tree at
* @param opts Options to modify default behavior. May be NULL
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_worktree_add
(
git_worktree
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
path
);
GIT_EXTERN
(
int
)
git_worktree_add
(
git_worktree
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
path
,
const
git_worktree_add_options
*
opts
);
/**
* Lock worktree if not already locked
...
...
@@ -137,23 +161,44 @@ typedef enum {
GIT_WORKTREE_PRUNE_WORKING_TREE
=
1u
<<
2
,
}
git_worktree_prune_t
;
typedef
struct
git_worktree_prune_options
{
unsigned
int
version
;
uint32_t
flags
;
}
git_worktree_prune_options
;
#define GIT_WORKTREE_PRUNE_OPTIONS_VERSION 1
#define GIT_WORKTREE_PRUNE_OPTIONS_INIT {GIT_WORKTREE_PRUNE_OPTIONS_VERSION,0}
/**
* Initializes a `git_worktree_prune_options` with default vaules.
* Equivalent to creating an instance with
* GIT_WORKTREE_PRUNE_OPTIONS_INIT.
*
* @param opts the struct to initialize
* @param version Verison of struct; pass `GIT_WORKTREE_PRUNE_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN
(
int
)
git_worktree_prune_init_options
(
git_worktree_prune_options
*
opts
,
unsigned
int
version
);
/**
* Is the worktree prunable with the given
set of flag
s?
* Is the worktree prunable with the given
option
s?
*
* A worktree is not prunable in the following scenarios:
*
* - the worktree is linking to a valid on-disk worktree. The
* GIT_WORKTREE_PRUNE_VALID flag will cause this check to be
* ignored.
* - the worktree is not valid but locked. The
* GIT_WORKRTEE_PRUNE_LOCKED flag will cause this check to be
* ignored.
* `valid` member will cause this check to be ignored.
* - the worktree is locked. The `locked` flag will cause this
* check to be ignored.
*
* If the worktree is not valid and not locked or if the above
* flags have been passed in, this function will return a
* positive value.
*/
GIT_EXTERN
(
int
)
git_worktree_is_prunable
(
git_worktree
*
wt
,
unsigned
flags
);
GIT_EXTERN
(
int
)
git_worktree_is_prunable
(
git_worktree
*
wt
,
git_worktree_prune_options
*
opts
);
/**
* Prune working tree
...
...
@@ -163,10 +208,12 @@ GIT_EXTERN(int) git_worktree_is_prunable(git_worktree *wt, unsigned flags);
* `git_worktree_is_prunable` succeeds.
*
* @param wt Worktree to prune
* @param flags git_worktree_prune_t flags
* @param opts Specifies which checks to override. See
* `git_worktree_is_prunable`. May be NULL
* @return 0 or an error code
*/
GIT_EXTERN
(
int
)
git_worktree_prune
(
git_worktree
*
wt
,
unsigned
flags
);
GIT_EXTERN
(
int
)
git_worktree_prune
(
git_worktree
*
wt
,
git_worktree_prune_options
*
opts
);
/** @} */
GIT_END_DECL
...
...
src/worktree.c
View file @
dd0aa811
...
...
@@ -269,15 +269,32 @@ out:
return
err
;
}
int
git_worktree_add
(
git_worktree
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
worktree
)
int
git_worktree_add_init_options
(
git_worktree_add_options
*
opts
,
unsigned
int
version
)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE
(
opts
,
version
,
git_worktree_add_options
,
GIT_WORKTREE_ADD_OPTIONS_INIT
);
return
0
;
}
int
git_worktree_add
(
git_worktree
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
worktree
,
const
git_worktree_add_options
*
opts
)
{
git_buf
gitdir
=
GIT_BUF_INIT
,
wddir
=
GIT_BUF_INIT
,
buf
=
GIT_BUF_INIT
;
git_reference
*
ref
=
NULL
,
*
head
=
NULL
;
git_commit
*
commit
=
NULL
;
git_repository
*
wt
=
NULL
;
git_checkout_options
coopts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_worktree_add_options
wtopts
=
GIT_WORKTREE_ADD_OPTIONS_INIT
;
int
err
;
GITERR_CHECK_VERSION
(
opts
,
GIT_WORKTREE_ADD_OPTIONS_VERSION
,
"git_worktree_add_options"
);
if
(
opts
)
memcpy
(
&
wtopts
,
opts
,
sizeof
(
wtopts
));
assert
(
out
&&
repo
&&
name
&&
worktree
);
*
out
=
NULL
;
...
...
@@ -301,6 +318,21 @@ int git_worktree_add(git_worktree **out, git_repository *repo, const char *name,
if
((
err
=
git_path_prettify_dir
(
&
wddir
,
worktree
,
NULL
))
<
0
)
goto
out
;
if
(
wtopts
.
lock
)
{
int
fd
;
if
((
err
=
git_buf_joinpath
(
&
buf
,
gitdir
.
ptr
,
"locked"
))
<
0
)
goto
out
;
if
((
fd
=
p_creat
(
buf
.
ptr
,
0644
))
<
0
)
{
err
=
fd
;
goto
out
;
}
p_close
(
fd
);
git_buf_clear
(
&
buf
);
}
/* Create worktree .git file */
if
((
err
=
git_buf_printf
(
&
buf
,
"gitdir: %s
\n
"
,
gitdir
.
ptr
))
<
0
)
goto
out
;
...
...
@@ -424,11 +456,29 @@ out:
return
ret
;
}
int
git_worktree_is_prunable
(
git_worktree
*
wt
,
unsigned
flags
)
int
git_worktree_prune_init_options
(
git_worktree_prune_options
*
opts
,
unsigned
int
version
)
{
GIT_INIT_STRUCTURE_FROM_TEMPLATE
(
opts
,
version
,
git_worktree_prune_options
,
GIT_WORKTREE_PRUNE_OPTIONS_INIT
);
return
0
;
}
int
git_worktree_is_prunable
(
git_worktree
*
wt
,
git_worktree_prune_options
*
opts
)
{
git_buf
reason
=
GIT_BUF_INIT
;
git_worktree_prune_options
popts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
GITERR_CHECK_VERSION
(
opts
,
GIT_WORKTREE_PRUNE_OPTIONS_VERSION
,
"git_worktree_prune_options"
);
if
(
opts
)
memcpy
(
&
popts
,
opts
,
sizeof
(
popts
));
if
((
flags
&
GIT_WORKTREE_PRUNE_LOCKED
)
==
0
&&
if
((
popts
.
flags
&
GIT_WORKTREE_PRUNE_LOCKED
)
==
0
&&
git_worktree_is_locked
(
&
reason
,
wt
))
{
if
(
!
reason
.
size
)
...
...
@@ -439,7 +489,7 @@ int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
return
0
;
}
if
((
flags
&
GIT_WORKTREE_PRUNE_VALID
)
==
0
&&
if
((
popts
.
flags
&
GIT_WORKTREE_PRUNE_VALID
)
==
0
&&
git_worktree_validate
(
wt
)
==
0
)
{
giterr_set
(
GITERR_WORKTREE
,
"Not pruning valid working tree"
);
...
...
@@ -449,13 +499,22 @@ int git_worktree_is_prunable(git_worktree *wt, unsigned flags)
return
1
;
}
int
git_worktree_prune
(
git_worktree
*
wt
,
unsigned
flags
)
int
git_worktree_prune
(
git_worktree
*
wt
,
git_worktree_prune_options
*
opts
)
{
git_worktree_prune_options
popts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_buf
path
=
GIT_BUF_INIT
;
char
*
wtpath
;
int
err
;
if
(
!
git_worktree_is_prunable
(
wt
,
flags
))
{
GITERR_CHECK_VERSION
(
opts
,
GIT_WORKTREE_PRUNE_OPTIONS_VERSION
,
"git_worktree_prune_options"
);
if
(
opts
)
memcpy
(
&
popts
,
opts
,
sizeof
(
popts
));
if
(
!
git_worktree_is_prunable
(
wt
,
&
popts
))
{
err
=
-
1
;
goto
out
;
}
...
...
@@ -474,7 +533,7 @@ int git_worktree_prune(git_worktree *wt, unsigned flags)
/* Skip deletion of the actual working tree if it does
* not exist or deletion was not requested */
if
((
flags
&
GIT_WORKTREE_PRUNE_WORKING_TREE
)
==
0
||
if
((
popts
.
flags
&
GIT_WORKTREE_PRUNE_WORKING_TREE
)
==
0
||
!
git_path_exists
(
wt
->
gitlink_path
))
{
goto
out
;
...
...
tests/worktree/refs.c
View file @
dd0aa811
...
...
@@ -118,11 +118,14 @@ void test_worktree_refs__delete_fails_for_checked_out_branch(void)
void
test_worktree_refs__delete_succeeds_after_pruning_worktree
(
void
)
{
git_worktree_prune_options
opts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_reference
*
branch
;
git_worktree
*
worktree
;
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
;
cl_git_pass
(
git_worktree_lookup
(
&
worktree
,
fixture
.
repo
,
fixture
.
worktreename
));
cl_git_pass
(
git_worktree_prune
(
worktree
,
GIT_WORKTREE_PRUNE_VALID
));
cl_git_pass
(
git_worktree_prune
(
worktree
,
&
opts
));
git_worktree_free
(
worktree
);
cl_git_pass
(
git_branch_lookup
(
&
branch
,
fixture
.
repo
,
...
...
tests/worktree/submodule.c
View file @
dd0aa811
...
...
@@ -74,7 +74,7 @@ void test_worktree_submodule__resolve_relative_url(void)
cl_git_pass
(
git_repository_open
(
&
child
.
repo
,
WORKTREE_CHILD
));
/* Create worktree of submodule repository */
cl_git_pass
(
git_worktree_add
(
&
wt
,
child
.
repo
,
"subdir"
,
wt_path
.
ptr
));
cl_git_pass
(
git_worktree_add
(
&
wt
,
child
.
repo
,
"subdir"
,
wt_path
.
ptr
,
NULL
));
cl_git_pass
(
git_repository_open_from_worktree
(
&
repo
,
wt
));
cl_git_pass
(
git_submodule_resolve_url
(
&
sm_relative_path
,
repo
,
...
...
tests/worktree/worktree.c
View file @
dd0aa811
...
...
@@ -215,7 +215,7 @@ void test_worktree_worktree__init(void)
git_buf
path
=
GIT_BUF_INIT
;
cl_git_pass
(
git_buf_joinpath
(
&
path
,
fixture
.
repo
->
workdir
,
"../worktree-new"
));
cl_git_pass
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
));
cl_git_pass
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
,
NULL
));
/* Open and verify created repo */
cl_git_pass
(
git_repository_open
(
&
repo
,
path
.
ptr
));
...
...
@@ -228,6 +228,31 @@ void test_worktree_worktree__init(void)
git_repository_free
(
repo
);
}
void
test_worktree_worktree__add_locked
(
void
)
{
git_worktree
*
wt
;
git_repository
*
repo
;
git_reference
*
branch
;
git_buf
path
=
GIT_BUF_INIT
;
git_worktree_add_options
opts
=
GIT_WORKTREE_ADD_OPTIONS_INIT
;
opts
.
lock
=
1
;
cl_git_pass
(
git_buf_joinpath
(
&
path
,
fixture
.
repo
->
workdir
,
"../worktree-locked"
));
cl_git_pass
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-locked"
,
path
.
ptr
,
&
opts
));
/* Open and verify created repo */
cl_assert
(
git_worktree_is_locked
(
NULL
,
wt
));
cl_git_pass
(
git_repository_open
(
&
repo
,
path
.
ptr
));
cl_assert
(
git__suffixcmp
(
git_repository_workdir
(
repo
),
"worktree-locked/"
)
==
0
);
cl_git_pass
(
git_branch_lookup
(
&
branch
,
repo
,
"worktree-locked"
,
GIT_BRANCH_LOCAL
));
git_buf_free
(
&
path
);
git_worktree_free
(
wt
);
git_reference_free
(
branch
);
git_repository_free
(
repo
);
}
void
test_worktree_worktree__init_existing_branch
(
void
)
{
git_reference
*
head
,
*
branch
;
...
...
@@ -240,7 +265,7 @@ void test_worktree_worktree__init_existing_branch(void)
cl_git_pass
(
git_branch_create
(
&
branch
,
fixture
.
repo
,
"worktree-new"
,
commit
,
false
));
cl_git_pass
(
git_buf_joinpath
(
&
path
,
fixture
.
repo
->
workdir
,
"../worktree-new"
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
,
NULL
));
git_buf_free
(
&
path
);
git_commit_free
(
commit
);
...
...
@@ -254,7 +279,7 @@ void test_worktree_worktree__init_existing_worktree(void)
git_buf
path
=
GIT_BUF_INIT
;
cl_git_pass
(
git_buf_joinpath
(
&
path
,
fixture
.
repo
->
workdir
,
"../worktree-new"
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
,
path
.
ptr
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
,
path
.
ptr
,
NULL
));
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_assert_equal_s
(
wt
->
gitlink_path
,
fixture
.
worktree
->
gitlink
);
...
...
@@ -279,7 +304,7 @@ void test_worktree_worktree__init_existing_path(void)
}
cl_git_pass
(
git_buf_joinpath
(
&
path
,
fixture
.
repo
->
workdir
,
"../testrepo-worktree"
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
));
cl_git_fail
(
git_worktree_add
(
&
wt
,
fixture
.
repo
,
"worktree-new"
,
path
.
ptr
,
NULL
));
/* Verify files have not been re-created */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
wtfiles
);
i
++
)
{
...
...
@@ -303,7 +328,7 @@ void test_worktree_worktree__init_submodule(void)
cl_git_pass
(
git_buf_joinpath
(
&
path
,
repo
->
workdir
,
"sm_unchanged"
));
cl_git_pass
(
git_repository_open
(
&
sm
,
path
.
ptr
));
cl_git_pass
(
git_buf_joinpath
(
&
path
,
repo
->
workdir
,
"../worktree/"
));
cl_git_pass
(
git_worktree_add
(
&
worktree
,
sm
,
"repo-worktree"
,
path
.
ptr
));
cl_git_pass
(
git_worktree_add
(
&
worktree
,
sm
,
"repo-worktree"
,
path
.
ptr
,
NULL
));
cl_git_pass
(
git_repository_open_from_worktree
(
&
wt
,
worktree
));
cl_git_pass
(
git_path_prettify_dir
(
&
path
,
path
.
ptr
,
NULL
));
...
...
@@ -429,13 +454,31 @@ void test_worktree_worktree__unlock_locked_worktree(void)
git_worktree_free
(
wt
);
}
void
test_worktree_worktree__prune_without_opts_fails
(
void
)
{
git_worktree
*
wt
;
git_repository
*
repo
;
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_git_fail
(
git_worktree_prune
(
wt
,
NULL
));
/* Assert the repository is still valid */
cl_git_pass
(
git_repository_open_from_worktree
(
&
repo
,
wt
));
git_worktree_free
(
wt
);
git_repository_free
(
repo
);
}
void
test_worktree_worktree__prune_valid
(
void
)
{
git_worktree_prune_options
opts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_worktree
*
wt
;
git_repository
*
repo
;
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
;
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_git_pass
(
git_worktree_prune
(
wt
,
GIT_WORKTREE_PRUNE_VALID
));
cl_git_pass
(
git_worktree_prune
(
wt
,
&
opts
));
/* Assert the repository is not valid anymore */
cl_git_fail
(
git_repository_open_from_worktree
(
&
repo
,
wt
));
...
...
@@ -446,27 +489,33 @@ void test_worktree_worktree__prune_valid(void)
void
test_worktree_worktree__prune_locked
(
void
)
{
git_worktree_prune_options
opts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_worktree
*
wt
;
git_repository
*
repo
;
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_git_pass
(
git_worktree_lock
(
wt
,
NULL
));
cl_git_fail
(
git_worktree_prune
(
wt
,
GIT_WORKTREE_PRUNE_VALID
));
cl_git_fail
(
git_worktree_prune
(
wt
,
~
GIT_WORKTREE_PRUNE_LOCKED
));
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
;
cl_git_fail
(
git_worktree_prune
(
wt
,
&
opts
));
/* Assert the repository is still valid */
cl_git_pass
(
git_repository_open_from_worktree
(
&
repo
,
wt
));
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
|
GIT_WORKTREE_PRUNE_LOCKED
;
cl_git_pass
(
git_worktree_prune
(
wt
,
&
opts
));
git_worktree_free
(
wt
);
git_repository_free
(
repo
);
}
void
test_worktree_worktree__prune_gitdir
(
void
)
void
test_worktree_worktree__prune_gitdir
_only
(
void
)
{
git_worktree_prune_options
opts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_worktree
*
wt
;
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
;
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_git_pass
(
git_worktree_prune
(
wt
,
GIT_WORKTREE_PRUNE_VALID
));
cl_git_pass
(
git_worktree_prune
(
wt
,
&
opts
));
cl_assert
(
!
git_path_exists
(
wt
->
gitdir_path
));
cl_assert
(
git_path_exists
(
wt
->
gitlink_path
));
...
...
@@ -474,12 +523,15 @@ void test_worktree_worktree__prune_gitdir(void)
git_worktree_free
(
wt
);
}
void
test_worktree_worktree__prune_
both
(
void
)
void
test_worktree_worktree__prune_
worktree
(
void
)
{
git_worktree_prune_options
opts
=
GIT_WORKTREE_PRUNE_OPTIONS_INIT
;
git_worktree
*
wt
;
opts
.
flags
=
GIT_WORKTREE_PRUNE_VALID
|
GIT_WORKTREE_PRUNE_WORKING_TREE
;
cl_git_pass
(
git_worktree_lookup
(
&
wt
,
fixture
.
repo
,
"testrepo-worktree"
));
cl_git_pass
(
git_worktree_prune
(
wt
,
GIT_WORKTREE_PRUNE_WORKING_TREE
|
GIT_WORKTREE_PRUNE_VALID
));
cl_git_pass
(
git_worktree_prune
(
wt
,
&
opts
));
cl_assert
(
!
git_path_exists
(
wt
->
gitdir_path
));
cl_assert
(
!
git_path_exists
(
wt
->
gitlink_path
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment