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
412293dc
Commit
412293dc
authored
Sep 11, 2012
by
Vicent Marti
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'diff-crlf-filters' into development
parents
5a409c44
c859184b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
458 additions
and
175 deletions
+458
-175
include/git2/diff.h
+53
-31
src/amiga/map.c
+4
-7
src/blob.c
+9
-10
src/crlf.c
+1
-1
src/diff.c
+22
-11
src/diff.h
+24
-0
src/diff_output.c
+0
-0
src/filebuf.c
+7
-2
src/fileops.c
+26
-22
src/fileops.h
+1
-0
src/object.c
+54
-44
src/object.h
+39
-0
src/odb.c
+62
-13
src/odb.h
+20
-5
src/repository.h
+2
-23
tests-clar/diff/diff_helpers.c
+5
-6
tests-clar/diff/diffiter.c
+85
-0
tests-clar/status/worktree.c
+44
-0
No files found.
include/git2/diff.h
View file @
412293dc
...
...
@@ -56,7 +56,13 @@ enum {
* values. Similarly, passing NULL for the options structure will
* give the defaults. The default values are marked below.
*
* @todo Most of the parameters here are not actually supported at this time.
* - flags: a combination of the GIT_DIFF_... values above
* - context_lines: number of lines of context to show around diffs
* - interhunk_lines: min lines between diff hunks to merge them
* - old_prefix: "directory" to prefix to old file names (default "a")
* - new_prefix: "directory" to prefix to new file names (default "b")
* - pathspec: array of paths / patterns to constrain diff
* - max_size: maximum blob size to diff, above this treated as binary
*/
typedef
struct
{
uint32_t
flags
;
/**< defaults to GIT_DIFF_NORMAL */
...
...
@@ -65,6 +71,7 @@ typedef struct {
char
*
old_prefix
;
/**< defaults to "a" */
char
*
new_prefix
;
/**< defaults to "b" */
git_strarray
pathspec
;
/**< defaults to show all paths */
git_off_t
max_size
;
/**< defaults to 512Mb */
}
git_diff_options
;
/**
...
...
@@ -72,13 +79,28 @@ typedef struct {
*/
typedef
struct
git_diff_list
git_diff_list
;
/**
* Flags that can be set for the file on side of a diff.
*
* Most of the flags are just for internal consumption by libgit2,
* but some of them may be interesting to external users. They are:
*
* - VALID_OID - the `oid` value is computed and correct
* - FREE_PATH - the `path` string is separated allocated memory
* - BINARY - this file should be considered binary data
* - NOT_BINARY - this file should be considered text data
* - FREE_DATA - the internal file data is kept in allocated memory
* - UNMAP_DATA - the internal file data is kept in mmap'ed memory
* - NO_DATA - this side of the diff should not be loaded
*/
enum
{
GIT_DIFF_FILE_VALID_OID
=
(
1
<<
0
),
GIT_DIFF_FILE_FREE_PATH
=
(
1
<<
1
),
GIT_DIFF_FILE_BINARY
=
(
1
<<
2
),
GIT_DIFF_FILE_NOT_BINARY
=
(
1
<<
3
),
GIT_DIFF_FILE_FREE_DATA
=
(
1
<<
4
),
GIT_DIFF_FILE_UNMAP_DATA
=
(
1
<<
5
)
GIT_DIFF_FILE_UNMAP_DATA
=
(
1
<<
5
),
GIT_DIFF_FILE_NO_DATA
=
(
1
<<
6
),
};
/**
...
...
@@ -169,7 +191,7 @@ enum {
GIT_DIFF_LINE_CONTEXT
=
' '
,
GIT_DIFF_LINE_ADDITION
=
'+'
,
GIT_DIFF_LINE_DELETION
=
'-'
,
GIT_DIFF_LINE_ADD_EOFNL
=
'\n'
,
/**<
DEPRECATED - will not be returned
*/
GIT_DIFF_LINE_ADD_EOFNL
=
'\n'
,
/**<
Removed line w/o LF & added one with
*/
GIT_DIFF_LINE_DEL_EOFNL
=
'\0'
,
/**< LF was removed at end of file */
/* The following values will only be sent to a `git_diff_data_fn` when
...
...
@@ -384,25 +406,16 @@ GIT_EXTERN(int) git_diff_iterator_new(
GIT_EXTERN
(
void
)
git_diff_iterator_free
(
git_diff_iterator
*
iterator
);
/**
* Return the number of files in the diff.
*
* Note that there is an uncommon scenario where this number might be too
* high -- if a file in the working directory has been "touched" on disk but
* the contents were then reverted, it might have been added to the
* `git_diff_list` as a MODIFIED file along with a note that the status
* needs to be confirmed when the file contents are loaded into memory. In
* that case, when the file is loaded, we will check the contents and might
* switch it back to UNMODIFIED. The loading of the file is deferred until
* as late as possible. As a result, this might return a value what was too
* high in those circumstances.
* Return progress value for traversing the diff.
*
* This is true of `git_diff_foreach` as well, but the only implication
* there is that the `progress` value would not advance evenly.
* This returns a value between 0.0 and 1.0 that represents the progress
* through the diff iterator. The value is monotonically increasing and
* will advance gradually as you progress through the iteration.
*
* @param iterator The
iterator object
* @return
The maximum number of files to be iterated over
* @param iterator The
diff iterator
* @return
Value between 0.0 and 1.0
*/
GIT_EXTERN
(
int
)
git_diff_iterator_num_file
s
(
git_diff_iterator
*
iterator
);
GIT_EXTERN
(
float
)
git_diff_iterator_progres
s
(
git_diff_iterator
*
iterator
);
/**
* Return the number of hunks in the current file
...
...
@@ -450,16 +463,19 @@ GIT_EXTERN(int) git_diff_iterator_next_file(
* It is recommended that you not call this if the file is a binary
* file, but it is allowed to do so.
*
* Warning! Call this function for the first time on a file is when the
* The `header` text output will contain the standard hunk header that
* would appear in diff output. The header string will be NUL terminated.
*
* WARNING! Call this function for the first time on a file is when the
* actual text diff will be computed (it cannot be computed incrementally)
* so the first call for a new file is expensive (at least in relative
* terms - in reality, it is still pretty darn fast).
*
* @param range
Pointer where to store the range for the hunk
*
@param header Pointer where to store the header for the chunk;
*
this string is owned by the library and should not be freed by
*
the user
* @param header_len
Pointer where to store the length of the returned header
* @param range
Output pointer to range of lines covered by the hunk;
*
This range object is owned by the library and should not be freed.
*
@param header Output pointer to the text of the hunk header
*
This string is owned by the library and should not be freed.
* @param header_len
Output pointer to store the length of the header text
* @param iterator The iterator object
* @return 0 on success, GIT_ITEROVER when done with current file, other
* value < 0 on error
...
...
@@ -473,12 +489,18 @@ GIT_EXTERN(int) git_diff_iterator_next_hunk(
/**
* Return the next line of the current hunk of diffs.
*
* @param line_origin Pointer where to store a GIT_DIFF_LINE_ value;
* this value is a single character, not a buffer
* @param content Pointer where to store the content of the line;
* this string is owned by the library and should not be freed by
* the user
* @param Pointer where to store the length of the returned content
* The `line_origin` output will tell you what type of line this is
* (e.g. was it added or removed or is it just context for the diff).
*
* The `content` will be a pointer to the file data that goes in the
* line. IT WILL NOT BE NUL TERMINATED. You have to use the `content_len`
* value and only process that many bytes of data from the content string.
*
* @param line_origin Output pointer to store a GIT_DIFF_LINE value for this
* next chunk of data. The value is a single character, not a buffer.
* @param content Output pointer to store the content of the diff; this
* string is owned by the library and should not be freed.
* @param content_len Output pointer to store the length of the content.
* @param iterator The iterator object
* @return 0 on success, GIT_ITEROVER when done with current line, other
* value < 0 on error
...
...
src/amiga/map.c
View file @
412293dc
...
...
@@ -24,18 +24,15 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
return
-
1
;
}
if
((
out
->
data
=
malloc
(
len
)))
{
p_lseek
(
fd
,
offset
,
SEEK_SET
);
p_read
(
fd
,
out
->
data
,
len
);
}
out
->
data
=
malloc
(
len
);
GITERR_CHECK_ALLOC
(
out
->
data
);
if
(
!
out
->
data
||
(
out
->
data
==
MAP_FAILED
))
{
giterr_set
(
GITERR_OS
,
"
Failed to mmap. Could not write data
"
);
if
(
p_lseek
(
fd
,
offset
,
SEEK_SET
)
<
0
||
p_read
(
fd
,
out
->
data
,
len
)
!=
len
)
giterr_set
(
GITERR_OS
,
"
mmap emulation failed
"
);
return
-
1
;
}
out
->
len
=
len
;
return
0
;
}
...
...
src/blob.c
View file @
412293dc
...
...
@@ -68,6 +68,7 @@ static int write_file_stream(
int
fd
,
error
;
char
buffer
[
4096
];
git_odb_stream
*
stream
=
NULL
;
ssize_t
read_len
,
written
=
0
;
if
((
error
=
git_odb_open_wstream
(
&
stream
,
odb
,
(
size_t
)
file_size
,
GIT_OBJ_BLOB
))
<
0
)
...
...
@@ -78,20 +79,18 @@ static int write_file_stream(
return
-
1
;
}
while
(
!
error
&&
file_size
>
0
)
{
ssize_t
read_len
=
p_read
(
fd
,
buffer
,
sizeof
(
buffer
));
if
(
read_len
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to create blob. Can't read whole file"
);
error
=
-
1
;
}
else
if
(
!
(
error
=
stream
->
write
(
stream
,
buffer
,
read_len
)))
file_size
-=
read_len
;
while
(
!
error
&&
(
read_len
=
p_read
(
fd
,
buffer
,
sizeof
(
buffer
)))
>
0
)
{
error
=
stream
->
write
(
stream
,
buffer
,
read_len
);
written
+=
read_len
;
}
p_close
(
fd
);
if
(
written
!=
file_size
||
read_len
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to read file into stream"
);
error
=
-
1
;
}
if
(
!
error
)
error
=
stream
->
finalize_write
(
oid
,
stream
);
...
...
src/crlf.c
View file @
412293dc
...
...
@@ -276,7 +276,7 @@ static int find_and_add_filter(git_vector *filters, git_repository *repo, const
/*
* Use the core Git logic to see if we should perform CRLF for this file
* based on its attributes & the value of `core.auto
_
crlf`
* based on its attributes & the value of `core.autocrlf`
*/
ca
.
crlf_action
=
crlf_input_action
(
&
ca
);
...
...
src/diff.c
View file @
412293dc
...
...
@@ -11,6 +11,7 @@
#include "fileops.h"
#include "config.h"
#include "attr_file.h"
#include "filter.h"
static
char
*
diff_prefix_from_pathspec
(
const
git_strarray
*
pathspec
)
{
...
...
@@ -63,8 +64,8 @@ static bool diff_path_matches_pathspec(git_diff_list *diff, const char *path)
git_vector_foreach
(
&
diff
->
pathspec
,
i
,
match
)
{
int
result
=
strcmp
(
match
->
pattern
,
path
)
?
FNM_NOMATCH
:
0
;
if
(((
diff
->
opts
.
flags
&
GIT_DIFF_DISABLE_PATHSPEC_MATCH
)
==
0
)
&&
if
(((
diff
->
opts
.
flags
&
GIT_DIFF_DISABLE_PATHSPEC_MATCH
)
==
0
)
&&
result
==
FNM_NOMATCH
)
result
=
p_fnmatch
(
match
->
pattern
,
path
,
0
);
...
...
@@ -262,12 +263,14 @@ static int diff_delta__from_two(
delta
=
diff_delta__alloc
(
diff
,
status
,
old_entry
->
path
);
GITERR_CHECK_ALLOC
(
delta
);
delta
->
old_file
.
mode
=
old_mode
;
git_oid_cpy
(
&
delta
->
old_file
.
oid
,
&
old_entry
->
oid
);
delta
->
old_file
.
size
=
old_entry
->
file_size
;
delta
->
old_file
.
mode
=
old_mode
;
delta
->
old_file
.
flags
|=
GIT_DIFF_FILE_VALID_OID
;
delta
->
new_file
.
mode
=
new_mode
;
git_oid_cpy
(
&
delta
->
new_file
.
oid
,
new_oid
?
new_oid
:
&
new_entry
->
oid
);
delta
->
new_file
.
size
=
new_entry
->
file_size
;
delta
->
new_file
.
mode
=
new_mode
;
if
(
new_oid
||
!
git_oid_iszero
(
&
new_entry
->
oid
))
delta
->
new_file
.
flags
|=
GIT_DIFF_FILE_VALID_OID
;
...
...
@@ -440,14 +443,22 @@ static int oid_for_workdir_item(
giterr_set
(
GITERR_OS
,
"File size overflow for 32-bit systems"
);
result
=
-
1
;
}
else
{
int
fd
=
git_futils_open_ro
(
full_path
.
ptr
);
if
(
fd
<
0
)
result
=
fd
;
else
{
result
=
git_odb__hashfd
(
oid
,
fd
,
(
size_t
)
item
->
file_size
,
GIT_OBJ_BLOB
);
p_close
(
fd
);
git_vector
filters
=
GIT_VECTOR_INIT
;
result
=
git_filters_load
(
&
filters
,
repo
,
item
->
path
,
GIT_FILTER_TO_ODB
);
if
(
result
>=
0
)
{
int
fd
=
git_futils_open_ro
(
full_path
.
ptr
);
if
(
fd
<
0
)
result
=
fd
;
else
{
result
=
git_odb__hashfd_filtered
(
oid
,
fd
,
(
size_t
)
item
->
file_size
,
GIT_OBJ_BLOB
,
&
filters
);
p_close
(
fd
);
}
}
git_filters_free
(
&
filters
);
}
git_buf_free
(
&
full_path
);
...
...
src/diff.h
View file @
412293dc
...
...
@@ -25,6 +25,8 @@ enum {
GIT_DIFFCAPS_USE_DEV
=
(
1
<<
4
),
/* use st_dev? */
};
#define MAX_DIFF_FILESIZE 0x20000000
struct
git_diff_list
{
git_refcount
rc
;
git_repository
*
repo
;
...
...
@@ -40,5 +42,27 @@ struct git_diff_list {
extern
void
git_diff__cleanup_modes
(
uint32_t
diffcaps
,
uint32_t
*
omode
,
uint32_t
*
nmode
);
/**
* Return the maximum possible number of files in the diff.
*
* NOTE: This number has to be treated as an upper bound on the number of
* files that have changed if the diff is with the working directory.
*
* Why?! For efficiency, we defer loading the file contents as long as
* possible, so if a file has been "touched" in the working directory and
* then reverted to the original content, it may get stored in the diff list
* as MODIFIED along with a flag that the status should be reconfirmed when
* it is actually loaded into memory. When that load happens, it could get
* flipped to UNMODIFIED. If unmodified files are being skipped, then the
* iterator will skip that file and this number may be too high.
*
* This behavior is true of `git_diff_foreach` as well, but the only
* implication there is that the `progress` value would not advance evenly.
*
* @param iterator The iterator object
* @return The maximum number of files to be iterated over
*/
int
git_diff_iterator__max_files
(
git_diff_iterator
*
iterator
);
#endif
src/diff_output.c
View file @
412293dc
This diff is collapsed.
Click to expand it.
src/filebuf.c
View file @
412293dc
...
...
@@ -73,7 +73,7 @@ static int lock_file(git_filebuf *file, int flags)
if
((
flags
&
GIT_FILEBUF_APPEND
)
&&
git_path_exists
(
file
->
path_original
)
==
true
)
{
git_file
source
;
char
buffer
[
2048
];
size_t
read_bytes
;
s
s
ize_t
read_bytes
;
source
=
p_open
(
file
->
path_original
,
O_RDONLY
);
if
(
source
<
0
)
{
...
...
@@ -83,13 +83,18 @@ static int lock_file(git_filebuf *file, int flags)
return
-
1
;
}
while
((
read_bytes
=
p_read
(
source
,
buffer
,
2048
))
>
0
)
{
while
((
read_bytes
=
p_read
(
source
,
buffer
,
sizeof
(
buffer
)
))
>
0
)
{
p_write
(
file
->
fd
,
buffer
,
read_bytes
);
if
(
file
->
digest
)
git_hash_update
(
file
->
digest
,
buffer
,
read_bytes
);
}
p_close
(
source
);
if
(
read_bytes
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to read file '%s'"
,
file
->
path_original
);
return
-
1
;
}
}
return
0
;
...
...
src/fileops.c
View file @
412293dc
...
...
@@ -115,10 +115,33 @@ mode_t git_futils_canonical_mode(mode_t raw_mode)
return
0
;
}
int
git_futils_readbuffer_updated
(
git_buf
*
buf
,
const
char
*
path
,
time_t
*
mtime
,
int
*
updated
)
int
git_futils_readbuffer_fd
(
git_buf
*
buf
,
git_file
fd
,
size_t
len
)
{
ssize_t
read_size
;
git_buf_clear
(
buf
);
if
(
git_buf_grow
(
buf
,
len
+
1
)
<
0
)
return
-
1
;
/* p_read loops internally to read len bytes */
read_size
=
p_read
(
fd
,
buf
->
ptr
,
len
);
if
(
read_size
!=
(
ssize_t
)
len
)
{
giterr_set
(
GITERR_OS
,
"Failed to read descriptor"
);
return
-
1
;
}
buf
->
ptr
[
read_size
]
=
'\0'
;
buf
->
size
=
read_size
;
return
0
;
}
int
git_futils_readbuffer_updated
(
git_buf
*
buf
,
const
char
*
path
,
time_t
*
mtime
,
int
*
updated
)
{
git_file
fd
;
size_t
len
;
struct
stat
st
;
assert
(
buf
&&
path
&&
*
path
);
...
...
@@ -147,30 +170,11 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime,
if
(
mtime
!=
NULL
)
*
mtime
=
st
.
st_mtime
;
len
=
(
size_t
)
st
.
st_size
;
git_buf_clear
(
buf
);
if
(
git_buf_grow
(
buf
,
len
+
1
)
<
0
)
{
if
(
git_futils_readbuffer_fd
(
buf
,
fd
,
(
size_t
)
st
.
st_size
)
<
0
)
{
p_close
(
fd
);
return
-
1
;
}
buf
->
ptr
[
len
]
=
'\0'
;
while
(
len
>
0
)
{
ssize_t
read_size
=
p_read
(
fd
,
buf
->
ptr
,
len
);
if
(
read_size
<
0
)
{
p_close
(
fd
);
giterr_set
(
GITERR_OS
,
"Failed to read descriptor for '%s'"
,
path
);
return
-
1
;
}
len
-=
read_size
;
buf
->
size
+=
read_size
;
}
p_close
(
fd
);
if
(
updated
!=
NULL
)
...
...
src/fileops.h
View file @
412293dc
...
...
@@ -19,6 +19,7 @@
*/
extern
int
git_futils_readbuffer
(
git_buf
*
obj
,
const
char
*
path
);
extern
int
git_futils_readbuffer_updated
(
git_buf
*
obj
,
const
char
*
path
,
time_t
*
mtime
,
int
*
updated
);
extern
int
git_futils_readbuffer_fd
(
git_buf
*
obj
,
git_file
fd
,
size_t
len
);
/**
* File utils
...
...
src/object.c
View file @
412293dc
...
...
@@ -77,6 +77,58 @@ static int create_object(git_object **object_out, git_otype type)
return
0
;
}
int
git_object__from_odb_object
(
git_object
**
object_out
,
git_repository
*
repo
,
git_odb_object
*
odb_obj
,
git_otype
type
)
{
int
error
;
git_object
*
object
=
NULL
;
if
(
type
!=
GIT_OBJ_ANY
&&
type
!=
odb_obj
->
raw
.
type
)
{
giterr_set
(
GITERR_ODB
,
"The requested type does not match the type in the ODB"
);
return
GIT_ENOTFOUND
;
}
type
=
odb_obj
->
raw
.
type
;
if
((
error
=
create_object
(
&
object
,
type
))
<
0
)
return
error
;
/* Initialize parent object */
git_oid_cpy
(
&
object
->
cached
.
oid
,
&
odb_obj
->
cached
.
oid
);
object
->
repo
=
repo
;
switch
(
type
)
{
case
GIT_OBJ_COMMIT
:
error
=
git_commit__parse
((
git_commit
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_TREE
:
error
=
git_tree__parse
((
git_tree
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_TAG
:
error
=
git_tag__parse
((
git_tag
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_BLOB
:
error
=
git_blob__parse
((
git_blob
*
)
object
,
odb_obj
);
break
;
default:
break
;
}
if
(
error
<
0
)
git_object__free
(
object
);
else
*
object_out
=
git_cache_try_store
(
&
repo
->
objects
,
object
);
return
error
;
}
int
git_object_lookup_prefix
(
git_object
**
object_out
,
git_repository
*
repo
,
...
...
@@ -148,53 +200,11 @@ int git_object_lookup_prefix(
if
(
error
<
0
)
return
error
;
if
(
type
!=
GIT_OBJ_ANY
&&
type
!=
odb_obj
->
raw
.
type
)
{
git_odb_object_free
(
odb_obj
);
giterr_set
(
GITERR_ODB
,
"The given type does not match the type on the ODB"
);
return
GIT_ENOTFOUND
;
}
type
=
odb_obj
->
raw
.
type
;
if
(
create_object
(
&
object
,
type
)
<
0
)
{
git_odb_object_free
(
odb_obj
);
return
-
1
;
}
/* Initialize parent object */
git_oid_cpy
(
&
object
->
cached
.
oid
,
&
odb_obj
->
cached
.
oid
);
object
->
repo
=
repo
;
switch
(
type
)
{
case
GIT_OBJ_COMMIT
:
error
=
git_commit__parse
((
git_commit
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_TREE
:
error
=
git_tree__parse
((
git_tree
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_TAG
:
error
=
git_tag__parse
((
git_tag
*
)
object
,
odb_obj
);
break
;
case
GIT_OBJ_BLOB
:
error
=
git_blob__parse
((
git_blob
*
)
object
,
odb_obj
);
break
;
default:
break
;
}
error
=
git_object__from_odb_object
(
object_out
,
repo
,
odb_obj
,
type
);
git_odb_object_free
(
odb_obj
);
if
(
error
<
0
)
{
git_object__free
(
object
);
return
-
1
;
}
*
object_out
=
git_cache_try_store
(
&
repo
->
objects
,
object
);
return
0
;
return
error
;
}
int
git_object_lookup
(
git_object
**
object_out
,
git_repository
*
repo
,
const
git_oid
*
id
,
git_otype
type
)
{
...
...
src/object.h
0 → 100644
View file @
412293dc
/*
* Copyright (C) 2009-2012 the libgit2 contributors
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_object_h__
#define INCLUDE_object_h__
/** Base git object for inheritance */
struct
git_object
{
git_cached_obj
cached
;
git_repository
*
repo
;
git_otype
type
;
};
/* fully free the object; internal method, DO NOT EXPORT */
void
git_object__free
(
void
*
object
);
GIT_INLINE
(
int
)
git_object__dup
(
git_object
**
dest
,
git_object
*
source
)
{
git_cached_obj_incref
(
source
);
*
dest
=
source
;
return
0
;
}
int
git_object__from_odb_object
(
git_object
**
object_out
,
git_repository
*
repo
,
git_odb_object
*
odb_obj
,
git_otype
type
);
int
git_object__resolve_to_type
(
git_object
**
obj
,
git_otype
type
);
int
git_oid__parse
(
git_oid
*
oid
,
const
char
**
buffer_out
,
const
char
*
buffer_end
,
const
char
*
header
);
void
git_oid__writebuf
(
git_buf
*
buf
,
const
char
*
header
,
const
git_oid
*
oid
);
#endif
src/odb.c
View file @
412293dc
...
...
@@ -12,6 +12,7 @@
#include "hash.h"
#include "odb.h"
#include "delta-apply.h"
#include "filter.h"
#include "git2/odb_backend.h"
#include "git2/oid.h"
...
...
@@ -114,32 +115,62 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
int
hdr_len
;
char
hdr
[
64
],
buffer
[
2048
];
git_hash_ctx
*
ctx
;
ssize_t
read_len
;
hdr_len
=
format_object_header
(
hdr
,
sizeof
(
hdr
),
size
,
type
);
ctx
=
git_hash_new_ctx
();
GITERR_CHECK_ALLOC
(
ctx
);
git_hash_update
(
ctx
,
hdr
,
hdr_len
);
while
(
size
>
0
)
{
ssize_t
read_len
=
read
(
fd
,
buffer
,
sizeof
(
buffer
));
if
(
read_len
<
0
)
{
git_hash_free_ctx
(
ctx
);
giterr_set
(
GITERR_OS
,
"Error reading file"
);
return
-
1
;
}
while
(
size
>
0
&&
(
read_len
=
p_read
(
fd
,
buffer
,
sizeof
(
buffer
)))
>
0
)
{
git_hash_update
(
ctx
,
buffer
,
read_len
);
size
-=
read_len
;
}
/* If p_read returned an error code, the read obviously failed.
* If size is not zero, the file was truncated after we originally
* stat'd it, so we consider this a read failure too */
if
(
read_len
<
0
||
size
>
0
)
{
git_hash_free_ctx
(
ctx
);
giterr_set
(
GITERR_OS
,
"Error reading file for hashing"
);
return
-
1
;
}
git_hash_final
(
out
,
ctx
);
git_hash_free_ctx
(
ctx
);
return
0
;
}
int
git_odb__hashfd_filtered
(
git_oid
*
out
,
git_file
fd
,
size_t
size
,
git_otype
type
,
git_vector
*
filters
)
{
int
error
;
git_buf
raw
=
GIT_BUF_INIT
;
git_buf
filtered
=
GIT_BUF_INIT
;
if
(
!
filters
||
!
filters
->
length
)
return
git_odb__hashfd
(
out
,
fd
,
size
,
type
);
/* size of data is used in header, so we have to read the whole file
* into memory to apply filters before beginning to calculate the hash
*/
if
(
!
(
error
=
git_futils_readbuffer_fd
(
&
raw
,
fd
,
size
)))
error
=
git_filters_apply
(
&
filtered
,
&
raw
,
filters
);
git_buf_free
(
&
raw
);
if
(
!
error
)
error
=
git_odb_hash
(
out
,
filtered
.
ptr
,
filtered
.
size
,
type
);
git_buf_free
(
&
filtered
);
return
error
;
}
int
git_odb__hashlink
(
git_oid
*
out
,
const
char
*
path
)
{
struct
stat
st
;
...
...
@@ -171,7 +202,7 @@ int git_odb__hashlink(git_oid *out, const char *path)
result
=
git_odb_hash
(
out
,
link_data
,
(
size_t
)
size
,
GIT_OBJ_BLOB
);
git__free
(
link_data
);
}
else
{
}
else
{
int
fd
=
git_futils_open_ro
(
path
);
if
(
fd
<
0
)
return
-
1
;
...
...
@@ -485,19 +516,36 @@ int git_odb_exists(git_odb *db, const git_oid *id)
int
git_odb_read_header
(
size_t
*
len_p
,
git_otype
*
type_p
,
git_odb
*
db
,
const
git_oid
*
id
)
{
int
error
;
git_odb_object
*
object
;
error
=
git_odb__read_header_or_object
(
&
object
,
len_p
,
type_p
,
db
,
id
);
if
(
object
)
git_odb_object_free
(
object
);
return
error
;
}
int
git_odb__read_header_or_object
(
git_odb_object
**
out
,
size_t
*
len_p
,
git_otype
*
type_p
,
git_odb
*
db
,
const
git_oid
*
id
)
{
unsigned
int
i
;
int
error
=
GIT_ENOTFOUND
;
git_odb_object
*
object
;
assert
(
db
&&
id
);
assert
(
db
&&
id
&&
out
&&
len_p
&&
type_p
);
if
((
object
=
git_cache_get
(
&
db
->
cache
,
id
))
!=
NULL
)
{
*
len_p
=
object
->
raw
.
len
;
*
type_p
=
object
->
raw
.
type
;
git_odb_object_free
(
object
)
;
*
out
=
object
;
return
0
;
}
*
out
=
NULL
;
for
(
i
=
0
;
i
<
db
->
backends
.
length
&&
error
<
0
;
++
i
)
{
backend_internal
*
internal
=
git_vector_get
(
&
db
->
backends
,
i
);
git_odb_backend
*
b
=
internal
->
backend
;
...
...
@@ -518,7 +566,8 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git
*
len_p
=
object
->
raw
.
len
;
*
type_p
=
object
->
raw
.
type
;
git_odb_object_free
(
object
);
*
out
=
object
;
return
0
;
}
...
...
src/odb.h
View file @
412293dc
...
...
@@ -58,12 +58,19 @@ int git_odb__hashobj(git_oid *id, git_rawobj *obj);
int
git_odb__hashfd
(
git_oid
*
out
,
git_file
fd
,
size_t
size
,
git_otype
type
);
/*
* Hash a `path`, assuming it could be a POSIX symlink: if the path is a symlink,
* then the raw contents of the symlink will be hashed. Otherwise, this will
* fallback to `git_odb__hashfd`.
* Hash an open file descriptor applying an array of filters
* Acts just like git_odb__hashfd with the addition of filters...
*/
int
git_odb__hashfd_filtered
(
git_oid
*
out
,
git_file
fd
,
size_t
len
,
git_otype
type
,
git_vector
*
filters
);
/*
* Hash a `path`, assuming it could be a POSIX symlink: if the path is a
* symlink, then the raw contents of the symlink will be hashed. Otherwise,
* this will fallback to `git_odb__hashfd`.
*
* The hash type for this call is always `GIT_OBJ_BLOB` because symlinks may
only
* point to blobs.
* The hash type for this call is always `GIT_OBJ_BLOB` because symlinks may
*
only
point to blobs.
*/
int
git_odb__hashlink
(
git_oid
*
out
,
const
char
*
path
);
...
...
@@ -77,4 +84,12 @@ int git_odb__error_notfound(const char *message, const git_oid *oid);
*/
int
git_odb__error_ambiguous
(
const
char
*
message
);
/*
* Attempt to read object header or just return whole object if it could
* not be read.
*/
int
git_odb__read_header_or_object
(
git_odb_object
**
out
,
size_t
*
len_p
,
git_otype
*
type_p
,
git_odb
*
db
,
const
git_oid
*
id
);
#endif
src/repository.h
View file @
412293dc
...
...
@@ -18,6 +18,7 @@
#include "refs.h"
#include "buffer.h"
#include "odb.h"
#include "object.h"
#include "attr.h"
#include "strmap.h"
...
...
@@ -75,13 +76,6 @@ enum {
GIT_REPOSITORY_INIT__IS_REINIT
=
(
1u
<<
18
),
};
/** Base git object for inheritance */
struct
git_object
{
git_cached_obj
cached
;
git_repository
*
repo
;
git_otype
type
;
};
/** Internal structure for repository object */
struct
git_repository
{
git_odb
*
_odb
;
...
...
@@ -102,21 +96,6 @@ struct git_repository {
git_cvar_value
cvar_cache
[
GIT_CVAR_CACHE_MAX
];
};
/* fully free the object; internal method, DO NOT EXPORT */
void
git_object__free
(
void
*
object
);
GIT_INLINE
(
int
)
git_object__dup
(
git_object
**
dest
,
git_object
*
source
)
{
git_cached_obj_incref
(
source
);
*
dest
=
source
;
return
0
;
}
int
git_object__resolve_to_type
(
git_object
**
obj
,
git_otype
type
);
int
git_oid__parse
(
git_oid
*
oid
,
const
char
**
buffer_out
,
const
char
*
buffer_end
,
const
char
*
header
);
void
git_oid__writebuf
(
git_buf
*
buf
,
const
char
*
header
,
const
git_oid
*
oid
);
GIT_INLINE
(
git_attr_cache
*
)
git_repository_attr_cache
(
git_repository
*
repo
)
{
return
&
repo
->
attrcache
;
...
...
@@ -136,7 +115,7 @@ int git_repository_odb__weakptr(git_odb **out, git_repository *repo);
int
git_repository_index__weakptr
(
git_index
**
out
,
git_repository
*
repo
);
/*
* CVAR cache
* CVAR cache
*
* Efficient access to the most used config variables of a repository.
* The cache is cleared everytime the config backend is replaced.
...
...
tests-clar/diff/diff_helpers.c
View file @
412293dc
...
...
@@ -89,7 +89,8 @@ int diff_line_fn(
e
->
line_adds
++
;
break
;
case
GIT_DIFF_LINE_ADD_EOFNL
:
assert
(
0
);
/* technically not a line add, but we'll count it as such */
e
->
line_adds
++
;
break
;
case
GIT_DIFF_LINE_DELETION
:
e
->
line_dels
++
;
...
...
@@ -111,23 +112,21 @@ int diff_foreach_via_iterator(
git_diff_hunk_fn
hunk_cb
,
git_diff_data_fn
line_cb
)
{
int
error
,
curr
,
total
;
int
error
;
git_diff_iterator
*
iter
;
git_diff_delta
*
delta
;
if
((
error
=
git_diff_iterator_new
(
&
iter
,
diff
))
<
0
)
return
error
;
curr
=
0
;
total
=
git_diff_iterator_num_files
(
iter
);
while
(
!
(
error
=
git_diff_iterator_next_file
(
&
delta
,
iter
)))
{
git_diff_range
*
range
;
const
char
*
hdr
;
size_t
hdr_len
;
float
progress
=
git_diff_iterator_progress
(
iter
);
/* call file_cb for this file */
if
(
file_cb
!=
NULL
&&
file_cb
(
data
,
delta
,
(
float
)
curr
/
total
)
!=
0
)
if
(
file_cb
!=
NULL
&&
file_cb
(
data
,
delta
,
progress
)
!=
0
)
goto
abort
;
if
(
!
hunk_cb
&&
!
line_cb
)
...
...
tests-clar/diff/diffiter.c
View file @
412293dc
...
...
@@ -114,3 +114,88 @@ void test_diff_diffiter__iterate_files_and_hunks(void)
git_diff_iterator_free
(
iter
);
git_diff_list_free
(
diff
);
}
void
test_diff_diffiter__max_size_threshold
(
void
)
{
git_repository
*
repo
=
cl_git_sandbox_init
(
"status"
);
git_diff_options
opts
=
{
0
};
git_diff_list
*
diff
=
NULL
;
git_diff_iterator
*
iter
;
git_diff_delta
*
delta
;
int
error
,
file_count
=
0
,
binary_count
=
0
,
hunk_count
=
0
;
opts
.
context_lines
=
3
;
opts
.
interhunk_lines
=
1
;
opts
.
flags
|=
GIT_DIFF_INCLUDE_IGNORED
|
GIT_DIFF_INCLUDE_UNTRACKED
;
cl_git_pass
(
git_diff_workdir_to_index
(
repo
,
&
opts
,
&
diff
));
cl_git_pass
(
git_diff_iterator_new
(
&
iter
,
diff
));
while
((
error
=
git_diff_iterator_next_file
(
&
delta
,
iter
))
!=
GIT_ITEROVER
)
{
cl_assert_equal_i
(
0
,
error
);
cl_assert
(
delta
);
file_count
++
;
hunk_count
+=
git_diff_iterator_num_hunks_in_file
(
iter
);
assert
(
delta
->
binary
==
0
||
delta
->
binary
==
1
);
binary_count
+=
delta
->
binary
;
}
cl_assert_equal_i
(
GIT_ITEROVER
,
error
);
cl_assert
(
delta
==
NULL
);
cl_assert_equal_i
(
13
,
file_count
);
cl_assert_equal_i
(
0
,
binary_count
);
cl_assert_equal_i
(
8
,
hunk_count
);
git_diff_iterator_free
(
iter
);
git_diff_list_free
(
diff
);
/* try again with low file size threshold */
file_count
=
0
;
binary_count
=
0
;
hunk_count
=
0
;
opts
.
context_lines
=
3
;
opts
.
interhunk_lines
=
1
;
opts
.
flags
|=
GIT_DIFF_INCLUDE_IGNORED
|
GIT_DIFF_INCLUDE_UNTRACKED
;
opts
.
max_size
=
50
;
/* treat anything over 50 bytes as binary! */
cl_git_pass
(
git_diff_workdir_to_index
(
repo
,
&
opts
,
&
diff
));
cl_git_pass
(
git_diff_iterator_new
(
&
iter
,
diff
));
while
((
error
=
git_diff_iterator_next_file
(
&
delta
,
iter
))
!=
GIT_ITEROVER
)
{
cl_assert_equal_i
(
0
,
error
);
cl_assert
(
delta
);
file_count
++
;
hunk_count
+=
git_diff_iterator_num_hunks_in_file
(
iter
);
assert
(
delta
->
binary
==
0
||
delta
->
binary
==
1
);
binary_count
+=
delta
->
binary
;
}
cl_assert_equal_i
(
GIT_ITEROVER
,
error
);
cl_assert
(
delta
==
NULL
);
cl_assert_equal_i
(
13
,
file_count
);
/* Three files are over the 50 byte threshold:
* - staged_changes_file_deleted
* - staged_changes_modified_file
* - staged_new_file_modified_file
*/
cl_assert_equal_i
(
3
,
binary_count
);
cl_assert_equal_i
(
5
,
hunk_count
);
git_diff_iterator_free
(
iter
);
git_diff_list_free
(
diff
);
}
tests-clar/status/worktree.c
View file @
412293dc
...
...
@@ -797,3 +797,47 @@ void test_status_worktree__interruptable_foreach(void)
cl_assert_equal_i
(
8
,
count
);
}
void
test_status_worktree__new_staged_file_must_handle_crlf
(
void
)
{
git_repository
*
repo
;
git_index
*
index
;
git_config
*
config
;
unsigned
int
status
;
cl_git_pass
(
git_repository_init
(
&
repo
,
"getting_started"
,
0
));
// Ensure that repo has core.autocrlf=true
cl_git_pass
(
git_repository_config
(
&
config
,
repo
));
cl_git_pass
(
git_config_set_bool
(
config
,
"core.autocrlf"
,
true
));
cl_git_mkfile
(
"getting_started/testfile.txt"
,
"content
\r\n
"
);
// Content with CRLF
cl_git_pass
(
git_repository_index
(
&
index
,
repo
));
cl_git_pass
(
git_index_add
(
index
,
"testfile.txt"
,
0
));
cl_git_pass
(
git_index_write
(
index
));
cl_git_pass
(
git_status_file
(
&
status
,
repo
,
"testfile.txt"
));
cl_assert_equal_i
(
GIT_STATUS_INDEX_NEW
,
status
);
git_config_free
(
config
);
git_index_free
(
index
);
git_repository_free
(
repo
);
}
void
test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf
(
void
)
{
git_repository
*
repo
=
cl_git_sandbox_init
(
"status"
);
git_config
*
config
;
unsigned
int
status
;
cl_git_pass
(
git_repository_config
(
&
config
,
repo
));
cl_git_pass
(
git_config_set_bool
(
config
,
"core.autocrlf"
,
true
));
git_config_free
(
config
);
cl_git_rewritefile
(
"status/current_file"
,
"current_file
\r\n
"
);
cl_git_pass
(
git_status_file
(
&
status
,
repo
,
"current_file"
));
cl_assert_equal_i
(
GIT_STATUS_CURRENT
,
status
);
}
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