Commit 272b462d by Vicent Marti

Merge pull request #2308 from libgit2/rb/diff-update-index-stat-cache

Reduce excessive OID calculation for diff and stat
parents 9862ef8e 99dfa470
......@@ -83,17 +83,16 @@ typedef struct git_blame_options {
#define GIT_BLAME_OPTIONS_INIT {GIT_BLAME_OPTIONS_VERSION}
/**
* Initializes a `git_blame_options` with default values. Equivalent to
* creating an instance with GIT_BLAME_OPTIONS_INIT.
*
* @param opts the `git_blame_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_BLAME_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
* Initializes a `git_blame_options` with default values. Equivalent to
* creating an instance with GIT_BLAME_OPTIONS_INIT.
*
* @param opts The `git_blame_options` struct to initialize
* @param version Version of struct; pass `GIT_BLAME_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_blame_init_options(
git_blame_options* opts,
int version);
git_blame_options *opts,
unsigned int version);
/**
* Structure that represents a blame hunk.
......
......@@ -270,14 +270,13 @@ typedef struct git_checkout_options {
* Initializes a `git_checkout_options` with default values. Equivalent to
* creating an instance with GIT_CHECKOUT_OPTIONS_INIT.
*
* @param opts the `git_checkout_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_CHECKOUT_OPTIONS_VERSION` here.
* @param opts the `git_checkout_options` struct to initialize.
* @param version Version of struct; pass `GIT_CHECKOUT_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_checkout_init_opts(
git_checkout_options* opts,
int version);
GIT_EXTERN(int) git_checkout_init_options(
git_checkout_options *opts,
unsigned int version);
/**
* Updates files in the index and the working tree to match the content of
......
......@@ -37,14 +37,13 @@ typedef struct {
* Initializes a `git_cherry_pick_options` with default values. Equivalent to
* creating an instance with GIT_CHERRY_PICK_OPTIONS_INIT.
*
* @param opts the `git_cherry_pick_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_CHERRY_PICK_OPTIONS_VERSION` here.
* @param opts the `git_cherry_pick_options` struct to initialize
* @param version Version of struct; pass `GIT_CHERRY_PICK_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_cherry_pick_init_opts(
git_cherry_pick_options* opts,
int version);
GIT_EXTERN(int) git_cherry_pick_init_options(
git_cherry_pick_options *opts,
unsigned int version);
/**
* Cherry-picks the given commit against the given "our" commit, producing an
......
......@@ -66,17 +66,16 @@ typedef struct git_clone_options {
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTIONS_VERSION, GIT_CHECKOUT_SAFE_CREATE}, GIT_REMOTE_CALLBACKS_INIT}
/**
* Initializes a `git_clone_options` with default values. Equivalent to
* creating an instance with GIT_CLONE_OPTIONS_INIT.
*
* @param opts the `git_clone_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_CLONE_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
* Initializes a `git_clone_options` with default values. Equivalent to
* creating an instance with GIT_CLONE_OPTIONS_INIT.
*
* @param opts The `git_clone_options` struct to initialize
* @param version Version of struct; pass `GIT_CLONE_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_clone_init_options(
git_clone_options* opts,
int version);
git_clone_options *opts,
unsigned int version);
/**
* Clone a remote repository.
......
......@@ -145,6 +145,13 @@ typedef enum {
*/
GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS = (1u << 14),
/** When diff finds a file in the working directory with stat
* information different from the index, but the OID ends up being the
* same, write the correct stat information into the index. Note:
* without this flag, diff will always leave the index untouched.
*/
GIT_DIFF_UPDATE_INDEX = (1u << 15),
/*
* Options controlling how output will be generated
*/
......@@ -381,17 +388,16 @@ typedef struct {
{GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_DEFAULT, {NULL,0}, NULL, NULL, 3}
/**
* Initializes a `git_diff_options` with default values. Equivalent to
* creating an instance with GIT_DIFF_OPTIONS_INIT.
*
* @param opts the `git_diff_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_DIFF_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
* Initializes a `git_diff_options` with default values. Equivalent to
* creating an instance with GIT_DIFF_OPTIONS_INIT.
*
* @param opts The `git_diff_options` struct to initialize
* @param version Version of struct; pass `GIT_DIFF_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_diff_init_options(
git_diff_options* opts,
int version);
git_diff_options *opts,
unsigned int version);
/**
* When iterating over a diff, callback that will be made per file.
......@@ -622,17 +628,16 @@ typedef struct {
#define GIT_DIFF_FIND_OPTIONS_INIT {GIT_DIFF_FIND_OPTIONS_VERSION}
/**
* Initializes a `git_diff_find_options` with default values. Equivalent to
* creating an instance with GIT_DIFF_FIND_OPTIONS_INIT.
*
* @param opts the `git_diff_find_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_DIFF_FIND_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
* Initializes a `git_diff_find_options` with default values. Equivalent to
* creating an instance with GIT_DIFF_FIND_OPTIONS_INIT.
*
* @param opts The `git_diff_find_options` struct to initialize
* @param version Version of struct; pass `GIT_DIFF_FIND_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_diff_find_init_options(
git_diff_find_options* opts,
int version);
git_diff_find_options *opts,
unsigned int version);
/** @name Diff Generator Functions
*
......@@ -804,23 +809,6 @@ GIT_EXTERN(int) git_diff_find_similar(
git_diff *diff,
const git_diff_find_options *options);
/**
* Initialize diff options structure
*
* In most cases, you can probably just use `GIT_DIFF_OPTIONS_INIT` to
* initialize the diff options structure, but in some cases that is not
* going to work. You can call this function instead. Note that you
* must pass both a pointer to the structure to be initialized and the
* `GIT_DIFF_OPTIONS_VERSION` value from the header you compiled with.
*
* @param options Pointer to git_diff_options memory to be initialized
* @param version Should be `GIT_DIFF_OPTIONS_VERSION`
* @return 0 on success, negative on failure (such as unsupported version)
*/
GIT_EXTERN(int) git_diff_options_init(
git_diff_options *options,
unsigned int version);
/**@}*/
......@@ -1233,17 +1221,17 @@ GIT_EXTERN(int) git_diff_commit_as_email(
const git_diff_options *diff_opts);
/**
* Initializes a `git_diff_format_email_options` with default values. Equivalent to
* creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
*
* @param opts the `git_diff_format_email_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION` here.
* @return Zero on success; -1 on failure.
*/
* Initializes a `git_diff_format_email_options` with default values.
*
* Equivalent to creating an instance with GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT.
*
* @param opts The `git_diff_format_email_options` struct to initialize
* @param version Version of struct; pass `GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_diff_format_email_init_options(
git_diff_format_email_options *opts,
int version);
unsigned int version);
GIT_END_DECL
......
......@@ -61,7 +61,7 @@ typedef struct git_index_entry {
unsigned short flags;
unsigned short flags_extended;
char *path;
const char *path;
} git_index_entry;
/**
......
......@@ -57,7 +57,7 @@ typedef struct {
*/
GIT_EXTERN(int) git_merge_file_init_input(
git_merge_file_input *opts,
int version);
unsigned int version);
/**
* Flags for `git_merge_tree` options. A combination of these flags can be
......@@ -164,7 +164,7 @@ typedef struct {
*/
GIT_EXTERN(int) git_merge_file_init_options(
git_merge_file_options *opts,
int version);
unsigned int version);
typedef struct {
/**
......@@ -232,7 +232,7 @@ typedef struct {
*/
GIT_EXTERN(int) git_merge_init_options(
git_merge_options *opts,
int version);
unsigned int version);
/**
* The results of `git_merge_analysis` indicate the merge opportunities.
......
......@@ -49,8 +49,8 @@ typedef struct {
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_push_init_options(
git_push_options* opts,
int version);
git_push_options *opts,
unsigned int version);
/** Push network progress notification function */
typedef int (*git_push_transfer_progress)(
......
......@@ -501,14 +501,13 @@ struct git_remote_callbacks {
* Initializes a `git_remote_callbacks` with default values. Equivalent to
* creating an instance with GIT_REMOTE_CALLBACKS_INIT.
*
* @param opts the `git_remote_callbacks` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_REMOTE_CALLBACKS_VERSION` here.
* @param opts the `git_remote_callbacks` struct to initialize
* @param version Version of struct; pass `GIT_REMOTE_CALLBACKS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_remote_init_callbacks(
git_remote_callbacks* opts,
int version);
git_remote_callbacks *opts,
unsigned int version);
/**
* Set the callbacks for a remote
......
......@@ -271,14 +271,13 @@ typedef struct {
* Initializes a `git_repository_init_options` with default values. Equivalent
* to creating an instance with GIT_REPOSITORY_INIT_OPTIONS_INIT.
*
* @param opts the `git_repository_init_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_REPOSITORY_INIT_OPTIONS_VERSION` here.
* @param opts the `git_repository_init_options` struct to initialize
* @param version Version of struct; pass `GIT_REPOSITORY_INIT_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_repository_init_init_options(
git_repository_init_options* opts,
int version);
git_repository_init_options *opts,
unsigned int version);
/**
* Create a new Git repository in the given folder with extended controls.
......
......@@ -37,14 +37,13 @@ typedef struct {
* Initializes a `git_revert_options` with default values. Equivalent to
* creating an instance with GIT_REVERT_OPTIONS_INIT.
*
* @param opts the `git_revert_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_REVERT_OPTIONS_VERSION` here.
* @param opts the `git_revert_options` struct to initialize
* @param version Version of struct; pass `GIT_REVERT_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_revert_init_opts(
git_revert_options* opts,
int version);
GIT_EXTERN(int) git_revert_init_options(
git_revert_options *opts,
unsigned int version);
/**
* Reverts the given commit against the given "our" commit, producing an
......
......@@ -121,6 +121,11 @@ typedef enum {
* - GIT_STATUS_OPT_NO_REFRESH bypasses the default status behavior of
* doing a "soft" index reload (i.e. reloading the index data if the
* file on disk has been modified outside libgit2).
* - GIT_STATUS_OPT_UPDATE_INDEX tells libgit2 to refresh the stat cache
* in the index for files that are unchanged but have out of date stat
* information in the index. It will result in less work being done on
* subsequent calls to get status. This is mutually exclusive with the
* NO_REFRESH option.
*
* Calling `git_status_foreach()` is like calling the extended version
* with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
......@@ -141,6 +146,7 @@ typedef enum {
GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY = (1u << 10),
GIT_STATUS_OPT_RENAMES_FROM_REWRITES = (1u << 11),
GIT_STATUS_OPT_NO_REFRESH = (1u << 12),
GIT_STATUS_OPT_UPDATE_INDEX = (1u << 13),
} git_status_opt_t;
#define GIT_STATUS_OPT_DEFAULTS \
......@@ -178,14 +184,13 @@ typedef struct {
* Initializes a `git_status_options` with default values. Equivalent to
* creating an instance with GIT_STATUS_OPTIONS_INIT.
*
* @param opts the `git_status_options` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_STATUS_OPTIONS_VERSION` here.
* @param opts The `git_status_options` instance to initialize.
* @param version Version of struct; pass `GIT_STATUS_OPTIONS_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_status_init_options(
git_status_options* opts,
int version);
git_status_options *opts,
unsigned int version);
/**
* A status entry, providing the differences between the file as it exists
......
......@@ -73,14 +73,13 @@ struct git_config_backend {
* Initializes a `git_config_backend` with default values. Equivalent to
* creating an instance with GIT_CONFIG_BACKEND_INIT.
*
* @param opts the `git_config_backend` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_CONFIG_BACKEND_VERSION` here.
* @param opts the `git_config_backend` struct to initialize.
* @param version Version of struct; pass `GIT_CONFIG_BACKEND_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_config_init_backend(
git_config_backend* backend,
int version);
git_config_backend *backend,
unsigned int version);
/**
* Add a generic config file instance to an existing config
......
......@@ -10,6 +10,8 @@
#include "git2/common.h"
#include "git2/types.h"
#include "git2/oid.h"
#include "git2/diff.h"
#include "git2/status.h"
/**
* @file git2/sys/diff.h
......@@ -58,6 +60,32 @@ GIT_EXTERN(int) git_diff_print_callback__to_file_handle(
const git_diff_line *line,
void *payload); /*< payload must be a `FILE *` */
typedef struct {
unsigned int version;
size_t stat_calls;
size_t oid_calculations;
} git_diff_perfdata;
#define GIT_DIFF_PERFDATA_VERSION 1
#define GIT_DIFF_PERFDATA_INIT {GIT_DIFF_PERFDATA_VERSION,0,0}
/**
* Get performance data for a diff object.
*
* @param out Structure to be filled with diff performance data
* @param diff Diff to read performance data from
* @return 0 for success, <0 for error
*/
GIT_EXTERN(int) git_diff_get_perfdata(
git_diff_perfdata *out, const git_diff *diff);
/**
* Get performance data for diffs from a git_status_list
*/
GIT_EXTERN(int) git_status_list_get_perfdata(
git_diff_perfdata *out, const git_status_list *status);
/** @} */
GIT_END_DECL
#endif
......@@ -93,14 +93,13 @@ struct git_odb_backend {
* Initializes a `git_odb_backend` with default values. Equivalent to
* creating an instance with GIT_ODB_BACKEND_INIT.
*
* @param opts the `git_odb_backend` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_ODB_BACKEND_VERSION` here.
* @param opts the `git_odb_backend` struct to initialize.
* @param version Version the struct; pass `GIT_ODB_BACKEND_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_odb_init_backend(
git_odb_backend* backend,
int version);
git_odb_backend *backend,
unsigned int version);
GIT_EXTERN(void *) git_odb_backend_malloc(git_odb_backend *backend, size_t len);
......
......@@ -162,14 +162,13 @@ struct git_refdb_backend {
* Initializes a `git_refdb_backend` with default values. Equivalent to
* creating an instance with GIT_REFDB_BACKEND_INIT.
*
* @param opts the `git_refdb_backend` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_REFDB_BACKEND_VERSION` here.
* @param opts the `git_refdb_backend` struct to initialize
* @param version Version of struct; pass `GIT_REFDB_BACKEND_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_refdb_init_backend(
git_refdb_backend* backend,
int version);
git_refdb_backend *backend,
unsigned int version);
/**
* Constructors for default filesystem-based refdb backend
......
......@@ -314,14 +314,13 @@ struct git_transport {
* Initializes a `git_transport` with default values. Equivalent to
* creating an instance with GIT_TRANSPORT_INIT.
*
* @param opts the `git_transport` instance to initialize.
* @param version the version of the struct; you should pass
* `GIT_TRANSPORT_VERSION` here.
* @param opts the `git_transport` struct to initialize
* @param version Version of struct; pass `GIT_TRANSPORT_VERSION`
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_transport_init(
git_transport* opts,
int version);
git_transport *opts,
unsigned int version);
/**
* Function to use to create a transport from a URL. The transport database
......
......@@ -480,14 +480,9 @@ int git_blame_buffer(
return 0;
}
int git_blame_init_options(git_blame_options* opts, int version)
int git_blame_init_options(git_blame_options *opts, unsigned int version)
{
if (version != GIT_BLAME_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_blame_options", version);
return -1;
} else {
git_blame_options o = GIT_BLAME_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_blame_options, GIT_BLAME_OPTIONS_INIT);
return 0;
}
......@@ -184,9 +184,7 @@ static bool checkout_is_workdir_modified(
if (baseitem->size && wditem->file_size != baseitem->size)
return true;
if (git_diff__oid_for_file(
data->repo, wditem->path, wditem->mode,
wditem->file_size, &oid) < 0)
if (git_diff__oid_for_entry(&oid, data->diff, wditem, NULL) < 0)
return false;
return (git_oid__cmp(&baseitem->id, &oid) != 0);
......@@ -2242,14 +2240,9 @@ int git_checkout_head(
return git_checkout_tree(repo, NULL, opts);
}
int git_checkout_init_opts(git_checkout_options* opts, int version)
int git_checkout_init_options(git_checkout_options *opts, unsigned int version)
{
if (version != GIT_CHECKOUT_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_checkout_options", version);
return -1;
} else {
git_checkout_options o = GIT_CHECKOUT_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_checkout_options, GIT_CHECKOUT_OPTIONS_INIT);
return 0;
}
......@@ -217,14 +217,10 @@ done:
return error;
}
int git_cherry_pick_init_opts(git_cherry_pick_options* opts, int version)
int git_cherry_pick_init_options(
git_cherry_pick_options *opts, unsigned int version)
{
if (version != GIT_CHERRY_PICK_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_cherry_pick_options", version);
return -1;
} else {
git_cherry_pick_options o = GIT_CHERRY_PICK_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_cherry_pick_options, GIT_CHERRY_PICK_OPTIONS_INIT);
return 0;
}
......@@ -445,14 +445,9 @@ int git_clone(
return error;
}
int git_clone_init_options(git_clone_options* opts, int version)
int git_clone_init_options(git_clone_options *opts, unsigned int version)
{
if (version != GIT_CLONE_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_clone_options", version);
return -1;
} else {
git_clone_options o = GIT_CLONE_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_clone_options, GIT_CLONE_OPTIONS_INIT);
return 0;
}
......@@ -170,6 +170,11 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
}
#define GIT_INIT_STRUCTURE(S,V) git__init_structure(S, sizeof(*S), V)
#define GIT_INIT_STRUCTURE_FROM_TEMPLATE(PTR,VERSION,TYPE,TPL) do { \
TYPE _tmpl = TPL; \
GITERR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \
memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0)
/* NOTE: other giterr functions are in the public errors.h header file */
#include "util.h"
......
......@@ -984,24 +984,22 @@ int git_config__global_location(git_buf *buf)
{
const git_buf *paths;
const char *sep, *start;
size_t len;
if (git_sysdir_get(&paths, GIT_SYSDIR_GLOBAL) < 0)
return -1;
/* no paths, so give up */
if (git_buf_len(paths) == 0)
if (!paths || !git_buf_len(paths))
return -1;
start = git_buf_cstr(paths);
sep = strchr(start, GIT_PATH_LIST_SEPARATOR);
if (sep)
len = sep - start;
else
len = paths->size;
/* find unescaped separator or end of string */
for (sep = start = git_buf_cstr(paths); *sep; ++sep) {
if (*sep == GIT_PATH_LIST_SEPARATOR &&
(sep <= start || sep[-1] != '\\'))
break;
}
if (git_buf_set(buf, start, len) < 0)
if (git_buf_set(buf, start, (size_t)(sep - start)) < 0)
return -1;
return git_buf_joinpath(buf, buf->ptr, GIT_CONFIG_FILENAME_GLOBAL);
......@@ -1276,14 +1274,9 @@ cleanup:
return error;
}
int git_config_init_backend(git_config_backend* backend, int version)
int git_config_init_backend(git_config_backend *backend, unsigned int version)
{
if (version != GIT_CONFIG_BACKEND_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_config_backend", version);
return -1;
} else {
git_config_backend b = GIT_CONFIG_BACKEND_INIT;
memcpy(backend, &b, sizeof(b));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
backend, version, git_config_backend, GIT_CONFIG_BACKEND_INIT);
return 0;
}
......@@ -442,6 +442,14 @@ static int diff_list_apply_options(
diff->new_src = tmp_src;
}
/* Unset UPDATE_INDEX unless diffing workdir and index */
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_UPDATE_INDEX) &&
(!(diff->old_src == GIT_ITERATOR_TYPE_WORKDIR ||
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR) ||
!(diff->old_src == GIT_ITERATOR_TYPE_INDEX ||
diff->new_src == GIT_ITERATOR_TYPE_INDEX)))
diff->opts.flags &= ~GIT_DIFF_UPDATE_INDEX;
/* if ignore_submodules not explicitly set, check diff config */
if (diff->opts.ignore_submodules <= 0) {
const git_config_entry *entry;
......@@ -510,76 +518,105 @@ void git_diff_addref(git_diff *diff)
}
int git_diff__oid_for_file(
git_repository *repo,
git_oid *out,
git_diff *diff,
const char *path,
uint16_t mode,
git_off_t size,
git_oid *oid)
git_off_t size)
{
git_index_entry entry;
memset(&entry, 0, sizeof(entry));
entry.mode = mode;
entry.file_size = size;
entry.path = (char *)path;
return git_diff__oid_for_entry(out, diff, &entry, NULL);
}
int git_diff__oid_for_entry(
git_oid *out,
git_diff *diff,
const git_index_entry *src,
const git_oid *update_match)
{
int result = 0;
int error = 0;
git_buf full_path = GIT_BUF_INIT;
git_index_entry entry = *src;
git_filter_list *fl = NULL;
memset(out, 0, sizeof(*out));
if (git_buf_joinpath(
&full_path, git_repository_workdir(repo), path) < 0)
&full_path, git_repository_workdir(diff->repo), entry.path) < 0)
return -1;
if (!mode) {
if (!entry.mode) {
struct stat st;
if (p_stat(path, &st) < 0) {
giterr_set(GITERR_OS, "Could not stat '%s'", path);
result = -1;
goto cleanup;
diff->perf.stat_calls++;
if (p_stat(full_path.ptr, &st) < 0) {
error = git_path_set_error(errno, entry.path, "stat");
git_buf_free(&full_path);
return error;
}
mode = st.st_mode;
size = st.st_size;
git_index_entry__init_from_stat(
&entry, &st, (diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) != 0);
}
/* calculate OID for file if possible */
if (S_ISGITLINK(mode)) {
if (S_ISGITLINK(entry.mode)) {
git_submodule *sm;
memset(oid, 0, sizeof(*oid));
if (!git_submodule_lookup(&sm, repo, path)) {
if (!git_submodule_lookup(&sm, diff->repo, entry.path)) {
const git_oid *sm_oid = git_submodule_wd_id(sm);
if (sm_oid)
git_oid_cpy(oid, sm_oid);
git_oid_cpy(out, sm_oid);
git_submodule_free(sm);
} else {
/* if submodule lookup failed probably just in an intermediate
* state where some init hasn't happened, so ignore the error
*/
giterr_clear();
memset(oid, 0, sizeof(*oid));
}
} else if (S_ISLNK(mode)) {
result = git_odb__hashlink(oid, full_path.ptr);
} else if (!git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'", path);
result = -1;
} else {
git_filter_list *fl = NULL;
result = git_filter_list_load(&fl, repo, NULL, path, GIT_FILTER_TO_ODB);
if (!result) {
int fd = git_futils_open_ro(full_path.ptr);
if (fd < 0)
result = fd;
else {
result = git_odb__hashfd_filtered(
oid, fd, (size_t)size, GIT_OBJ_BLOB, fl);
p_close(fd);
}
git_filter_list_free(fl);
} else if (S_ISLNK(entry.mode)) {
error = git_odb__hashlink(out, full_path.ptr);
diff->perf.oid_calculations++;
} else if (!git__is_sizet(entry.file_size)) {
giterr_set(GITERR_OS, "File size overflow (for 32-bits) on '%s'",
entry.path);
error = -1;
} else if (!(error = git_filter_list_load(
&fl, diff->repo, NULL, entry.path, GIT_FILTER_TO_ODB)))
{
int fd = git_futils_open_ro(full_path.ptr);
if (fd < 0)
error = fd;
else {
error = git_odb__hashfd_filtered(
out, fd, (size_t)entry.file_size, GIT_OBJ_BLOB, fl);
p_close(fd);
diff->perf.oid_calculations++;
}
git_filter_list_free(fl);
}
cleanup:
/* update index for entry if requested */
if (!error && update_match && git_oid_equal(out, update_match)) {
git_index *idx;
if (!(error = git_repository_index(&idx, diff->repo))) {
memcpy(&entry.id, out, sizeof(entry.id));
error = git_index_add(idx, &entry);
git_index_free(idx);
}
}
git_buf_free(&full_path);
return result;
return error;
}
static bool diff_time_eq(
......@@ -660,6 +697,7 @@ static int maybe_modified(
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
bool new_is_workdir = (info->new_iter->type == GIT_ITERATOR_TYPE_WORKDIR);
bool modified_uncertain = false;
const char *matched_pathspec;
int error = 0;
......@@ -727,15 +765,21 @@ static int maybe_modified(
/* if the stat data looks different, then mark modified - this just
* means that the OID will be recalculated below to confirm change
*/
else if (omode != nmode ||
oitem->file_size != nitem->file_size ||
!diff_time_eq(&oitem->mtime, &nitem->mtime, use_nanos) ||
else if (omode != nmode || oitem->file_size != nitem->file_size) {
status = GIT_DELTA_MODIFIED;
modified_uncertain =
(oitem->file_size <= 0 && nitem->file_size > 0);
}
else if (!diff_time_eq(&oitem->mtime, &nitem->mtime, use_nanos) ||
(use_ctime &&
!diff_time_eq(&oitem->ctime, &nitem->ctime, use_nanos)) ||
oitem->ino != nitem->ino ||
oitem->uid != nitem->uid ||
oitem->gid != nitem->gid)
{
status = GIT_DELTA_MODIFIED;
modified_uncertain = true;
}
}
/* if mode is GITLINK and submodules are ignored, then skip */
......@@ -746,10 +790,14 @@ static int maybe_modified(
/* if we got here and decided that the files are modified, but we
* haven't calculated the OID of the new item, then calculate it now
*/
if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->id)) {
if (modified_uncertain && git_oid_iszero(&nitem->id)) {
if (git_oid_iszero(&noid)) {
if ((error = git_diff__oid_for_file(diff->repo,
nitem->path, nitem->mode, nitem->file_size, &noid)) < 0)
const git_oid *update_check =
DIFF_FLAG_IS_SET(diff, GIT_DIFF_UPDATE_INDEX) ?
&oitem->id : NULL;
if ((error = git_diff__oid_for_entry(
&noid, diff, nitem, update_check)) < 0)
return error;
}
......@@ -1066,6 +1114,8 @@ int git_diff__from_iterators(
error = 0;
}
diff->perf.stat_calls += old_iter->stat_calls + new_iter->stat_calls;
cleanup:
if (!error)
*diff_ptr = diff;
......@@ -1174,6 +1224,9 @@ int git_diff_index_to_workdir(
&b, repo, GIT_ITERATOR_DONT_AUTOEXPAND, pfx, pfx)
);
if (!error && DIFF_FLAG_IS_SET(*diff, GIT_DIFF_UPDATE_INDEX))
error = git_index_write(index);
return error;
}
......@@ -1226,20 +1279,6 @@ int git_diff_tree_to_workdir_with_index(
return error;
}
int git_diff_options_init(git_diff_options *options, unsigned int version)
{
git_diff_options template = GIT_DIFF_OPTIONS_INIT;
if (version != template.version) {
giterr_set(GITERR_INVALID,
"Invalid version %d for git_diff_options", (int)version);
return -1;
}
memcpy(options, &template, sizeof(*options));
return 0;
}
size_t git_diff_num_deltas(const git_diff *diff)
{
assert(diff);
......@@ -1271,6 +1310,15 @@ int git_diff_is_sorted_icase(const git_diff *diff)
return (diff->opts.flags & GIT_DIFF_IGNORE_CASE) != 0;
}
int git_diff_get_perfdata(git_diff_perfdata *out, const git_diff *diff)
{
assert(out);
GITERR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
out->stat_calls = diff->perf.stat_calls;
out->oid_calculations = diff->perf.oid_calculations;
return 0;
}
int git_diff__paired_foreach(
git_diff *head2idx,
git_diff *idx2wd,
......@@ -1573,38 +1621,26 @@ int git_diff_commit_as_email(
return error;
}
int git_diff_init_options(git_diff_options* opts, int version)
int git_diff_init_options(git_diff_options *opts, unsigned int version)
{
if (version != GIT_DIFF_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_options", version);
return -1;
} else {
git_diff_options o = GIT_DIFF_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_options, GIT_DIFF_OPTIONS_INIT);
return 0;
}
int git_diff_find_init_options(git_diff_find_options* opts, int version)
int git_diff_find_init_options(
git_diff_find_options *opts, unsigned int version)
{
if (version != GIT_DIFF_FIND_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_find_options", version);
return -1;
} else {
git_diff_find_options o = GIT_DIFF_FIND_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_find_options, GIT_DIFF_FIND_OPTIONS_INIT);
return 0;
}
int git_diff_format_email_init_options(git_diff_format_email_options* opts, int version)
int git_diff_format_email_init_options(
git_diff_format_email_options *opts, unsigned int version)
{
if (version != GIT_DIFF_FORMAT_EMAIL_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_diff_format_email_options", version);
return -1;
} else {
git_diff_format_email_options o = GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_diff_format_email_options,
GIT_DIFF_FORMAT_EMAIL_OPTIONS_INIT);
return 0;
}
......@@ -8,6 +8,7 @@
#define INCLUDE_diff_h__
#include "git2/diff.h"
#include "git2/sys/diff.h"
#include "git2/oid.h"
#include <stdio.h>
......@@ -62,6 +63,7 @@ struct git_diff {
git_iterator_type_t old_src;
git_iterator_type_t new_src;
uint32_t diffcaps;
git_diff_perfdata perf;
int (*strcomp)(const char *, const char *);
int (*strncomp)(const char *, const char *, size_t);
......@@ -90,7 +92,9 @@ extern int git_diff_delta__format_file_header(
int oid_strlen);
extern int git_diff__oid_for_file(
git_repository *, const char *, uint16_t, git_off_t, git_oid *);
git_oid *out, git_diff *, const char *, uint16_t, git_off_t);
extern int git_diff__oid_for_entry(
git_oid *out, git_diff *, const git_index_entry *, const git_oid *update);
extern int git_diff__from_iterators(
git_diff **diff_ptr,
......
......@@ -574,14 +574,14 @@ static int similarity_measure(
if (exact_match) {
if (git_oid_iszero(&a_file->id) &&
diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(diff->repo, a_file->path,
a_file->mode, a_file->size, &a_file->id))
!git_diff__oid_for_file(&a_file->id,
diff, a_file->path, a_file->mode, a_file->size))
a_file->flags |= GIT_DIFF_FLAG_VALID_ID;
if (git_oid_iszero(&b_file->id) &&
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(diff->repo, b_file->path,
b_file->mode, b_file->size, &b_file->id))
!git_diff__oid_for_file(&b_file->id,
diff, b_file->path, b_file->mode, b_file->size))
b_file->flags |= GIT_DIFF_FLAG_VALID_ID;
}
......
......@@ -842,7 +842,7 @@ static int index_entry_reuc_init(git_index_reuc_entry **reuc_out,
static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src)
{
char *tgt_path = tgt->path;
const char *tgt_path = tgt->path;
memcpy(tgt, src, sizeof(*tgt));
tgt->path = tgt_path; /* reset to existing path data */
}
......@@ -2282,9 +2282,7 @@ static int read_tree_cb(
entry->mode == old_entry->mode &&
git_oid_equal(&entry->id, &old_entry->id))
{
char *oldpath = entry->path;
memcpy(entry, old_entry, sizeof(*entry));
entry->path = oldpath;
index_entry_cpy(entry, old_entry);
entry->flags_extended = 0;
}
......
......@@ -1016,6 +1016,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
fs_iterator__free_frame(ff);
return GIT_ENOTFOUND;
}
fi->base.stat_calls += ff->entries.length;
fs_iterator__seek_frame_start(fi, ff);
......@@ -1304,9 +1305,10 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
/* convert submodules to GITLINK and remove trailing slashes */
git_vector_foreach(&ff->entries, pos, entry) {
if (S_ISDIR(entry->st.st_mode) &&
git_submodule__is_submodule(fi->base.repo, entry->path))
{
if (!S_ISDIR(entry->st.st_mode) || !strcmp(GIT_DIR, entry->path))
continue;
if (git_submodule__is_submodule(fi->base.repo, entry->path)) {
entry->st.st_mode = GIT_FILEMODE_COMMIT;
entry->path_len--;
entry->path[entry->path_len] = '\0';
......
......@@ -52,6 +52,7 @@ struct git_iterator {
char *start;
char *end;
int (*prefixcomp)(const char *str, const char *prefix);
size_t stat_calls;
unsigned int flags;
};
......
......@@ -2803,38 +2803,24 @@ void git_merge_head_free(git_merge_head *head)
git__free(head);
}
int git_merge_init_options(git_merge_options *opts, int version)
int git_merge_init_options(git_merge_options *opts, unsigned int version)
{
if (version != GIT_MERGE_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_merge_options", version);
return -1;
} else {
git_merge_options default_opts = GIT_MERGE_OPTIONS_INIT;
memcpy(opts, &default_opts, sizeof(git_merge_options));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_merge_options, GIT_MERGE_OPTIONS_INIT);
return 0;
}
int git_merge_file_init_input(git_merge_file_input *input, int version)
int git_merge_file_init_input(git_merge_file_input *input, unsigned int version)
{
if (version != GIT_MERGE_FILE_INPUT_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_merge_file_input", version);
return -1;
} else {
git_merge_file_input i = GIT_MERGE_FILE_INPUT_INIT;
memcpy(input, &i, sizeof(i));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
input, version, git_merge_file_input, GIT_MERGE_FILE_INPUT_INIT);
return 0;
}
int git_merge_file_init_options(git_merge_file_options *opts, int version)
int git_merge_file_init_options(
git_merge_file_options *opts, unsigned int version)
{
if (version != GIT_MERGE_FILE_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_merge_file_options", version);
return -1;
} else {
git_merge_file_options o = GIT_MERGE_FILE_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_merge_file_options, GIT_MERGE_FILE_OPTIONS_INIT);
return 0;
}
......@@ -1123,14 +1123,9 @@ int git_odb__error_ambiguous(const char *message)
return GIT_EAMBIGUOUS;
}
int git_odb_init_backend(git_odb_backend* backend, int version)
int git_odb_init_backend(git_odb_backend *backend, unsigned int version)
{
if (version != GIT_ODB_BACKEND_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_odb_backend", version);
return -1;
} else {
git_odb_backend b = GIT_ODB_BACKEND_INIT;
memcpy(backend, &b, sizeof(b));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
backend, version, git_odb_backend, GIT_ODB_BACKEND_INIT);
return 0;
}
......@@ -716,14 +716,9 @@ void git_push_free(git_push *push)
git__free(push);
}
int git_push_init_options(git_push_options* opts, int version)
int git_push_init_options(git_push_options *opts, unsigned int version)
{
if (version != GIT_PUSH_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_push_options", version);
return -1;
} else {
git_push_options o = GIT_PUSH_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_push_options, GIT_PUSH_OPTIONS_INIT);
return 0;
}
......@@ -236,14 +236,9 @@ int git_refdb_ensure_log(git_refdb *db, const char *refname)
return db->backend->ensure_log(db->backend, refname);
}
int git_refdb_init_backend(git_refdb_backend* backend, int version)
int git_refdb_init_backend(git_refdb_backend *backend, unsigned int version)
{
if (version != GIT_REFDB_BACKEND_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_refdb_backend", version);
return -1;
} else {
git_refdb_backend b = GIT_REFDB_BACKEND_INIT;
memcpy(backend, &b, sizeof(b));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
backend, version, git_refdb_backend, GIT_REFDB_BACKEND_INIT);
return 0;
}
......@@ -1736,14 +1736,9 @@ const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
return git_vector_get(&remote->refspecs, n);
}
int git_remote_init_callbacks(git_remote_callbacks* opts, int version)
int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
{
if (version != GIT_REMOTE_CALLBACKS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_remote_callbacks", version);
return -1;
} else {
git_remote_callbacks o = GIT_REMOTE_CALLBACKS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
return 0;
}
......@@ -2026,14 +2026,11 @@ int git_repository_is_shallow(git_repository *repo)
return st.st_size == 0 ? 0 : 1;
}
int git_repository_init_init_options(git_repository_init_options* opts, int version)
int git_repository_init_init_options(
git_repository_init_options *opts, unsigned int version)
{
if (version != GIT_REPOSITORY_INIT_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_repository_init_options", version);
return -1;
} else {
git_repository_init_options o = GIT_REPOSITORY_INIT_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_repository_init_options,
GIT_REPOSITORY_INIT_OPTIONS_INIT);
return 0;
}
......@@ -220,14 +220,9 @@ done:
return error;
}
int git_revert_init_opts(git_revert_options* opts, int version)
int git_revert_init_options(git_revert_options *opts, unsigned int version)
{
if (version != GIT_REVERT_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_revert_options", version);
return -1;
} else {
git_revert_options o = GIT_REVERT_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_revert_options, GIT_REVERT_OPTIONS_INIT);
return 0;
}
......@@ -81,15 +81,15 @@ static unsigned int workdir_delta2status(
if (git_oid_iszero(&idx2wd->old_file.id) &&
diff->old_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(
diff->repo, idx2wd->old_file.path, idx2wd->old_file.mode,
idx2wd->old_file.size, &idx2wd->old_file.id))
&idx2wd->old_file.id, diff, idx2wd->old_file.path,
idx2wd->old_file.mode, idx2wd->old_file.size))
idx2wd->old_file.flags |= GIT_DIFF_FLAG_VALID_ID;
if (git_oid_iszero(&idx2wd->new_file.id) &&
diff->new_src == GIT_ITERATOR_TYPE_WORKDIR &&
!git_diff__oid_for_file(
diff->repo, idx2wd->new_file.path, idx2wd->new_file.mode,
idx2wd->new_file.size, &idx2wd->new_file.id))
&idx2wd->new_file.id, diff, idx2wd->new_file.path,
idx2wd->new_file.mode, idx2wd->new_file.size))
idx2wd->new_file.flags |= GIT_DIFF_FLAG_VALID_ID;
if (!git_oid_equal(&idx2wd->old_file.id, &idx2wd->new_file.id))
......@@ -225,6 +225,28 @@ static git_status_list *git_status_list_alloc(git_index *index)
return status;
}
static int status_validate_options(const git_status_options *opts)
{
if (!opts)
return 0;
GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options");
if (opts->show > GIT_STATUS_SHOW_WORKDIR_ONLY) {
giterr_set(GITERR_INVALID, "Unknown status 'show' option");
return -1;
}
if ((opts->flags & GIT_STATUS_OPT_NO_REFRESH) != 0 &&
(opts->flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0) {
giterr_set(GITERR_INVALID, "Updating index from status "
"is not allowed when index refresh is disabled");
return -1;
}
return 0;
}
int git_status_list_new(
git_status_list **out,
git_repository *repo,
......@@ -240,11 +262,10 @@ int git_status_list_new(
int error = 0;
unsigned int flags = opts ? opts->flags : GIT_STATUS_OPT_DEFAULTS;
assert(show <= GIT_STATUS_SHOW_WORKDIR_ONLY);
*out = NULL;
GITERR_CHECK_VERSION(opts, GIT_STATUS_OPTIONS_VERSION, "git_status_options");
if (status_validate_options(opts) < 0)
return -1;
if ((error = git_repository__ensure_not_bare(repo, "status")) < 0 ||
(error = git_repository_index(&index, repo)) < 0)
......@@ -287,6 +308,8 @@ int git_status_list_new(
diffopt.flags = diffopt.flags | GIT_DIFF_RECURSE_IGNORED_DIRS;
if ((flags & GIT_STATUS_OPT_EXCLUDE_SUBMODULES) != 0)
diffopt.flags = diffopt.flags | GIT_DIFF_IGNORE_SUBMODULES;
if ((flags & GIT_STATUS_OPT_UPDATE_INDEX) != 0)
diffopt.flags = diffopt.flags | GIT_DIFF_UPDATE_INDEX;
if ((flags & GIT_STATUS_OPT_RENAMES_FROM_REWRITES) != 0)
findopt.flags = findopt.flags |
......@@ -495,14 +518,31 @@ int git_status_should_ignore(
return git_ignore_path_is_ignored(ignored, repo, path);
}
int git_status_init_options(git_status_options* opts, int version)
int git_status_init_options(git_status_options *opts, unsigned int version)
{
if (version != GIT_STATUS_OPTIONS_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_status_options", version);
return -1;
} else {
git_status_options o = GIT_STATUS_OPTIONS_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_status_options, GIT_STATUS_OPTIONS_INIT);
return 0;
}
int git_status_list_get_perfdata(
git_diff_perfdata *out, const git_status_list *status)
{
assert(out);
GITERR_CHECK_VERSION(out, GIT_DIFF_PERFDATA_VERSION, "git_diff_perfdata");
out->stat_calls = 0;
out->oid_calculations = 0;
if (status->head2idx) {
out->stat_calls += status->head2idx->perf.stat_calls;
out->oid_calculations += status->head2idx->perf.oid_calculations;
}
if (status->idx2wd) {
out->stat_calls += status->idx2wd->perf.stat_calls;
out->oid_calculations += status->idx2wd->perf.oid_calculations;
}
return 0;
}
......@@ -194,14 +194,19 @@ static int git_sysdir_find_in_dirlist(
const git_buf *syspath;
GITERR_CHECK_ERROR(git_sysdir_get(&syspath, which));
if (!syspath || !git_buf_len(syspath))
goto done;
for (scan = git_buf_cstr(syspath); scan; scan = next) {
for (next = strchr(scan, GIT_PATH_LIST_SEPARATOR);
next && next > scan && next[-1] == '\\';
next = strchr(next + 1, GIT_PATH_LIST_SEPARATOR))
/* find unescaped separator or end of string */;
/* find unescaped separator or end of string */
for (next = scan; *next; ++next) {
if (*next == GIT_PATH_LIST_SEPARATOR &&
(next <= scan || next[-1] != '\\'))
break;
}
len = next ? (size_t)(next++ - scan) : strlen(scan);
len = (size_t)(next - scan);
next = (*next ? next + 1 : NULL);
if (!len)
continue;
......@@ -213,6 +218,7 @@ static int git_sysdir_find_in_dirlist(
return 0;
}
done:
git_buf_free(path);
giterr_set(GITERR_OS, "The %s file '%s' doesn't exist", label, name);
return GIT_ENOTFOUND;
......
......@@ -218,14 +218,9 @@ int git_remote_supported_url(const char* url)
return fn != &git_transport_dummy;
}
int git_transport_init(git_transport* opts, int version)
int git_transport_init(git_transport *opts, unsigned int version)
{
if (version != GIT_TRANSPORT_VERSION) {
giterr_set(GITERR_INVALID, "Invalid version %d for git_transport", version);
return -1;
} else {
git_transport o = GIT_TRANSPORT_INIT;
memcpy(opts, &o, sizeof(o));
return 0;
}
GIT_INIT_STRUCTURE_FROM_TEMPLATE(
opts, version, git_transport, GIT_TRANSPORT_INIT);
return 0;
}
......@@ -148,12 +148,11 @@ void test_attr_ignore__skip_gitignore_directory(void)
void test_attr_ignore__expand_tilde_to_homedir(void)
{
git_buf cleanup = GIT_BUF_INIT;
git_config *cfg;
assert_is_ignored(false, "example.global_with_tilde");
cl_fake_home(&cleanup);
cl_fake_home();
/* construct fake home with fake global excludes */
cl_git_mkfile("home/globalexclude", "# found me\n*.global_with_tilde\n");
......@@ -168,7 +167,7 @@ void test_attr_ignore__expand_tilde_to_homedir(void)
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
cl_fake_home_cleanup(&cleanup);
cl_fake_home_cleanup(NULL);
git_attr_cache_flush(g_repo); /* must reset to pick up change */
......
......@@ -9,11 +9,6 @@ static git_repository *g_repo = NULL;
void test_attr_repo__initialize(void)
{
/* Before each test, instantiate the attr repo from the fixtures and
* rename the .gitted to .git so it is a repo with a working dir.
* Also rename gitattributes to .gitattributes, because it contains
* macro definitions which are only allowed in the root.
*/
g_repo = cl_git_sandbox_init("attr");
}
......
......@@ -484,23 +484,36 @@ void clar__assert_equal_file(
(size_t)expected_bytes, (size_t)total_bytes);
}
void cl_fake_home(git_buf *restore)
static char *_cl_restore_home = NULL;
void cl_fake_home_cleanup(void *payload)
{
char *restore = _cl_restore_home;
_cl_restore_home = NULL;
GIT_UNUSED(payload);
if (restore) {
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, restore));
git__free(restore);
}
}
void cl_fake_home(void)
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_libgit2_opts(
GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, restore));
GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &path));
_cl_restore_home = git_buf_detach(&path);
cl_set_cleanup(cl_fake_home_cleanup, NULL);
cl_must_pass(p_mkdir("home", 0777));
if (!git_path_exists("home"))
cl_must_pass(p_mkdir("home", 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
git_buf_free(&path);
}
void cl_fake_home_cleanup(git_buf *restore)
{
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, restore->ptr));
git_buf_free(restore);
}
......@@ -131,7 +131,12 @@ int cl_repo_get_bool(git_repository *repo, const char *cfg);
void cl_repo_set_string(git_repository *repo, const char *cfg, const char *value);
void cl_fake_home(git_buf *restore);
void cl_fake_home_cleanup(git_buf *restore);
/* set up a fake "home" directory and set libgit2 GLOBAL search path.
*
* automatically configures cleanup function to restore the regular search
* path, although you can call it explicitly if you wish (with NULL).
*/
void cl_fake_home(void);
void cl_fake_home_cleanup(void *);
#endif
......@@ -2,22 +2,36 @@
#include "buffer.h"
#include "fileops.h"
static git_config_level_t setting[3] = {
GIT_CONFIG_LEVEL_GLOBAL,
GIT_CONFIG_LEVEL_XDG,
GIT_CONFIG_LEVEL_SYSTEM
};
static char *restore[3];
void test_config_global__initialize(void)
{
int i;
git_buf path = GIT_BUF_INIT;
cl_assert_equal_i(0, p_mkdir("home", 0777));
/* snapshot old settings to restore later */
for (i = 0; i < 3; ++i) {
cl_git_pass(
git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, setting[i], &path));
restore[i] = git_buf_detach(&path);
}
cl_git_pass(git_futils_mkdir_r("home", NULL, 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_assert_equal_i(0, p_mkdir("xdg", 0777));
cl_assert_equal_i(0, p_mkdir("xdg/git", 0777));
cl_git_pass(git_futils_mkdir_r("xdg/git", NULL, 0777));
cl_git_pass(git_path_prettify(&path, "xdg/git", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_assert_equal_i(0, p_mkdir("etc", 0777));
cl_git_pass(git_futils_mkdir_r("etc", NULL, 0777));
cl_git_pass(git_path_prettify(&path, "etc", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
......@@ -27,13 +41,18 @@ void test_config_global__initialize(void)
void test_config_global__cleanup(void)
{
int i;
for (i = 0; i < 3; ++i) {
cl_git_pass(
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, setting[i], restore[i]));
git__free(restore[i]);
restore[i] = NULL;
}
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("xdg", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("etc", NULL, GIT_RMDIR_REMOVE_FILES));
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, NULL);
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, NULL);
git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL);
}
void test_config_global__open_global(void)
......
......@@ -26,7 +26,7 @@ void test_diff_blob__initialize(void)
g_repo = cl_git_sandbox_init("attr");
cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
opts.context_lines = 1;
memset(&expected, 0, sizeof(expected));
......
......@@ -9,7 +9,7 @@ static diff_expects expect;
void test_diff_tree__initialize(void)
{
cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
memset(&expect, 0, sizeof(expect));
......
#include "clar_libgit2.h"
#include "diff_helpers.h"
#include "repository.h"
#include "git2/sys/diff.h"
static git_repository *g_repo = NULL;
void test_diff_workdir__initialize(void)
{
}
void test_diff_workdir__cleanup(void)
{
cl_git_sandbox_cleanup();
......@@ -60,6 +57,14 @@ void test_diff_workdir__to_index(void)
cl_assert_equal_i(5, exp.line_dels);
}
{
git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT;
cl_git_pass(git_diff_get_perfdata(&perf, diff));
cl_assert_equal_sz(
13 /* in root */ + 3 /* in subdir */, perf.stat_calls);
cl_assert_equal_sz(5, perf.oid_calculations);
}
git_diff_free(diff);
}
......@@ -1490,3 +1495,88 @@ void test_diff_workdir__with_stale_index(void)
git_index_free(idx);
}
static int touch_file(void *payload, git_buf *path)
{
int fd;
char b;
GIT_UNUSED(payload);
if (git_path_isdir(path->ptr))
return 0;
cl_assert((fd = p_open(path->ptr, O_RDWR)) >= 0);
cl_assert_equal_i(1, p_read(fd, &b, 1));
cl_must_pass(p_lseek(fd, 0, SEEK_SET));
cl_must_pass(p_write(fd, &b, 1));
cl_must_pass(p_close(fd));
return 0;
}
static void basic_diff_status(git_diff **out, const git_diff_options *opts)
{
diff_expects exp;
cl_git_pass(git_diff_index_to_workdir(out, g_repo, NULL, opts));
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
*out, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
cl_assert_equal_i(13, exp.files);
cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]);
cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]);
}
void test_diff_workdir__can_update_index(void)
{
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff *diff = NULL;
git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT;
g_repo = cl_git_sandbox_init("status");
/* touch all the files so stat times are different */
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_buf_sets(&path, "status"));
cl_git_pass(git_path_direach(&path, 0, touch_file, NULL));
git_buf_free(&path);
}
opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
basic_diff_status(&diff, &opts);
cl_git_pass(git_diff_get_perfdata(&perf, diff));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(5, perf.oid_calculations);
git_diff_free(diff);
/* now allow diff to update stat cache */
opts.flags |= GIT_DIFF_UPDATE_INDEX;
basic_diff_status(&diff, &opts);
cl_git_pass(git_diff_get_perfdata(&perf, diff));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(5, perf.oid_calculations);
git_diff_free(diff);
/* now if we do it again, we should see fewer OID calculations */
basic_diff_status(&diff, &opts);
cl_git_pass(git_diff_get_perfdata(&perf, diff));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(0, perf.oid_calculations);
git_diff_free(diff);
}
......@@ -7,10 +7,9 @@ static git_reference *branch;
void test_refs_branches_create__initialize(void)
{
cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
repo = cl_git_sandbox_init("testrepo.git");
branch = NULL;
target = NULL;
}
void test_refs_branches_create__cleanup(void)
......@@ -21,10 +20,8 @@ void test_refs_branches_create__cleanup(void)
git_commit_free(target);
target = NULL;
git_repository_free(repo);
cl_git_sandbox_cleanup();
repo = NULL;
cl_fixture_cleanup("testrepo.git");
}
static void retrieve_target_from_oid(git_commit **out, git_repository *repo, const char *sha)
......
......@@ -10,8 +10,7 @@ void test_refs_branches_delete__initialize(void)
{
git_oid id;
cl_fixture_sandbox("testrepo.git");
cl_git_pass(git_repository_open(&repo, "testrepo.git"));
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"));
cl_git_pass(git_reference_create(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0, NULL, NULL));
......@@ -22,10 +21,8 @@ void test_refs_branches_delete__cleanup(void)
git_reference_free(fake_remote);
fake_remote = NULL;
git_repository_free(repo);
cl_git_sandbox_cleanup();
repo = NULL;
cl_fixture_cleanup("testrepo.git");
}
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void)
......
......@@ -7,7 +7,8 @@ static git_reference *branch;
void test_refs_branches_ishead__initialize(void)
{
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
repo = cl_git_sandbox_init("testrepo.git");
branch = NULL;
}
void test_refs_branches_ishead__cleanup(void)
......@@ -15,7 +16,7 @@ void test_refs_branches_ishead__cleanup(void)
git_reference_free(branch);
branch = NULL;
git_repository_free(repo);
cl_git_sandbox_cleanup();
repo = NULL;
}
......@@ -28,34 +29,20 @@ void test_refs_branches_ishead__can_tell_if_a_branch_is_pointed_at_by_HEAD(void)
void test_refs_branches_ishead__can_properly_handle_unborn_HEAD(void)
{
git_repository_free(repo);
repo = cl_git_sandbox_init("testrepo.git");
make_head_unborn(repo, NON_EXISTING_HEAD);
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_assert_equal_i(false, git_branch_is_head(branch));
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_refs_branches_ishead__can_properly_handle_missing_HEAD(void)
{
git_repository_free(repo);
repo = cl_git_sandbox_init("testrepo.git");
delete_head(repo);
cl_git_pass(git_reference_lookup(&branch, repo, "refs/heads/master"));
cl_assert_equal_i(false, git_branch_is_head(branch));
cl_git_sandbox_cleanup();
repo = NULL;
}
void test_refs_branches_ishead__can_tell_if_a_branch_is_not_pointed_at_by_HEAD(void)
......@@ -95,9 +82,6 @@ void test_refs_branches_ishead__only_direct_references_are_considered(void)
{
git_reference *linked, *super, *head;
git_repository_free(repo);
repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_reference_symbolic_create(&linked, repo, "refs/heads/linked", "refs/heads/master", 0, NULL, NULL));
cl_git_pass(git_reference_symbolic_create(&super, repo, "refs/heads/super", "refs/heads/linked", 0, NULL, NULL));
cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1, NULL, NULL));
......@@ -111,6 +95,4 @@ void test_refs_branches_ishead__only_direct_references_are_considered(void)
git_reference_free(linked);
git_reference_free(super);
git_reference_free(head);
cl_git_sandbox_cleanup();
repo = NULL;
}
......@@ -364,7 +364,6 @@ void test_status_ignore__leading_slash_ignores(void)
{
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
status_entry_counts counts;
git_buf home = GIT_BUF_INIT;
static const char *paths_2[] = {
"dir/.gitignore",
"dir/a/ignore_me",
......@@ -385,7 +384,7 @@ void test_status_ignore__leading_slash_ignores(void)
make_test_data(test_repo_1, test_files_1);
cl_fake_home(&home);
cl_fake_home();
cl_git_mkfile("home/.gitignore", "/ignore_me\n");
{
git_config *cfg;
......@@ -412,8 +411,6 @@ void test_status_ignore__leading_slash_ignores(void)
cl_assert_equal_i(counts.expected_entry_count, counts.entry_count);
cl_assert_equal_i(0, counts.wrong_status_flags_count);
cl_assert_equal_i(0, counts.wrong_sorted_path);
cl_fake_home_cleanup(&home);
}
void test_status_ignore__contained_dir_with_matching_name(void)
......
......@@ -5,6 +5,8 @@
#include "posix.h"
#include "util.h"
#include "path.h"
#include "../diff/diff_helpers.h"
#include "git2/sys/diff.h"
/**
* Cleanup
......@@ -40,11 +42,15 @@ void test_status_worktree__whole_repository(void)
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
void assert_show(const int entry_counts, const char *entry_paths[],
const unsigned int entry_statuses[], git_status_show_t show)
void assert_show(
const int entry_counts,
const char *entry_paths[],
const unsigned int entry_statuses[],
git_repository *repo,
git_status_show_t show,
unsigned int extra_flags)
{
status_entry_counts counts;
git_repository *repo = cl_git_sandbox_init("status");
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
memset(&counts, 0x0, sizeof(status_entry_counts));
......@@ -52,7 +58,7 @@ void assert_show(const int entry_counts, const char *entry_paths[],
counts.expected_paths = entry_paths;
counts.expected_statuses = entry_statuses;
opts.flags = GIT_STATUS_OPT_DEFAULTS;
opts.flags = GIT_STATUS_OPT_DEFAULTS | extra_flags;
opts.show = show;
cl_git_pass(
......@@ -67,19 +73,19 @@ void assert_show(const int entry_counts, const char *entry_paths[],
void test_status_worktree__show_index_and_workdir(void)
{
assert_show(entry_count0, entry_paths0, entry_statuses0,
GIT_STATUS_SHOW_INDEX_AND_WORKDIR);
cl_git_sandbox_init("status"), GIT_STATUS_SHOW_INDEX_AND_WORKDIR, 0);
}
void test_status_worktree__show_index_only(void)
{
assert_show(entry_count5, entry_paths5, entry_statuses5,
GIT_STATUS_SHOW_INDEX_ONLY);
cl_git_sandbox_init("status"), GIT_STATUS_SHOW_INDEX_ONLY, 0);
}
void test_status_worktree__show_workdir_only(void)
{
assert_show(entry_count6, entry_paths6, entry_statuses6,
GIT_STATUS_SHOW_WORKDIR_ONLY);
cl_git_sandbox_init("status"), GIT_STATUS_SHOW_WORKDIR_ONLY, 0);
}
/* this test is equivalent to t18-status.c:statuscb1 */
......@@ -578,7 +584,11 @@ void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf(void
cl_git_pass(git_status_file(&status, repo, "current_file"));
cl_assert_equal_i(GIT_STATUS_CURRENT, status);
/* stat data on file should no longer match stat cache, even though
* file diff will be empty because of line-ending conversion - matches
* the Git command-line behavior here.
*/
cl_assert_equal_i(GIT_STATUS_WT_MODIFIED, status);
}
void test_status_worktree__line_endings_dont_count_as_changes_with_autocrlf_issue_1397(void)
......@@ -873,3 +883,55 @@ void test_status_worktree__long_filenames(void)
cl_assert_equal_i(0, counts.wrong_sorted_path);
}
/* The update stat cache tests mostly just mirror other tests and try
* to make sure that updating the stat cache doesn't change the results
* while reducing the amount of work that needs to be done
*/
static void check_status0(git_status_list *status)
{
size_t i, max_i = git_status_list_entrycount(status);
cl_assert_equal_sz(entry_count0, max_i);
for (i = 0; i < max_i; ++i) {
const git_status_entry *entry = git_status_byindex(status, i);
cl_assert_equal_i(entry_statuses0[i], entry->status);
}
}
void test_status_worktree__update_stat_cache_0(void)
{
git_repository *repo = cl_git_sandbox_init("status");
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
git_status_list *status;
git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT;
opts.flags = GIT_STATUS_OPT_DEFAULTS;
cl_git_pass(git_status_list_new(&status, repo, &opts));
check_status0(status);
cl_git_pass(git_status_list_get_perfdata(&perf, status));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(5, perf.oid_calculations);
git_status_list_free(status);
opts.flags |= GIT_STATUS_OPT_UPDATE_INDEX;
cl_git_pass(git_status_list_new(&status, repo, &opts));
check_status0(status);
cl_git_pass(git_status_list_get_perfdata(&perf, status));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(5, perf.oid_calculations);
git_status_list_free(status);
opts.flags &= ~GIT_STATUS_OPT_UPDATE_INDEX;
cl_git_pass(git_status_list_new(&status, repo, &opts));
check_status0(status);
cl_git_pass(git_status_list_get_perfdata(&perf, status));
cl_assert_equal_sz(13 + 3, perf.stat_calls);
cl_assert_equal_sz(0, perf.oid_calculations);
git_status_list_free(status);
}
......@@ -48,7 +48,7 @@ void test_structinit_structinit__compare(void)
/* checkout */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_checkout_options, GIT_CHECKOUT_OPTIONS_VERSION, \
GIT_CHECKOUT_OPTIONS_INIT, git_checkout_init_opts);
GIT_CHECKOUT_OPTIONS_INIT, git_checkout_init_options);
/* clone */
CHECK_MACRO_FUNC_INIT_EQUAL( \
......@@ -98,7 +98,7 @@ void test_structinit_structinit__compare(void)
/* revert */
CHECK_MACRO_FUNC_INIT_EQUAL( \
git_revert_options, GIT_REVERT_OPTIONS_VERSION, \
GIT_REVERT_OPTIONS_INIT, git_revert_init_opts);
GIT_REVERT_OPTIONS_INIT, git_revert_init_options);
/* status */
CHECK_MACRO_FUNC_INIT_EQUAL( \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment