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
3aa443a9
Commit
3aa443a9
authored
Aug 20, 2012
by
nulltoken
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
checkout: introduce git_checkout_tree()
parent
e8776d30
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
172 additions
and
103 deletions
+172
-103
include/git2/checkout.h
+27
-2
src/checkout.c
+0
-0
src/clone.c
+1
-2
src/filter.c
+9
-25
src/filter.h
+3
-4
tests-clar/checkout/tree.c
+132
-70
No files found.
include/git2/checkout.h
View file @
3aa443a9
...
...
@@ -32,10 +32,16 @@ typedef struct git_checkout_opts {
int
dir_mode
;
/* default is 0755 */
int
file_mode
;
/* default is 0644 */
int
file_open_flags
;
/* default is O_CREAT | O_TRUNC | O_WRONLY */
/* when not NULL, arrays of fnmatch pattern specifying
* which paths should be taken into account
*/
git_strarray
*
paths
;
}
git_checkout_opts
;
/**
* Updates files in the working tree to match the commit pointed to by HEAD.
* Updates files in the index and the working tree to match the content of the
* commit pointed at by HEAD.
*
* @param repo repository to check out (must be non-bare)
* @param opts specifies checkout options (may be NULL)
...
...
@@ -49,7 +55,9 @@ GIT_EXTERN(int) git_checkout_head(
git_indexer_stats
*
stats
);
/**
* Updates files in the working tree to match a commit pointed to by a ref.
* Updates files in the index and the working tree to match the content of the
* commit pointed at by the reference.
*
*
* @param ref reference to follow to a commit
* @param opts specifies checkout options (may be NULL)
...
...
@@ -62,6 +70,23 @@ GIT_EXTERN(int) git_checkout_reference(
git_checkout_opts
*
opts
,
git_indexer_stats
*
stats
);
/**
* Updates files in the index and working tree to match the content of the
* tree pointed at by the treeish.
*
* @param repo repository to check out (must be non-bare)
* @param treeish a commit, tag or tree which content will be used to update
* the working directory
* @param opts specifies checkout options (may be NULL)
* @param stats structure through which progress information is reported
* @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
* about the error)
*/
GIT_EXTERN
(
int
)
git_checkout_tree
(
git_repository
*
repo
,
git_object
*
treeish
,
git_checkout_opts
*
opts
,
git_indexer_stats
*
stats
);
/** @} */
GIT_END_DECL
...
...
src/checkout.c
View file @
3aa443a9
This diff is collapsed.
Click to expand it.
src/clone.c
View file @
3aa443a9
...
...
@@ -235,9 +235,8 @@ int git_clone(git_repository **out,
assert
(
out
&&
origin_url
&&
workdir_path
);
if
(
!
(
retcode
=
clone_internal
(
out
,
origin_url
,
workdir_path
,
fetch_stats
,
0
)))
{
if
(
!
(
retcode
=
clone_internal
(
out
,
origin_url
,
workdir_path
,
fetch_stats
,
0
)))
retcode
=
git_checkout_head
(
*
out
,
checkout_opts
,
checkout_stats
);
}
return
retcode
;
}
src/filter.c
View file @
3aa443a9
...
...
@@ -165,37 +165,21 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters)
return
0
;
}
static
int
unfiltered_blob_contents
(
git_buf
*
out
,
git_repository
*
repo
,
const
git_oid
*
blob_id
)
int
git_filter_blob_content
(
git_buf
*
out
,
git_blob
*
blob
,
const
char
*
hintpath
)
{
int
retcode
=
GIT_ERROR
;
git_blob
*
blob
;
if
(
!
(
retcode
=
git_blob_lookup
(
&
blob
,
repo
,
blob_id
)))
{
retcode
=
git_blob__getbuf
(
out
,
blob
);
git_blob_free
(
blob
);
}
git_buf
unfiltered
=
GIT_BUF_INIT
;
git_vector
filters
=
GIT_VECTOR_INIT
;
int
retcode
;
return
retcode
;
}
retcode
=
git_blob__getbuf
(
&
unfiltered
,
blob
);
int
git_filter_blob_contents
(
git_buf
*
out
,
git_repository
*
repo
,
const
git_oid
*
oid
,
const
char
*
path
)
{
int
retcode
=
GIT_ERROR
;
git_buf_clear
(
out
);
git_buf
unfiltered
=
GIT_BUF_INIT
;
if
(
!
unfiltered_blob_contents
(
&
unfiltered
,
repo
,
oid
))
{
git_vector
filters
=
GIT_VECTOR_INIT
;
if
(
git_filters_load
(
&
filters
,
repo
,
path
,
GIT_FILTER_TO_WORKTREE
)
>=
0
)
{
git_buf_clear
(
out
);
if
(
git_filters_load
(
&
filters
,
git_object_owner
((
git_object
*
)
blob
),
hintpath
,
GIT_FILTER_TO_WORKTREE
)
>=
0
)
retcode
=
git_filters_apply
(
out
,
&
unfiltered
,
&
filters
);
}
git_filters_free
(
&
filters
);
}
git_filters_free
(
&
filters
);
git_buf_free
(
&
unfiltered
);
return
retcode
;
}
src/filter.h
View file @
3aa443a9
...
...
@@ -124,11 +124,10 @@ extern int git_text_is_binary(git_text_stats *stats);
* Get the content of a blob after all filters have been run.
*
* @param out buffer to receive the contents
* @param repo repository containing the blob
* @param oid object id for the blob
* @param path path to the blob's output file, relative to the workdir root
* @param hintpath path to the blob's output file, relative to the workdir root.
* Used to determine what git filters should be applied to the content.
* @return 0 on success, an error code otherwise
*/
extern
int
git_filter_blob_content
s
(
git_buf
*
out
,
git_repository
*
repo
,
const
git_oid
*
oid
,
const
char
*
path
);
extern
int
git_filter_blob_content
(
git_buf
*
out
,
git_blob
*
blob
,
const
char
*
hint
path
);
#endif
tests-clar/checkout/
checkout
.c
→
tests-clar/checkout/
tree
.c
View file @
3aa443a9
...
...
@@ -5,21 +5,28 @@
static
git_repository
*
g_repo
;
static
git_object
*
g_treeish
;
static
git_checkout_opts
g_opts
;
void
test_checkout_
checkout
__initialize
(
void
)
void
test_checkout_
tree
__initialize
(
void
)
{
const
char
*
attributes
=
"* text eol=lf
\n
"
;
memset
(
&
g_opts
,
0
,
sizeof
(
g_opts
))
;
g_repo
=
cl_git_sandbox_init
(
"testrepo"
);
cl_git_mkfile
(
"./testrepo/.gitattributes"
,
attributes
);
cl_git_rewritefile
(
"./testrepo/.gitattributes"
,
"* text eol=lf
\n
"
);
cl_git_pass
(
git_repository_head_tree
((
git_tree
**
)
&
g_treeish
,
g_repo
));
}
void
test_checkout_
checkout
__cleanup
(
void
)
void
test_checkout_
tree
__cleanup
(
void
)
{
git_object_free
(
g_treeish
);
cl_git_sandbox_cleanup
();
}
static
void
test_file_contents
(
const
char
*
path
,
const
char
*
expectedcontents
)
{
int
fd
;
...
...
@@ -37,70 +44,105 @@ static void test_file_contents(const char *path, const char *expectedcontents)
cl_assert_equal_s
(
buffer
,
expectedcontents
);
}
void
test_checkout_checkout__bare
(
void
)
void
test_checkout_tree__cannot_checkout_a_bare_repository
(
void
)
{
cl_git_sandbox_cleanup
();
test_checkout_tree__cleanup
();
memset
(
&
g_opts
,
0
,
sizeof
(
g_opts
));
g_repo
=
cl_git_sandbox_init
(
"testrepo.git"
);
cl_git_fail
(
git_checkout_head
(
g_repo
,
NULL
,
NULL
));
cl_git_pass
(
git_repository_head_tree
((
git_tree
**
)
&
g_treeish
,
g_repo
));
cl_git_fail
(
git_checkout_tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
}
void
test_checkout_
checkout__default
(
void
)
void
test_checkout_
tree__update_the_content_of_workdir_with_missing_files
(
void
)
{
cl_git_pass
(
git_checkout_head
(
g_repo
,
NULL
,
NULL
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/README"
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/branch_file.txt"
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/new.txt"
));
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
test_file_contents
(
"./testrepo/README"
,
"hey there
\n
"
);
test_file_contents
(
"./testrepo/branch_file.txt"
,
"hi
\n
bye!
\n
"
);
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\n
"
);
}
void
test_checkout_tree__honor_the_specified_pathspecs
(
void
)
{
git_strarray
paths
;
char
*
entries
[]
=
{
"*.txt"
};
paths
.
strings
=
entries
;
paths
.
count
=
1
;
g_opts
.
paths
=
&
paths
;
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/README"
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/branch_file.txt"
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/new.txt"
));
void
test_checkout_checkout__crlf
(
void
)
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
cl_assert_equal_i
(
false
,
git_path_isfile
(
"./testrepo/README"
));
test_file_contents
(
"./testrepo/branch_file.txt"
,
"hi
\n
bye!
\n
"
);
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\n
"
);
}
static
void
set_config_entry_to
(
const
char
*
entry_name
,
bool
value
)
{
git_config
*
cfg
;
cl_git_pass
(
git_repository_config
(
&
cfg
,
g_repo
));
cl_git_pass
(
git_config_set_bool
(
cfg
,
entry_name
,
value
));
git_config_free
(
cfg
);
}
static
void
set_core_autocrlf_to
(
bool
value
)
{
set_config_entry_to
(
"core.autocrlf"
,
value
);
}
void
test_checkout_tree__honor_the_gitattributes_directives
(
void
)
{
const
char
*
attributes
=
"branch_file.txt text eol=crlf
\n
"
"new.txt text eol=lf
\n
"
;
git_config
*
cfg
;
cl_git_pass
(
git_repository_config__weakptr
(
&
cfg
,
g_repo
));
cl_git_pass
(
git_config_set_bool
(
cfg
,
"core.autocrlf"
,
false
));
cl_git_mkfile
(
"./testrepo/.gitattributes"
,
attributes
);
set_core_autocrlf_to
(
false
);
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
cl_git_pass
(
git_checkout_head
(
g_repo
,
NULL
,
NULL
));
test_file_contents
(
"./testrepo/README"
,
"hey there
\n
"
);
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\n
"
);
test_file_contents
(
"./testrepo/branch_file.txt"
,
"hi
\r\n
bye!
\r\n
"
);
}
void
test_checkout_checkout__win32_autocrlf
(
void
)
void
test_checkout_tree__honor_coreautocrlf_setting_set_to_true
(
void
)
{
#ifdef GIT_WIN32
git_config
*
cfg
;
const
char
*
expected_readme_text
=
"hey there
\r\n
"
;
cl_must_pass
(
p_unlink
(
"./testrepo/.gitattributes"
));
cl_git_pass
(
git_repository_config__weakptr
(
&
cfg
,
g_repo
));
cl_git_pass
(
git_config_set_bool
(
cfg
,
"core.autocrlf"
,
true
));
cl_git_pass
(
p_unlink
(
"./testrepo/.gitattributes"
));
set_core_autocrlf_to
(
true
);
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
cl_git_pass
(
git_checkout_head
(
g_repo
,
NULL
,
NULL
));
test_file_contents
(
"./testrepo/README"
,
expected_readme_text
);
#endif
}
static
void
enable_symlinks
(
bool
enable
)
static
void
set_repo_symlink_handling_cap_to
(
bool
value
)
{
git_config
*
cfg
;
cl_git_pass
(
git_repository_config
(
&
cfg
,
g_repo
));
cl_git_pass
(
git_config_set_bool
(
cfg
,
"core.symlinks"
,
enable
));
git_config_free
(
cfg
);
set_config_entry_to
(
"core.symlinks"
,
value
);
}
void
test_checkout_
checkout__symlinks
(
void
)
void
test_checkout_
tree__honor_coresymlinks_setting_set_to_true
(
void
)
{
/* First try with symlinks forced on */
enable_symlinks
(
true
);
cl_git_pass
(
git_checkout_
head
(
g_repo
,
NULL
,
NULL
));
set_repo_symlink_handling_cap_to
(
true
);
cl_git_pass
(
git_checkout_
tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
#ifdef GIT_WIN32
test_file_contents
(
"./testrepo/link_to_new.txt"
,
"new.txt"
);
...
...
@@ -116,56 +158,67 @@ void test_checkout_checkout__symlinks(void)
test_file_contents
(
"./testrepo/link_to_new.txt"
,
"my new file
\n
"
);
}
#endif
}
/* Now with symlinks forced off */
cl_git_sandbox_cleanup
();
g_repo
=
cl_git_sandbox_init
(
"testrepo"
);
enable_symlinks
(
false
);
cl_git_pass
(
git_checkout_
head
(
g_repo
,
NULL
,
NULL
));
void
test_checkout_tree__honor_coresymlinks_setting_set_to_false
(
void
)
{
set_repo_symlink_handling_cap_to
(
false
);
cl_git_pass
(
git_checkout_
tree
(
g_repo
,
g_treeish
,
NULL
,
NULL
));
test_file_contents
(
"./testrepo/link_to_new.txt"
,
"new.txt"
);
}
void
test_checkout_
checkout__existing_file_skip
(
void
)
void
test_checkout_
tree__options_skip_existing_file
(
void
)
{
git_checkout_opts
opts
=
{
0
};
cl_git_mkfile
(
"./testrepo/new.txt"
,
"This isn't what's stored!"
);
opts
.
existing_file_action
=
GIT_CHECKOUT_SKIP_EXISTING
;
cl_git_pass
(
git_checkout_head
(
g_repo
,
&
opts
,
NULL
));
g_opts
.
existing_file_action
=
GIT_CHECKOUT_SKIP_EXISTING
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
test_file_contents
(
"./testrepo/new.txt"
,
"This isn't what's stored!"
);
}
void
test_checkout_
checkout__existing_file_overwrit
e
(
void
)
void
test_checkout_
tree__options_overwrite_existing_fil
e
(
void
)
{
git_checkout_opts
opts
=
{
0
};
cl_git_mkfile
(
"./testrepo/new.txt"
,
"This isn't what's stored!"
);
opts
.
existing_file_action
=
GIT_CHECKOUT_OVERWRITE_EXISTING
;
cl_git_pass
(
git_checkout_head
(
g_repo
,
&
opts
,
NULL
));
g_opts
.
existing_file_action
=
GIT_CHECKOUT_OVERWRITE_EXISTING
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\n
"
);
}
void
test_checkout_
checkout_
_disable_filters
(
void
)
void
test_checkout_
tree__options
_disable_filters
(
void
)
{
git_checkout_opts
opts
=
{
0
};
cl_git_mkfile
(
"./testrepo/.gitattributes"
,
"*.txt text eol=crlf
\n
"
);
/* TODO cl_git_pass(git_checkout_head(g_repo, &opts, NULL));*/
/* TODO test_file_contents("./testrepo/new.txt", "my new file\r\n");*/
opts
.
disable_filters
=
true
;
cl_git_pass
(
git_checkout_head
(
g_repo
,
&
opts
,
NULL
));
g_opts
.
disable_filters
=
false
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\r\n
"
);
p_unlink
(
"./testrepo/new.txt"
);
g_opts
.
disable_filters
=
true
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
test_file_contents
(
"./testrepo/new.txt"
,
"my new file
\n
"
);
}
void
test_checkout_
checkout_
_dir_modes
(
void
)
void
test_checkout_
tree__options
_dir_modes
(
void
)
{
#ifndef GIT_WIN32
git_checkout_opts
opts
=
{
0
};
struct
stat
st
;
git_reference
*
ref
;
git_oid
oid
;
git_commit
*
commit
;
cl_git_pass
(
git_reference_lookup
(
&
ref
,
g_repo
,
"refs/heads/dir"
));
cl_git_pass
(
git_reference_name_to_oid
(
&
oid
,
g_repo
,
"refs/heads/dir"
));
cl_git_pass
(
git_commit_lookup
(
&
commit
,
g_repo
,
&
oid
));
g_opts
.
dir_mode
=
0701
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
(
git_object
*
)
commit
,
&
g_opts
,
NULL
));
opts
.
dir_mode
=
0701
;
cl_git_pass
(
git_checkout_reference
(
ref
,
&
opts
,
NULL
));
cl_git_pass
(
p_stat
(
"./testrepo/a"
,
&
st
));
cl_assert_equal_i
(
st
.
st_mode
&
0777
,
0701
);
...
...
@@ -173,34 +226,43 @@ void test_checkout_checkout__dir_modes(void)
cl_git_pass
(
p_stat
(
"./testrepo/a/b.txt"
,
&
st
));
cl_assert_equal_i
(
st
.
st_mode
&
0777
,
0755
);
git_
reference_free
(
ref
);
git_
commit_free
(
commit
);
#endif
}
void
test_checkout_
checkout_
_override_file_modes
(
void
)
void
test_checkout_
tree__options
_override_file_modes
(
void
)
{
#ifndef GIT_WIN32
git_checkout_opts
opts
=
{
0
};
struct
stat
st
;
opts
.
file_mode
=
0700
;
cl_git_pass
(
git_checkout_head
(
g_repo
,
&
opts
,
NULL
));
g_opts
.
file_mode
=
0700
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
cl_git_pass
(
p_stat
(
"./testrepo/new.txt"
,
&
st
));
cl_assert_equal_i
(
st
.
st_mode
&
0777
,
0700
);
#endif
}
void
test_checkout_
checkout_
_open_flags
(
void
)
void
test_checkout_
tree__options
_open_flags
(
void
)
{
git_checkout_opts
opts
=
{
0
};
cl_git_mkfile
(
"./testrepo/new.txt"
,
"hi
\n
"
);
opts
.
file_open_flags
=
O_CREAT
|
O_RDWR
|
O_APPEND
;
cl_git_pass
(
git_checkout_head
(
g_repo
,
&
opts
,
NULL
));
g_opts
.
file_open_flags
=
O_CREAT
|
O_RDWR
|
O_APPEND
;
cl_git_pass
(
git_checkout_tree
(
g_repo
,
g_treeish
,
&
g_opts
,
NULL
));
test_file_contents
(
"./testrepo/new.txt"
,
"hi
\n
my new file
\n
"
);
}
void
test_checkout_
checkout__detached_head
(
void
)
void
test_checkout_
tree__cannot_checkout_a_non_treeish
(
void
)
{
/* TODO: write this when git_checkout_commit is implemented. */
git_oid
oid
;
git_blob
*
blob
;
cl_git_pass
(
git_oid_fromstr
(
&
oid
,
"a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"
));
cl_git_pass
(
git_blob_lookup
(
&
blob
,
g_repo
,
&
oid
));
cl_git_fail
(
git_checkout_tree
(
g_repo
,
(
git_object
*
)
blob
,
NULL
,
NULL
));
git_blob_free
(
blob
);
}
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