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
d24a5312
Commit
d24a5312
authored
Feb 12, 2015
by
Carlos Martín Nieto
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2866 from ethomson/checkout_perf2
Checkout performance
parents
8e29ae73
fa89ff20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
380 additions
and
129 deletions
+380
-129
src/attr.c
+95
-34
src/attr_file.c
+51
-17
src/attr_file.h
+37
-10
src/attrcache.c
+10
-5
src/attrcache.h
+1
-0
src/checkout.c
+49
-41
src/fileops.c
+26
-9
src/fileops.h
+11
-2
src/filter.c
+24
-5
src/filter.h
+10
-0
src/ignore.c
+2
-2
src/repository.h
+2
-0
tests/checkout/tree.c
+54
-0
tests/refs/list.c
+2
-2
tests/repo/iterator.c
+2
-1
tests/resources/testrepo/.gitted/objects/6f/d5c7dd2ab27b48c493023f794be09861e9045f
+2
-0
tests/resources/testrepo/.gitted/objects/c3/6d8ea75da8cb510fcb0c408c1d7e53f9a99dbe
+0
-0
tests/resources/testrepo/.gitted/objects/e3/6900c3224db4adf4c7f7a09d4ac80247978a13
+0
-0
tests/resources/testrepo/.gitted/refs/heads/ident
+1
-0
tests/revwalk/basic.c
+1
-1
No files found.
src/attr.c
View file @
d24a5312
...
...
@@ -29,6 +29,7 @@ git_attr_t git_attr_value(const char *attr)
static
int
collect_attr_files
(
git_repository
*
repo
,
git_attr_session
*
attr_session
,
uint32_t
flags
,
const
char
*
path
,
git_vector
*
files
);
...
...
@@ -57,7 +58,7 @@ int git_attr_get(
if
(
git_attr_path__init
(
&
path
,
pathname
,
git_repository_workdir
(
repo
))
<
0
)
return
-
1
;
if
((
error
=
collect_attr_files
(
repo
,
flags
,
pathname
,
&
files
))
<
0
)
if
((
error
=
collect_attr_files
(
repo
,
NULL
,
flags
,
pathname
,
&
files
))
<
0
)
goto
cleanup
;
memset
(
&
attr
,
0
,
sizeof
(
attr
));
...
...
@@ -90,9 +91,10 @@ typedef struct {
git_attr_assignment
*
found
;
}
attr_get_many_info
;
int
git_attr_get_many
(
int
git_attr_get_many
_with_session
(
const
char
**
values
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
uint32_t
flags
,
const
char
*
pathname
,
size_t
num_attr
,
...
...
@@ -115,7 +117,7 @@ int git_attr_get_many(
if
(
git_attr_path__init
(
&
path
,
pathname
,
git_repository_workdir
(
repo
))
<
0
)
return
-
1
;
if
((
error
=
collect_attr_files
(
repo
,
flags
,
pathname
,
&
files
))
<
0
)
if
((
error
=
collect_attr_files
(
repo
,
attr_session
,
flags
,
pathname
,
&
files
))
<
0
)
goto
cleanup
;
info
=
git__calloc
(
num_attr
,
sizeof
(
attr_get_many_info
));
...
...
@@ -161,6 +163,17 @@ cleanup:
return
error
;
}
int
git_attr_get_many
(
const
char
**
values
,
git_repository
*
repo
,
uint32_t
flags
,
const
char
*
pathname
,
size_t
num_attr
,
const
char
**
names
)
{
return
git_attr_get_many_with_session
(
values
,
repo
,
NULL
,
flags
,
pathname
,
num_attr
,
names
);
}
int
git_attr_foreach
(
git_repository
*
repo
,
...
...
@@ -183,7 +196,7 @@ int git_attr_foreach(
if
(
git_attr_path__init
(
&
path
,
pathname
,
git_repository_workdir
(
repo
))
<
0
)
return
-
1
;
if
((
error
=
collect_attr_files
(
repo
,
flags
,
pathname
,
&
files
))
<
0
||
if
((
error
=
collect_attr_files
(
repo
,
NULL
,
flags
,
pathname
,
&
files
))
<
0
||
(
error
=
git_strmap_alloc
(
&
seen
))
<
0
)
goto
cleanup
;
...
...
@@ -219,6 +232,7 @@ cleanup:
static
int
preload_attr_file
(
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_source
source
,
const
char
*
base
,
const
char
*
file
)
...
...
@@ -229,19 +243,61 @@ static int preload_attr_file(
if
(
!
file
)
return
0
;
if
(
!
(
error
=
git_attr_cache__get
(
&
preload
,
repo
,
source
,
base
,
file
,
git_attr_file__parse_buffer
)))
&
preload
,
repo
,
attr_session
,
source
,
base
,
file
,
git_attr_file__parse_buffer
)))
git_attr_file__free
(
preload
);
return
error
;
}
static
int
attr_setup
(
git_repository
*
repo
)
static
int
system_attr_file
(
git_buf
*
out
,
git_attr_session
*
attr_session
)
{
int
error
;
if
(
!
attr_session
)
{
error
=
git_sysdir_find_system_file
(
out
,
GIT_ATTR_FILE_SYSTEM
);
if
(
error
==
GIT_ENOTFOUND
)
giterr_clear
();
return
error
;
}
if
(
!
attr_session
->
init_sysdir
)
{
error
=
git_sysdir_find_system_file
(
&
attr_session
->
sysdir
,
GIT_ATTR_FILE_SYSTEM
);
if
(
error
==
GIT_ENOTFOUND
)
giterr_clear
();
else
if
(
error
)
return
error
;
attr_session
->
init_sysdir
=
1
;
}
if
(
attr_session
->
sysdir
.
size
==
0
)
return
GIT_ENOTFOUND
;
/* We can safely provide a git_buf with no allocation (asize == 0) to
* a consumer. This allows them to treat this as a regular `git_buf`,
* but their call to `git_buf_free` will not attempt to free it.
*/
out
->
ptr
=
attr_session
->
sysdir
.
ptr
;
out
->
size
=
attr_session
->
sysdir
.
size
;
out
->
asize
=
0
;
return
0
;
}
static
int
attr_setup
(
git_repository
*
repo
,
git_attr_session
*
attr_session
)
{
int
error
=
0
;
const
char
*
workdir
=
git_repository_workdir
(
repo
);
git_index
*
idx
=
NULL
;
git_buf
sys
=
GIT_BUF_INIT
;
if
(
attr_session
&&
attr_session
->
init_setup
)
return
0
;
if
((
error
=
git_attr_cache__init
(
repo
))
<
0
)
return
error
;
...
...
@@ -249,39 +305,39 @@ static int attr_setup(git_repository *repo)
* definitions will be available for later file parsing
*/
if
(
!
(
error
=
git_sysdir_find_system_file
(
&
sys
,
GIT_ATTR_FILE_SYSTEM
)))
{
error
=
system_attr_file
(
&
sys
,
attr_session
);
if
(
error
==
0
)
error
=
preload_attr_file
(
repo
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
sys
.
ptr
);
git_buf_free
(
&
sys
);
}
if
(
error
<
0
)
{
if
(
error
==
GIT_ENOTFOUND
)
{
giterr_clear
();
error
=
0
;
}
else
return
error
;
}
repo
,
attr_session
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
sys
.
ptr
);
else
if
(
error
!=
GIT_ENOTFOUND
)
return
error
;
git_buf_free
(
&
sys
);
if
((
error
=
preload_attr_file
(
repo
,
GIT_ATTR_FILE__FROM_FILE
,
repo
,
attr_session
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
git_repository_attr_cache
(
repo
)
->
cfg_attr_file
))
<
0
)
return
error
;
if
((
error
=
preload_attr_file
(
repo
,
GIT_ATTR_FILE__FROM_FILE
,
repo
,
attr_session
,
GIT_ATTR_FILE__FROM_FILE
,
git_repository_path
(
repo
),
GIT_ATTR_FILE_INREPO
))
<
0
)
return
error
;
if
(
workdir
!=
NULL
&&
(
error
=
preload_attr_file
(
repo
,
GIT_ATTR_FILE__FROM_FILE
,
workdir
,
GIT_ATTR_FILE
))
<
0
)
repo
,
attr_session
,
GIT_ATTR_FILE__FROM_FILE
,
workdir
,
GIT_ATTR_FILE
))
<
0
)
return
error
;
if
((
error
=
git_repository_index__weakptr
(
&
idx
,
repo
))
<
0
||
(
error
=
preload_attr_file
(
repo
,
GIT_ATTR_FILE__FROM_INDEX
,
NULL
,
GIT_ATTR_FILE
))
<
0
)
repo
,
attr_session
,
GIT_ATTR_FILE__FROM_INDEX
,
NULL
,
GIT_ATTR_FILE
))
<
0
)
return
error
;
if
(
attr_session
)
attr_session
->
init_setup
=
1
;
return
error
;
}
...
...
@@ -321,6 +377,7 @@ int git_attr_add_macro(
typedef
struct
{
git_repository
*
repo
;
git_attr_session
*
attr_session
;
uint32_t
flags
;
const
char
*
workdir
;
git_index
*
index
;
...
...
@@ -356,6 +413,7 @@ static int attr_decide_sources(
static
int
push_attr_file
(
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_vector
*
list
,
git_attr_file_source
source
,
const
char
*
base
,
...
...
@@ -364,8 +422,9 @@ static int push_attr_file(
int
error
=
0
;
git_attr_file
*
file
=
NULL
;
error
=
git_attr_cache__get
(
&
file
,
repo
,
source
,
base
,
filename
,
git_attr_file__parse_buffer
);
error
=
git_attr_cache__get
(
&
file
,
repo
,
attr_session
,
source
,
base
,
filename
,
git_attr_file__parse_buffer
);
if
(
error
<
0
)
return
error
;
...
...
@@ -387,8 +446,8 @@ static int push_one_attr(void *ref, const char *path)
info
->
flags
,
info
->
workdir
!=
NULL
,
info
->
index
!=
NULL
,
src
);
for
(
i
=
0
;
!
error
&&
i
<
n_src
;
++
i
)
error
=
push_attr_file
(
info
->
repo
,
info
->
files
,
src
[
i
],
path
,
GIT_ATTR_FILE
);
error
=
push_attr_file
(
info
->
repo
,
info
->
attr_session
,
info
->
files
,
src
[
i
],
path
,
GIT_ATTR_FILE
);
return
error
;
}
...
...
@@ -407,6 +466,7 @@ static void release_attr_files(git_vector *files)
static
int
collect_attr_files
(
git_repository
*
repo
,
git_attr_session
*
attr_session
,
uint32_t
flags
,
const
char
*
path
,
git_vector
*
files
)
...
...
@@ -416,7 +476,7 @@ static int collect_attr_files(
const
char
*
workdir
=
git_repository_workdir
(
repo
);
attr_walk_up_info
info
=
{
NULL
};
if
((
error
=
attr_setup
(
repo
))
<
0
)
if
((
error
=
attr_setup
(
repo
,
attr_session
))
<
0
)
return
error
;
/* Resolve path in a non-bare repo */
...
...
@@ -435,12 +495,13 @@ static int collect_attr_files(
*/
error
=
push_attr_file
(
repo
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
repo
,
attr_session
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
git_repository_path
(
repo
),
GIT_ATTR_FILE_INREPO
);
if
(
error
<
0
)
goto
cleanup
;
info
.
repo
=
repo
;
info
.
repo
=
repo
;
info
.
attr_session
=
attr_session
;
info
.
flags
=
flags
;
info
.
workdir
=
workdir
;
if
(
git_repository_index__weakptr
(
&
info
.
index
,
repo
)
<
0
)
...
...
@@ -457,21 +518,21 @@ static int collect_attr_files(
if
(
git_repository_attr_cache
(
repo
)
->
cfg_attr_file
!=
NULL
)
{
error
=
push_attr_file
(
repo
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
repo
,
attr_session
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
git_repository_attr_cache
(
repo
)
->
cfg_attr_file
);
if
(
error
<
0
)
goto
cleanup
;
}
if
((
flags
&
GIT_ATTR_CHECK_NO_SYSTEM
)
==
0
)
{
error
=
git_sysdir_find_system_file
(
&
dir
,
GIT_ATTR_FILE_SYSTEM
);
error
=
system_attr_file
(
&
dir
,
attr_session
);
if
(
!
error
)
error
=
push_attr_file
(
repo
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
dir
.
ptr
);
else
if
(
error
==
GIT_ENOTFOUND
)
{
giterr_clear
();
repo
,
attr_session
,
files
,
GIT_ATTR_FILE__FROM_FILE
,
NULL
,
dir
.
ptr
);
else
if
(
error
==
GIT_ENOTFOUND
)
error
=
0
;
}
}
cleanup:
...
...
src/attr_file.c
View file @
d24a5312
...
...
@@ -96,6 +96,7 @@ static int attr_file_oid_from_index(
int
git_attr_file__load
(
git_attr_file
**
out
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_entry
*
entry
,
git_attr_file_source
source
,
git_attr_file_parser
parser
)
...
...
@@ -105,6 +106,7 @@ int git_attr_file__load(
git_buf
content
=
GIT_BUF_INIT
;
git_attr_file
*
file
;
struct
stat
st
;
bool
nonexistent
=
false
;
*
out
=
NULL
;
...
...
@@ -127,22 +129,16 @@ int git_attr_file__load(
case
GIT_ATTR_FILE__FROM_FILE
:
{
int
fd
;
if
(
p_stat
(
entry
->
fullpath
,
&
st
)
<
0
)
return
git_path_set_error
(
errno
,
entry
->
fullpath
,
"stat"
);
if
(
S_ISDIR
(
st
.
st_mode
))
return
GIT_ENOTFOUND
;
/* For open or read errors, return ENOTFOUND to skip item */
/* For open or read errors, pretend that we got ENOTFOUND. */
/* TODO: issue warning when warning API is available */
if
((
fd
=
git_futils_open_ro
(
entry
->
fullpath
))
<
0
)
return
GIT_ENOTFOUND
;
error
=
git_futils_readbuffer_fd
(
&
content
,
fd
,
(
size_t
)
st
.
st_size
);
p_close
(
fd
);
if
(
error
<
0
)
return
GIT_ENOTFOUND
;
if
(
p_stat
(
entry
->
fullpath
,
&
st
)
<
0
||
S_ISDIR
(
st
.
st_mode
)
||
(
fd
=
git_futils_open_ro
(
entry
->
fullpath
))
<
0
||
(
error
=
git_futils_readbuffer_fd
(
&
content
,
fd
,
(
size_t
)
st
.
st_size
))
<
0
)
nonexistent
=
true
;
else
p_close
(
fd
);
break
;
}
...
...
@@ -154,13 +150,21 @@ int git_attr_file__load(
if
((
error
=
git_attr_file__new
(
&
file
,
entry
,
source
))
<
0
)
goto
cleanup
;
/* store the key of the attr_reader; don't bother with cache
* invalidation during the same attr reader session.
*/
if
(
attr_session
)
file
->
session_key
=
attr_session
->
key
;
if
(
parser
&&
(
error
=
parser
(
repo
,
file
,
git_buf_cstr
(
&
content
)))
<
0
)
{
git_attr_file__free
(
file
);
goto
cleanup
;
}
/* write cache breaker */
if
(
source
==
GIT_ATTR_FILE__FROM_INDEX
)
/* write cache breakers */
if
(
nonexistent
)
file
->
nonexistent
=
1
;
else
if
(
source
==
GIT_ATTR_FILE__FROM_INDEX
)
git_oid_cpy
(
&
file
->
cache_data
.
oid
,
git_blob_id
(
blob
));
else
if
(
source
==
GIT_ATTR_FILE__FROM_FILE
)
git_futils_filestamp_set_from_stat
(
&
file
->
cache_data
.
stamp
,
&
st
);
...
...
@@ -175,11 +179,22 @@ cleanup:
return
error
;
}
int
git_attr_file__out_of_date
(
git_repository
*
repo
,
git_attr_file
*
file
)
int
git_attr_file__out_of_date
(
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file
*
file
)
{
if
(
!
file
)
return
1
;
/* we are never out of date if we just created this data in the same
* attr_session; otherwise, nonexistent files must be invalidated
*/
if
(
attr_session
&&
attr_session
->
key
==
file
->
session_key
)
return
0
;
else
if
(
file
->
nonexistent
)
return
1
;
switch
(
file
->
source
)
{
case
GIT_ATTR_FILE__IN_MEMORY
:
return
0
;
...
...
@@ -831,3 +846,22 @@ void git_attr_rule__free(git_attr_rule *rule)
git__free
(
rule
);
}
int
git_attr_session__init
(
git_attr_session
*
session
,
git_repository
*
repo
)
{
assert
(
repo
);
session
->
key
=
git_atomic_inc
(
&
repo
->
attr_session_key
);
return
0
;
}
void
git_attr_session__free
(
git_attr_session
*
session
)
{
if
(
!
session
)
return
;
git_buf_free
(
&
session
->
sysdir
);
git_buf_free
(
&
session
->
tmp
);
memset
(
session
,
0
,
sizeof
(
git_attr_session
));
}
src/attr_file.h
View file @
d24a5312
...
...
@@ -38,11 +38,11 @@
GIT_ATTR_FNMATCH_ALLOWMACRO | GIT_ATTR_FNMATCH_NOLEADINGDIR)
typedef
enum
{
GIT_ATTR_FILE__IN_MEMORY
=
0
,
GIT_ATTR_FILE__FROM_FILE
=
1
,
GIT_ATTR_FILE__FROM_INDEX
=
2
,
GIT_ATTR_FILE__IN_MEMORY
=
0
,
GIT_ATTR_FILE__FROM_FILE
=
1
,
GIT_ATTR_FILE__FROM_INDEX
=
2
,
GIT_ATTR_FILE_NUM_SOURCES
=
3
GIT_ATTR_FILE_NUM_SOURCES
=
3
}
git_attr_file_source
;
extern
const
char
*
git_attr__true
;
...
...
@@ -84,6 +84,8 @@ typedef struct {
git_attr_file_source
source
;
git_vector
rules
;
/* vector of <rule*> or <fnmatch*> */
git_pool
pool
;
unsigned
int
nonexistent
:
1
;
int
session_key
;
union
{
git_oid
oid
;
git_futils_filestamp
stamp
;
...
...
@@ -96,11 +98,6 @@ struct git_attr_file_entry {
char
fullpath
[
GIT_FLEX_ARRAY
];
};
typedef
int
(
*
git_attr_file_parser
)(
git_repository
*
repo
,
git_attr_file
*
file
,
const
char
*
data
);
typedef
struct
{
git_buf
full
;
char
*
path
;
...
...
@@ -108,6 +105,35 @@ typedef struct {
int
is_dir
;
}
git_attr_path
;
/* A git_attr_session can provide an "instance" of reading, to prevent cache
* invalidation during a single operation instance (like checkout).
*/
typedef
struct
{
int
key
;
unsigned
int
init_setup
:
1
,
init_sysdir
:
1
;
git_buf
sysdir
;
git_buf
tmp
;
}
git_attr_session
;
extern
int
git_attr_session__init
(
git_attr_session
*
attr_session
,
git_repository
*
repo
);
extern
void
git_attr_session__free
(
git_attr_session
*
session
);
extern
int
git_attr_get_many_with_session
(
const
char
**
values_out
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
uint32_t
flags
,
const
char
*
path
,
size_t
num_attr
,
const
char
**
names
);
typedef
int
(
*
git_attr_file_parser
)(
git_repository
*
repo
,
git_attr_file
*
file
,
const
char
*
data
);
/*
* git_attr_file API
*/
...
...
@@ -122,6 +148,7 @@ void git_attr_file__free(git_attr_file *file);
int
git_attr_file__load
(
git_attr_file
**
out
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_entry
*
ce
,
git_attr_file_source
source
,
git_attr_file_parser
parser
);
...
...
@@ -130,7 +157,7 @@ int git_attr_file__load_standalone(
git_attr_file
**
out
,
const
char
*
path
);
int
git_attr_file__out_of_date
(
git_repository
*
repo
,
git_attr_file
*
file
);
git_repository
*
repo
,
git_attr_
session
*
session
,
git_attr_
file
*
file
);
int
git_attr_file__parse_buffer
(
git_repository
*
repo
,
git_attr_file
*
attrs
,
const
char
*
data
);
...
...
src/attrcache.c
View file @
d24a5312
...
...
@@ -149,6 +149,7 @@ static int attr_cache_lookup(
git_attr_file
**
out_file
,
git_attr_file_entry
**
out_entry
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_source
source
,
const
char
*
base
,
const
char
*
filename
)
...
...
@@ -162,9 +163,12 @@ static int attr_cache_lookup(
/* join base and path as needed */
if
(
base
!=
NULL
&&
git_path_root
(
filename
)
<
0
)
{
if
(
git_buf_joinpath
(
&
path
,
base
,
filename
)
<
0
)
git_buf
*
p
=
attr_session
?
&
attr_session
->
tmp
:
&
path
;
if
(
git_buf_joinpath
(
p
,
base
,
filename
)
<
0
)
return
-
1
;
filename
=
path
.
ptr
;
filename
=
p
->
ptr
;
}
relfile
=
filename
;
...
...
@@ -196,6 +200,7 @@ cleanup:
int
git_attr_cache__get
(
git_attr_file
**
out
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_source
source
,
const
char
*
base
,
const
char
*
filename
,
...
...
@@ -207,12 +212,12 @@ int git_attr_cache__get(
git_attr_file
*
file
=
NULL
,
*
updated
=
NULL
;
if
((
error
=
attr_cache_lookup
(
&
file
,
&
entry
,
repo
,
source
,
base
,
filename
))
<
0
)
&
file
,
&
entry
,
repo
,
attr_session
,
source
,
base
,
filename
))
<
0
)
return
error
;
/* load file if we don't have one or if existing one is out of date */
if
(
!
file
||
(
error
=
git_attr_file__out_of_date
(
repo
,
file
))
>
0
)
error
=
git_attr_file__load
(
&
updated
,
repo
,
entry
,
source
,
parser
);
if
(
!
file
||
(
error
=
git_attr_file__out_of_date
(
repo
,
attr_session
,
file
))
>
0
)
error
=
git_attr_file__load
(
&
updated
,
repo
,
attr_session
,
entry
,
source
,
parser
);
/* if we loaded the file, insert into and/or update cache */
if
(
updated
)
{
...
...
src/attrcache.h
View file @
d24a5312
...
...
@@ -31,6 +31,7 @@ extern int git_attr_cache__do_init(git_repository *repo);
extern
int
git_attr_cache__get
(
git_attr_file
**
file
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_attr_file_source
source
,
const
char
*
base
,
const
char
*
filename
,
...
...
src/checkout.c
View file @
d24a5312
...
...
@@ -28,6 +28,11 @@
#include "buf_text.h"
#include "merge_file.h"
#include "path.h"
#include "attr.h"
#include "pool.h"
#include "strmap.h"
GIT__USE_STRMAP
;
/* See docs/checkout-internals.md for more information */
...
...
@@ -68,7 +73,8 @@ typedef struct {
size_t
total_steps
;
size_t
completed_steps
;
git_checkout_perfdata
perfdata
;
git_buf
last_mkdir
;
git_strmap
*
mkdir_map
;
git_attr_session
attr_session
;
}
checkout_data
;
typedef
struct
{
...
...
@@ -1291,25 +1297,6 @@ fail:
return
error
;
}
static
int
checkout_mkdir
(
checkout_data
*
data
,
const
char
*
path
,
const
char
*
base
,
mode_t
mode
,
unsigned
int
flags
)
{
struct
git_futils_mkdir_perfdata
mkdir_perfdata
=
{
0
};
int
error
=
git_futils_mkdir_withperf
(
path
,
base
,
mode
,
flags
,
&
mkdir_perfdata
);
data
->
perfdata
.
mkdir_calls
+=
mkdir_perfdata
.
mkdir_calls
;
data
->
perfdata
.
stat_calls
+=
mkdir_perfdata
.
stat_calls
;
data
->
perfdata
.
chmod_calls
+=
mkdir_perfdata
.
chmod_calls
;
return
error
;
}
static
bool
should_remove_existing
(
checkout_data
*
data
)
{
int
ignorecase
=
0
;
...
...
@@ -1325,31 +1312,43 @@ static bool should_remove_existing(checkout_data *data)
#define MKDIR_REMOVE_EXISTING \
MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS
static
int
checkout_mkdir
(
checkout_data
*
data
,
const
char
*
path
,
const
char
*
base
,
mode_t
mode
,
unsigned
int
flags
)
{
struct
git_futils_mkdir_options
mkdir_opts
=
{
0
};
int
error
;
mkdir_opts
.
dir_map
=
data
->
mkdir_map
;
mkdir_opts
.
pool
=
&
data
->
pool
;
error
=
git_futils_mkdir_ext
(
path
,
base
,
mode
,
flags
,
&
mkdir_opts
);
data
->
perfdata
.
mkdir_calls
+=
mkdir_opts
.
perfdata
.
mkdir_calls
;
data
->
perfdata
.
stat_calls
+=
mkdir_opts
.
perfdata
.
stat_calls
;
data
->
perfdata
.
chmod_calls
+=
mkdir_opts
.
perfdata
.
chmod_calls
;
return
error
;
}
static
int
mkpath2file
(
checkout_data
*
data
,
const
char
*
path
,
unsigned
int
mode
)
{
git_buf
*
mkdir_path
=
&
data
->
tmp
;
struct
stat
st
;
bool
remove_existing
=
should_remove_existing
(
data
);
unsigned
int
flags
=
(
remove_existing
?
MKDIR_REMOVE_EXISTING
:
MKDIR_NORMAL
)
|
GIT_MKDIR_SKIP_LAST
;
int
error
;
if
((
error
=
git_buf_sets
(
mkdir_path
,
path
))
<
0
)
if
((
error
=
checkout_mkdir
(
data
,
path
,
data
->
opts
.
target_directory
,
mode
,
flags
))
<
0
)
return
error
;
git_buf_rtruncate_at_char
(
mkdir_path
,
'/'
);
if
(
!
data
->
last_mkdir
.
size
||
data
->
last_mkdir
.
size
!=
mkdir_path
->
size
||
memcmp
(
mkdir_path
->
ptr
,
data
->
last_mkdir
.
ptr
,
mkdir_path
->
size
)
!=
0
)
{
if
((
error
=
checkout_mkdir
(
data
,
mkdir_path
->
ptr
,
data
->
opts
.
target_directory
,
mode
,
remove_existing
?
MKDIR_REMOVE_EXISTING
:
MKDIR_NORMAL
))
<
0
)
return
error
;
git_buf_swap
(
&
data
->
last_mkdir
,
mkdir_path
);
}
if
(
remove_existing
)
{
data
->
perfdata
.
stat_calls
++
;
...
...
@@ -1425,8 +1424,8 @@ static int blob_content_to_file(
hint_path
=
path
;
if
(
!
data
->
opts
.
disable_filters
)
error
=
git_filter_list_
load
(
&
fl
,
git_blob_owner
(
blob
)
,
blob
,
hint_path
,
error
=
git_filter_list_
_load_with_attr_session
(
&
fl
,
data
->
repo
,
&
data
->
attr_session
,
blob
,
hint_path
,
GIT_FILTER_TO_WORKTREE
,
GIT_FILTER_OPT_DEFAULT
);
if
(
!
error
)
...
...
@@ -2008,7 +2007,8 @@ static int checkout_write_merge(
in_data
.
ptr
=
(
char
*
)
result
.
ptr
;
in_data
.
size
=
result
.
len
;
if
((
error
=
git_filter_list_load
(
&
fl
,
data
->
repo
,
NULL
,
git_buf_cstr
(
&
path_workdir
),
if
((
error
=
git_filter_list__load_with_attr_session
(
&
fl
,
data
->
repo
,
&
data
->
attr_session
,
NULL
,
git_buf_cstr
(
&
path_workdir
),
GIT_FILTER_TO_WORKTREE
,
GIT_FILTER_OPT_DEFAULT
))
<
0
||
(
error
=
git_filter_list_apply_to_data
(
&
out_data
,
fl
,
&
in_data
))
<
0
)
goto
done
;
...
...
@@ -2212,12 +2212,17 @@ static void checkout_data_clear(checkout_data *data)
git__free
(
data
->
pfx
);
data
->
pfx
=
NULL
;
git_buf_free
(
&
data
->
last_mkdir
);
git_strmap_free
(
data
->
mkdir_map
);
git_buf_free
(
&
data
->
path
);
git_buf_free
(
&
data
->
tmp
);
git_index_free
(
data
->
index
);
data
->
index
=
NULL
;
git_strmap_free
(
data
->
mkdir_map
);
git_attr_session__free
(
&
data
->
attr_session
);
}
static
int
checkout_data_init
(
...
...
@@ -2355,11 +2360,14 @@ static int checkout_data_init(
(
error
=
git_vector_init
(
&
data
->
update_conflicts
,
0
,
NULL
))
<
0
||
(
error
=
git_pool_init
(
&
data
->
pool
,
1
,
0
))
<
0
||
(
error
=
git_buf_puts
(
&
data
->
path
,
data
->
opts
.
target_directory
))
<
0
||
(
error
=
git_path_to_dir
(
&
data
->
path
))
<
0
)
(
error
=
git_path_to_dir
(
&
data
->
path
))
<
0
||
(
error
=
git_strmap_alloc
(
&
data
->
mkdir_map
))
<
0
)
goto
cleanup
;
data
->
workdir_len
=
git_buf_len
(
&
data
->
path
);
git_attr_session__init
(
&
data
->
attr_session
,
data
->
repo
);
cleanup
:
if
(
error
<
0
)
checkout_data_clear
(
data
);
...
...
src/fileops.c
View file @
d24a5312
...
...
@@ -7,11 +7,14 @@
#include "common.h"
#include "fileops.h"
#include "global.h"
#include "strmap.h"
#include <ctype.h>
#if GIT_WIN32
#include "win32/findfile.h"
#endif
GIT__USE_STRMAP
;
int
git_futils_mkpath2file
(
const
char
*
file_path
,
const
mode_t
mode
)
{
return
git_futils_mkdir
(
...
...
@@ -321,12 +324,12 @@ GIT_INLINE(int) validate_existing(
return
0
;
}
int
git_futils_mkdir_
withperf
(
int
git_futils_mkdir_
ext
(
const
char
*
path
,
const
char
*
base
,
mode_t
mode
,
uint32_t
flags
,
struct
git_futils_mkdir_
perfdata
*
perfdata
)
struct
git_futils_mkdir_
options
*
opts
)
{
int
error
=
-
1
;
git_buf
make_path
=
GIT_BUF_INIT
;
...
...
@@ -401,11 +404,14 @@ int git_futils_mkdir_withperf(
*
tail
=
'\0'
;
st
.
st_mode
=
0
;
if
(
opts
->
dir_map
&&
git_strmap_exists
(
opts
->
dir_map
,
make_path
.
ptr
))
continue
;
/* See what's going on with this path component */
perfdata
->
stat_calls
++
;
opts
->
perfdata
.
stat_calls
++
;
if
(
p_lstat
(
make_path
.
ptr
,
&
st
)
<
0
)
{
perfdata
->
mkdir_calls
++
;
opts
->
perfdata
.
mkdir_calls
++
;
if
(
errno
!=
ENOENT
||
p_mkdir
(
make_path
.
ptr
,
mode
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to make directory '%s'"
,
make_path
.
ptr
);
...
...
@@ -423,7 +429,7 @@ int git_futils_mkdir_withperf(
}
if
((
error
=
validate_existing
(
make_path
.
ptr
,
&
st
,
mode
,
flags
,
perfdata
))
<
0
)
make_path
.
ptr
,
&
st
,
mode
,
flags
,
&
opts
->
perfdata
))
<
0
)
goto
done
;
}
...
...
@@ -432,7 +438,7 @@ int git_futils_mkdir_withperf(
(
lastch
==
'\0'
&&
(
flags
&
GIT_MKDIR_CHMOD
)
!=
0
))
&&
st
.
st_mode
!=
mode
)
{
perfdata
->
chmod_calls
++
;
opts
->
perfdata
.
chmod_calls
++
;
if
((
error
=
p_chmod
(
make_path
.
ptr
,
mode
))
<
0
&&
lastch
==
'\0'
)
{
...
...
@@ -441,6 +447,17 @@ int git_futils_mkdir_withperf(
goto
done
;
}
}
if
(
opts
->
dir_map
&&
opts
->
pool
)
{
char
*
cache_path
=
git_pool_malloc
(
opts
->
pool
,
make_path
.
size
+
1
);
GITERR_CHECK_ALLOC
(
cache_path
);
memcpy
(
cache_path
,
make_path
.
ptr
,
make_path
.
size
+
1
);
git_strmap_insert
(
opts
->
dir_map
,
cache_path
,
cache_path
,
error
);
if
(
error
<
0
)
goto
done
;
}
}
error
=
0
;
...
...
@@ -448,7 +465,7 @@ int git_futils_mkdir_withperf(
/* check that full path really is a directory if requested & needed */
if
((
flags
&
GIT_MKDIR_VERIFY_DIR
)
!=
0
&&
lastch
!=
'\0'
)
{
perfdata
->
stat_calls
++
;
opts
->
perfdata
.
stat_calls
++
;
if
(
p_stat
(
make_path
.
ptr
,
&
st
)
<
0
||
!
S_ISDIR
(
st
.
st_mode
))
{
giterr_set
(
GITERR_OS
,
"Path is not a directory '%s'"
,
...
...
@@ -468,8 +485,8 @@ int git_futils_mkdir(
mode_t
mode
,
uint32_t
flags
)
{
struct
git_futils_mkdir_
perfdata
perfdata
=
{
0
};
return
git_futils_mkdir_
withperf
(
path
,
base
,
mode
,
flags
,
&
perfdata
);
struct
git_futils_mkdir_
options
options
=
{
0
};
return
git_futils_mkdir_
ext
(
path
,
base
,
mode
,
flags
,
&
options
);
}
int
git_futils_mkdir_r
(
const
char
*
path
,
const
char
*
base
,
const
mode_t
mode
)
...
...
src/fileops.h
View file @
d24a5312
...
...
@@ -11,6 +11,8 @@
#include "map.h"
#include "posix.h"
#include "path.h"
#include "pool.h"
#include "strmap.h"
/**
* Filebuffer methods
...
...
@@ -95,6 +97,13 @@ struct git_futils_mkdir_perfdata
size_t
chmod_calls
;
};
struct
git_futils_mkdir_options
{
git_strmap
*
dir_map
;
git_pool
*
pool
;
struct
git_futils_mkdir_perfdata
perfdata
;
};
/**
* Create a directory or entire path.
*
...
...
@@ -106,10 +115,10 @@ struct git_futils_mkdir_perfdata
* @param base Root for relative path. These directories will never be made.
* @param mode The mode to use for created directories.
* @param flags Combination of the mkdir flags above.
* @param
perfdata Performance data, use `git_futils_mkdir` if you don't want this data
.
* @param
opts Extended options, use `git_futils_mkdir` if you are not interested
.
* @return 0 on success, else error code
*/
extern
int
git_futils_mkdir_
withperf
(
const
char
*
path
,
const
char
*
base
,
mode_t
mode
,
uint32_t
flags
,
struct
git_futils_mkdir_perfdata
*
perfdata
);
extern
int
git_futils_mkdir_
ext
(
const
char
*
path
,
const
char
*
base
,
mode_t
mode
,
uint32_t
flags
,
struct
git_futils_mkdir_options
*
opts
);
/**
* Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
...
...
src/filter.c
View file @
d24a5312
...
...
@@ -394,15 +394,19 @@ static int filter_list_new(
}
static
int
filter_list_check_attributes
(
const
char
***
out
,
git_filter_def
*
fdef
,
const
git_filter_source
*
src
)
const
char
***
out
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_filter_def
*
fdef
,
const
git_filter_source
*
src
)
{
int
error
;
size_t
i
;
const
char
**
strs
=
git__calloc
(
fdef
->
nattrs
,
sizeof
(
const
char
*
));
GITERR_CHECK_ALLOC
(
strs
);
error
=
git_attr_get_many
(
strs
,
src
->
repo
,
0
,
src
->
path
,
fdef
->
nattrs
,
fdef
->
attrs
);
error
=
git_attr_get_many
_with_session
(
strs
,
repo
,
attr_session
,
0
,
src
->
path
,
fdef
->
nattrs
,
fdef
->
attrs
);
/* if no values were found but no matches are needed, it's okay! */
if
(
error
==
GIT_ENOTFOUND
&&
!
fdef
->
nmatches
)
{
...
...
@@ -448,9 +452,10 @@ int git_filter_list_new(
return
filter_list_new
(
out
,
&
src
);
}
int
git_filter_list_
load
(
int
git_filter_list_
_load_with_attr_session
(
git_filter_list
**
filters
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_blob
*
blob
,
/* can be NULL */
const
char
*
path
,
git_filter_mode_t
mode
,
...
...
@@ -481,7 +486,9 @@ int git_filter_list_load(
continue
;
if
(
fdef
->
nattrs
>
0
)
{
error
=
filter_list_check_attributes
(
&
values
,
fdef
,
&
src
);
error
=
filter_list_check_attributes
(
&
values
,
repo
,
attr_session
,
fdef
,
&
src
);
if
(
error
==
GIT_ENOTFOUND
)
{
error
=
0
;
continue
;
...
...
@@ -523,6 +530,18 @@ int git_filter_list_load(
return
error
;
}
int
git_filter_list_load
(
git_filter_list
**
filters
,
git_repository
*
repo
,
git_blob
*
blob
,
/* can be NULL */
const
char
*
path
,
git_filter_mode_t
mode
,
uint32_t
options
)
{
return
git_filter_list__load_with_attr_session
(
filters
,
repo
,
NULL
,
blob
,
path
,
mode
,
options
);
}
void
git_filter_list_free
(
git_filter_list
*
fl
)
{
uint32_t
i
;
...
...
src/filter.h
View file @
d24a5312
...
...
@@ -8,6 +8,7 @@
#define INCLUDE_filter_h__
#include "common.h"
#include "attr_file.h"
#include "git2/filter.h"
/* Amount of file to examine for NUL byte when checking binary-ness */
...
...
@@ -25,6 +26,15 @@ typedef enum {
extern
void
git_filter_free
(
git_filter
*
filter
);
extern
int
git_filter_list__load_with_attr_session
(
git_filter_list
**
filters
,
git_repository
*
repo
,
git_attr_session
*
attr_session
,
git_blob
*
blob
,
/* can be NULL */
const
char
*
path
,
git_filter_mode_t
mode
,
uint32_t
options
);
/*
* Available filters
*/
...
...
src/ignore.c
View file @
d24a5312
...
...
@@ -161,7 +161,7 @@ static int push_ignore_file(
git_attr_file
*
file
=
NULL
;
error
=
git_attr_cache__get
(
&
file
,
ignores
->
repo
,
GIT_ATTR_FILE__FROM_FILE
,
&
file
,
ignores
->
repo
,
NULL
,
GIT_ATTR_FILE__FROM_FILE
,
base
,
filename
,
parse_ignore_file
);
if
(
error
<
0
)
return
error
;
...
...
@@ -189,7 +189,7 @@ static int get_internal_ignores(git_attr_file **out, git_repository *repo)
return
error
;
error
=
git_attr_cache__get
(
out
,
repo
,
GIT_ATTR_FILE__IN_MEMORY
,
NULL
,
GIT_IGNORE_INTERNAL
,
NULL
);
out
,
repo
,
NULL
,
GIT_ATTR_FILE__IN_MEMORY
,
NULL
,
GIT_IGNORE_INTERNAL
,
NULL
);
/* if internal rules list is empty, insert default rules */
if
(
!
error
&&
!
(
*
out
)
->
rules
.
length
)
...
...
src/repository.h
View file @
d24a5312
...
...
@@ -133,6 +133,8 @@ struct git_repository {
has_8dot3_default
:
1
;
unsigned
int
lru_counter
;
git_atomic
attr_session_key
;
git_cvar_value
cvar_cache
[
GIT_CVAR_CACHE_MAX
];
};
...
...
tests/checkout/tree.c
View file @
d24a5312
...
...
@@ -1130,3 +1130,57 @@ void test_checkout_tree__can_collect_perfdata(void)
git_object_free
(
obj
);
}
void
update_attr_callback
(
const
char
*
path
,
size_t
completed_steps
,
size_t
total_steps
,
void
*
payload
)
{
GIT_UNUSED
(
completed_steps
);
GIT_UNUSED
(
total_steps
);
GIT_UNUSED
(
payload
);
if
(
path
&&
strcmp
(
path
,
"ident1.txt"
)
==
0
)
cl_git_write2file
(
"testrepo/.gitattributes"
,
"*.txt ident
\n
"
,
12
,
O_RDWR
|
O_CREAT
,
0666
);
}
void
test_checkout_tree__caches_attributes_during_checkout
(
void
)
{
git_checkout_options
opts
=
GIT_CHECKOUT_OPTIONS_INIT
;
git_oid
oid
;
git_object
*
obj
=
NULL
;
git_buf
ident1
=
GIT_BUF_INIT
,
ident2
=
GIT_BUF_INIT
;
char
*
ident_paths
[]
=
{
"ident1.txt"
,
"ident2.txt"
};
opts
.
progress_cb
=
update_attr_callback
;
assert_on_branch
(
g_repo
,
"master"
);
opts
.
checkout_strategy
=
GIT_CHECKOUT_FORCE
;
opts
.
paths
.
strings
=
ident_paths
;
opts
.
paths
.
count
=
2
;
cl_git_pass
(
git_reference_name_to_id
(
&
oid
,
g_repo
,
"refs/heads/ident"
));
cl_git_pass
(
git_object_lookup
(
&
obj
,
g_repo
,
&
oid
,
GIT_OBJ_ANY
));
cl_git_pass
(
git_checkout_tree
(
g_repo
,
obj
,
&
opts
));
cl_git_pass
(
git_futils_readbuffer
(
&
ident1
,
"testrepo/ident1.txt"
));
cl_git_pass
(
git_futils_readbuffer
(
&
ident2
,
"testrepo/ident2.txt"
));
cl_assert_equal_strn
(
ident1
.
ptr
,
"# $Id$"
,
6
);
cl_assert_equal_strn
(
ident2
.
ptr
,
"# $Id$"
,
6
);
cl_git_pass
(
git_checkout_tree
(
g_repo
,
obj
,
&
opts
));
cl_git_pass
(
git_futils_readbuffer
(
&
ident1
,
"testrepo/ident1.txt"
));
cl_git_pass
(
git_futils_readbuffer
(
&
ident2
,
"testrepo/ident2.txt"
));
cl_assert_equal_strn
(
ident1
.
ptr
,
"# $Id: "
,
7
);
cl_assert_equal_strn
(
ident2
.
ptr
,
"# $Id: "
,
7
);
git_buf_free
(
&
ident1
);
git_buf_free
(
&
ident2
);
git_object_free
(
obj
);
}
tests/refs/list.c
View file @
d24a5312
...
...
@@ -36,7 +36,7 @@ void test_refs_list__all(void)
/* We have exactly 12 refs in total if we include the packed ones:
* there is a reference that exists both in the packfile and as
* loose, but we only list it once */
cl_assert_equal_i
((
int
)
ref_list
.
count
,
1
4
);
cl_assert_equal_i
((
int
)
ref_list
.
count
,
1
5
);
git_strarray_free
(
&
ref_list
);
}
...
...
@@ -51,7 +51,7 @@ void test_refs_list__do_not_retrieve_references_which_name_end_with_a_lock_exten
"144344043ba4d4a405da03de3844aa829ae8be0e
\n
"
);
cl_git_pass
(
git_reference_list
(
&
ref_list
,
g_repo
));
cl_assert_equal_i
((
int
)
ref_list
.
count
,
1
4
);
cl_assert_equal_i
((
int
)
ref_list
.
count
,
1
5
);
git_strarray_free
(
&
ref_list
);
}
tests/repo/iterator.c
View file @
d24a5312
...
...
@@ -906,6 +906,7 @@ void test_repo_iterator__fs2(void)
static
const
char
*
expect_base
[]
=
{
"heads/br2"
,
"heads/dir"
,
"heads/ident"
,
"heads/long-file-name"
,
"heads/master"
,
"heads/packed-test"
,
...
...
@@ -923,7 +924,7 @@ void test_repo_iterator__fs2(void)
cl_git_pass
(
git_iterator_for_filesystem
(
&
i
,
"testrepo/.git/refs"
,
0
,
NULL
,
NULL
));
expect_iterator_items
(
i
,
1
2
,
expect_base
,
12
,
expect_base
);
expect_iterator_items
(
i
,
1
3
,
expect_base
,
13
,
expect_base
);
git_iterator_free
(
i
);
}
...
...
tests/resources/testrepo/.gitted/objects/6f/d5c7dd2ab27b48c493023f794be09861e9045f
0 → 100644
View file @
d24a5312
File added
tests/resources/testrepo/.gitted/objects/c3/6d8ea75da8cb510fcb0c408c1d7e53f9a99dbe
0 → 100644
View file @
d24a5312
File added
tests/resources/testrepo/.gitted/objects/e3/6900c3224db4adf4c7f7a09d4ac80247978a13
0 → 100644
View file @
d24a5312
File added
tests/resources/testrepo/.gitted/refs/heads/ident
0 → 100644
View file @
d24a5312
6fd5c7dd2ab27b48c493023f794be09861e9045f
tests/revwalk/basic.c
View file @
d24a5312
...
...
@@ -177,7 +177,7 @@ void test_revwalk_basic__glob_heads_with_invalid(void)
/* walking */
;
/* git log --branches --oneline | wc -l => 16 */
cl_assert_equal_i
(
1
7
,
i
);
cl_assert_equal_i
(
1
8
,
i
);
}
void
test_revwalk_basic__push_head
(
void
)
...
...
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