mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-26 06:07:06 +00:00
Merge pull request #1499 from arrbee/fix-diff-config-usage
Support more diff config options and use the config cache more
This commit is contained in:
commit
2370b4d79e
@ -1119,7 +1119,6 @@ static int checkout_data_init(
|
||||
git_checkout_opts *proposed)
|
||||
{
|
||||
int error = 0;
|
||||
git_config *cfg;
|
||||
git_repository *repo = git_iterator_owner(target);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
@ -1132,9 +1131,6 @@ static int checkout_data_init(
|
||||
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
|
||||
return error;
|
||||
|
||||
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
|
||||
return error;
|
||||
|
||||
data->repo = repo;
|
||||
|
||||
GITERR_CHECK_VERSION(
|
||||
@ -1147,7 +1143,10 @@ static int checkout_data_init(
|
||||
|
||||
/* refresh config and index content unless NO_REFRESH is given */
|
||||
if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
|
||||
if ((error = git_config_refresh(cfg)) < 0)
|
||||
git_config *cfg;
|
||||
|
||||
if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
|
||||
(error = git_config_refresh(cfg)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* if we are checking out the index, don't reload,
|
||||
@ -1184,19 +1183,13 @@ static int checkout_data_init(
|
||||
|
||||
data->pfx = git_pathspec_prefix(&data->opts.paths);
|
||||
|
||||
error = git_config_get_bool(&data->can_symlink, cfg, "core.symlinks");
|
||||
if (error < 0) {
|
||||
if (error != GIT_ENOTFOUND)
|
||||
goto cleanup;
|
||||
|
||||
/* If "core.symlinks" is not found anywhere, default to true. */
|
||||
data->can_symlink = true;
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
}
|
||||
if ((error = git_repository__cvar(
|
||||
&data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!data->opts.baseline) {
|
||||
data->opts_free_baseline = true;
|
||||
|
||||
error = checkout_lookup_head_tree(&data->opts.baseline, repo);
|
||||
|
||||
if (error == GIT_EORPHANEDHEAD) {
|
||||
|
||||
11
src/config.c
11
src/config.c
@ -293,6 +293,9 @@ int git_config_refresh(git_config *cfg)
|
||||
error = file->refresh(file);
|
||||
}
|
||||
|
||||
if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL)
|
||||
git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -360,6 +363,7 @@ int git_config_set_bool(git_config *cfg, const char *name, int value)
|
||||
|
||||
int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
{
|
||||
int error;
|
||||
git_config_backend *file;
|
||||
file_internal *internal;
|
||||
|
||||
@ -371,7 +375,12 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
||||
internal = git_vector_get(&cfg->files, 0);
|
||||
file = internal->file;
|
||||
|
||||
return file->set(file, name, value);
|
||||
error = file->set(file, name, value);
|
||||
|
||||
if (!error && GIT_REFCOUNT_OWNER(cfg) != NULL)
|
||||
git_repository__cvar_cache_clear(GIT_REFCOUNT_OWNER(cfg));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/***********
|
||||
|
||||
@ -26,7 +26,7 @@ struct map_data {
|
||||
* files that have the text property set. Alternatives are lf, crlf
|
||||
* and native, which uses the platform's native line ending. The default
|
||||
* value is native. See gitattributes(5) for more information on
|
||||
* end-of-line conversion.
|
||||
* end-of-line conversion.
|
||||
*/
|
||||
static git_cvar_map _cvar_map_eol[] = {
|
||||
{GIT_CVAR_FALSE, NULL, GIT_EOL_UNSET},
|
||||
@ -37,7 +37,7 @@ static git_cvar_map _cvar_map_eol[] = {
|
||||
|
||||
/*
|
||||
* core.autocrlf
|
||||
* Setting this variable to "true" is almost the same as setting
|
||||
* Setting this variable to "true" is almost the same as setting
|
||||
* the text attribute to "auto" on all files except that text files are
|
||||
* not guaranteed to be normalized: files that contain CRLF in the
|
||||
* repository will not be touched. Use this setting if you want to have
|
||||
@ -51,9 +51,22 @@ static git_cvar_map _cvar_map_autocrlf[] = {
|
||||
{GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT}
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic map for integer values
|
||||
*/
|
||||
static git_cvar_map _cvar_map_int[] = {
|
||||
{GIT_CVAR_INT32, NULL, 0},
|
||||
};
|
||||
|
||||
static struct map_data _cvar_maps[] = {
|
||||
{"core.autocrlf", _cvar_map_autocrlf, ARRAY_SIZE(_cvar_map_autocrlf), GIT_AUTO_CRLF_DEFAULT},
|
||||
{"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT}
|
||||
{"core.eol", _cvar_map_eol, ARRAY_SIZE(_cvar_map_eol), GIT_EOL_DEFAULT},
|
||||
{"core.symlinks", NULL, 0, GIT_SYMLINKS_DEFAULT },
|
||||
{"core.ignorecase", NULL, 0, GIT_IGNORECASE_DEFAULT },
|
||||
{"core.filemode", NULL, 0, GIT_FILEMODE_DEFAULT },
|
||||
{"core.ignorestat", NULL, 0, GIT_IGNORESTAT_DEFAULT },
|
||||
{"core.trustctime", NULL, 0, GIT_TRUSTCTIME_DEFAULT },
|
||||
{"core.abbrev", _cvar_map_int, 1, GIT_ABBREV_DEFAULT },
|
||||
};
|
||||
|
||||
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
|
||||
@ -69,12 +82,16 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar)
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = git_config_get_mapped(out,
|
||||
config, data->cvar_name, data->maps, data->map_count);
|
||||
if (data->maps)
|
||||
error = git_config_get_mapped(
|
||||
out, config, data->cvar_name, data->maps, data->map_count);
|
||||
else
|
||||
error = git_config_get_bool(out, config, data->cvar_name);
|
||||
|
||||
if (error == GIT_ENOTFOUND)
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
*out = data->default_value;
|
||||
|
||||
}
|
||||
else if (error < 0)
|
||||
return error;
|
||||
|
||||
|
||||
230
src/diff.c
230
src/diff.c
@ -14,6 +14,8 @@
|
||||
|
||||
#define DIFF_FLAG_IS_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) != 0)
|
||||
#define DIFF_FLAG_ISNT_SET(DIFF,FLAG) (((DIFF)->opts.flags & (FLAG)) == 0)
|
||||
#define DIFF_FLAG_SET(DIFF,FLAG,VAL) (DIFF)->opts.flags = \
|
||||
(VAL) ? ((DIFF)->opts.flags | (FLAG)) : ((DIFF)->opts.flags & ~(VAL))
|
||||
|
||||
static git_diff_delta *diff_delta__alloc(
|
||||
git_diff_list *diff,
|
||||
@ -267,67 +269,158 @@ static int config_bool(git_config *cfg, const char *name, int defvalue)
|
||||
return val;
|
||||
}
|
||||
|
||||
static git_diff_list *git_diff_list_alloc(
|
||||
git_repository *repo, const git_diff_options *opts)
|
||||
static int config_int(git_config *cfg, const char *name, int defvalue)
|
||||
{
|
||||
git_config *cfg;
|
||||
int val = defvalue;
|
||||
|
||||
if (git_config_get_int32(&val, cfg, name) < 0)
|
||||
giterr_clear();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const char *diff_mnemonic_prefix(
|
||||
git_iterator_type_t type, bool left_side)
|
||||
{
|
||||
const char *pfx = "";
|
||||
|
||||
switch (type) {
|
||||
case GIT_ITERATOR_TYPE_EMPTY: pfx = "c"; break;
|
||||
case GIT_ITERATOR_TYPE_TREE: pfx = "c"; break;
|
||||
case GIT_ITERATOR_TYPE_INDEX: pfx = "i"; break;
|
||||
case GIT_ITERATOR_TYPE_WORKDIR: pfx = "w"; break;
|
||||
case GIT_ITERATOR_TYPE_FS: pfx = left_side ? "1" : "2"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* note: without a deeper look at pathspecs, there is no easy way
|
||||
* to get the (o)bject / (w)ork tree mnemonics working...
|
||||
*/
|
||||
|
||||
return pfx;
|
||||
}
|
||||
|
||||
static git_diff_list *diff_list_alloc(
|
||||
git_repository *repo,
|
||||
git_iterator *old_iter,
|
||||
git_iterator *new_iter)
|
||||
{
|
||||
git_diff_options dflt = GIT_DIFF_OPTIONS_INIT;
|
||||
git_diff_list *diff = git__calloc(1, sizeof(git_diff_list));
|
||||
if (diff == NULL)
|
||||
if (!diff)
|
||||
return NULL;
|
||||
|
||||
assert(repo && old_iter && new_iter);
|
||||
|
||||
GIT_REFCOUNT_INC(diff);
|
||||
diff->repo = repo;
|
||||
diff->old_src = old_iter->type;
|
||||
diff->new_src = new_iter->type;
|
||||
memcpy(&diff->opts, &dflt, sizeof(diff->opts));
|
||||
|
||||
if (git_vector_init(&diff->deltas, 0, git_diff_delta__cmp) < 0 ||
|
||||
git_pool_init(&diff->pool, 1, 0) < 0)
|
||||
goto fail;
|
||||
git_pool_init(&diff->pool, 1, 0) < 0) {
|
||||
git_diff_list_free(diff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Use case-insensitive compare if either iterator has
|
||||
* the ignore_case bit set */
|
||||
if (!git_iterator_ignore_case(old_iter) &&
|
||||
!git_iterator_ignore_case(new_iter))
|
||||
{
|
||||
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
|
||||
|
||||
diff->strcomp = git__strcmp;
|
||||
diff->strncomp = git__strncmp;
|
||||
diff->pfxcomp = git__prefixcmp;
|
||||
diff->entrycomp = git_index_entry__cmp;
|
||||
} else {
|
||||
diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE;
|
||||
|
||||
diff->strcomp = git__strcasecmp;
|
||||
diff->strncomp = git__strncasecmp;
|
||||
diff->pfxcomp = git__prefixcmp_icase;
|
||||
diff->entrycomp = git_index_entry__cmp_icase;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static int diff_list_apply_options(
|
||||
git_diff_list *diff,
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
git_config *cfg;
|
||||
git_repository *repo = diff->repo;
|
||||
git_pool *pool = &diff->pool;
|
||||
int val;
|
||||
|
||||
if (opts) {
|
||||
/* copy user options (except case sensitivity info from iterators) */
|
||||
bool icase = DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE);
|
||||
memcpy(&diff->opts, opts, sizeof(diff->opts));
|
||||
DIFF_FLAG_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE, icase);
|
||||
|
||||
/* initialize pathspec from options */
|
||||
if (git_pathspec_init(&diff->pathspec, &opts->pathspec, pool) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* flag INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
|
||||
diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
|
||||
|
||||
/* load config values that affect diff behavior */
|
||||
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
||||
goto fail;
|
||||
if (config_bool(cfg, "core.symlinks", 1))
|
||||
return -1;
|
||||
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS) && val)
|
||||
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS;
|
||||
if (config_bool(cfg, "core.ignorestat", 0))
|
||||
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORESTAT) && val)
|
||||
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED;
|
||||
if (config_bool(cfg, "core.filemode", 1))
|
||||
|
||||
if ((diff->opts.flags & GIT_DIFF_IGNORE_FILEMODE) == 0 &&
|
||||
!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE) && val)
|
||||
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_MODE_BITS;
|
||||
if (config_bool(cfg, "core.trustctime", 1))
|
||||
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_TRUSTCTIME) && val)
|
||||
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME;
|
||||
|
||||
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
|
||||
|
||||
/* TODO: there are certain config settings where even if we were
|
||||
* not given an options structure, we need the diff list to have one
|
||||
* so that we can store the altered default values.
|
||||
*
|
||||
* - diff.ignoreSubmodules
|
||||
* - diff.mnemonicprefix
|
||||
* - diff.noprefix
|
||||
*/
|
||||
/* If not given explicit `opts`, check `diff.xyz` configs */
|
||||
if (!opts) {
|
||||
diff->opts.context_lines = config_int(cfg, "diff.context", 3);
|
||||
|
||||
if (opts == NULL) {
|
||||
/* Make sure we default to 3 lines */
|
||||
diff->opts.context_lines = 3;
|
||||
return diff;
|
||||
if (config_bool(cfg, "diff.ignoreSubmodules", 0))
|
||||
diff->opts.flags |= GIT_DIFF_IGNORE_SUBMODULES;
|
||||
}
|
||||
|
||||
memcpy(&diff->opts, opts, sizeof(git_diff_options));
|
||||
/* if either prefix is not set, figure out appropriate value */
|
||||
if (!diff->opts.old_prefix || !diff->opts.new_prefix) {
|
||||
const char *use_old = DIFF_OLD_PREFIX_DEFAULT;
|
||||
const char *use_new = DIFF_NEW_PREFIX_DEFAULT;
|
||||
|
||||
if(opts->flags & GIT_DIFF_IGNORE_FILEMODE)
|
||||
diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS;
|
||||
if (config_bool(cfg, "diff.noprefix", 0)) {
|
||||
use_old = use_new = "";
|
||||
} else if (config_bool(cfg, "diff.mnemonicprefix", 0)) {
|
||||
use_old = diff_mnemonic_prefix(diff->old_src, true);
|
||||
use_new = diff_mnemonic_prefix(diff->new_src, false);
|
||||
}
|
||||
|
||||
/* pathspec init will do nothing for empty pathspec */
|
||||
if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0)
|
||||
goto fail;
|
||||
|
||||
/* TODO: handle config diff.mnemonicprefix, diff.noprefix */
|
||||
|
||||
diff->opts.old_prefix = diff_strdup_prefix(&diff->pool,
|
||||
opts->old_prefix ? opts->old_prefix : DIFF_OLD_PREFIX_DEFAULT);
|
||||
diff->opts.new_prefix = diff_strdup_prefix(&diff->pool,
|
||||
opts->new_prefix ? opts->new_prefix : DIFF_NEW_PREFIX_DEFAULT);
|
||||
if (!diff->opts.old_prefix)
|
||||
diff->opts.old_prefix = use_old;
|
||||
if (!diff->opts.new_prefix)
|
||||
diff->opts.new_prefix = use_new;
|
||||
}
|
||||
|
||||
/* strdup prefix from pool so we're not dependent on external data */
|
||||
diff->opts.old_prefix = diff_strdup_prefix(pool, diff->opts.old_prefix);
|
||||
diff->opts.new_prefix = diff_strdup_prefix(pool, diff->opts.new_prefix);
|
||||
if (!diff->opts.old_prefix || !diff->opts.new_prefix)
|
||||
goto fail;
|
||||
return -1;
|
||||
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_REVERSE)) {
|
||||
const char *swap = diff->opts.old_prefix;
|
||||
@ -335,15 +428,7 @@ static git_diff_list *git_diff_list_alloc(
|
||||
diff->opts.new_prefix = swap;
|
||||
}
|
||||
|
||||
/* INCLUDE_TYPECHANGE_TREES implies INCLUDE_TYPECHANGE */
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
|
||||
diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
|
||||
|
||||
return diff;
|
||||
|
||||
fail:
|
||||
git_diff_list_free(diff);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void diff_list_free(git_diff_list *diff)
|
||||
@ -607,37 +692,6 @@ static bool entry_is_prefixed(
|
||||
item->path[pathlen] == '/');
|
||||
}
|
||||
|
||||
static int diff_list_init_from_iterators(
|
||||
git_diff_list *diff,
|
||||
git_iterator *old_iter,
|
||||
git_iterator *new_iter)
|
||||
{
|
||||
diff->old_src = old_iter->type;
|
||||
diff->new_src = new_iter->type;
|
||||
|
||||
/* Use case-insensitive compare if either iterator has
|
||||
* the ignore_case bit set */
|
||||
if (!git_iterator_ignore_case(old_iter) &&
|
||||
!git_iterator_ignore_case(new_iter))
|
||||
{
|
||||
diff->opts.flags &= ~GIT_DIFF_DELTAS_ARE_ICASE;
|
||||
|
||||
diff->strcomp = git__strcmp;
|
||||
diff->strncomp = git__strncmp;
|
||||
diff->pfxcomp = git__prefixcmp;
|
||||
diff->entrycomp = git_index_entry__cmp;
|
||||
} else {
|
||||
diff->opts.flags |= GIT_DIFF_DELTAS_ARE_ICASE;
|
||||
|
||||
diff->strcomp = git__strcasecmp;
|
||||
diff->strncomp = git__strncasecmp;
|
||||
diff->pfxcomp = git__prefixcmp_icase;
|
||||
diff->entrycomp = git_index_entry__cmp_icase;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_diff__from_iterators(
|
||||
git_diff_list **diff_ptr,
|
||||
git_repository *repo,
|
||||
@ -648,20 +702,22 @@ int git_diff__from_iterators(
|
||||
int error = 0;
|
||||
const git_index_entry *oitem, *nitem;
|
||||
git_buf ignore_prefix = GIT_BUF_INIT;
|
||||
git_diff_list *diff = git_diff_list_alloc(repo, opts);
|
||||
git_diff_list *diff;
|
||||
|
||||
*diff_ptr = NULL;
|
||||
|
||||
if (!diff || diff_list_init_from_iterators(diff, old_iter, new_iter) < 0)
|
||||
goto fail;
|
||||
diff = diff_list_alloc(repo, old_iter, new_iter);
|
||||
GITERR_CHECK_ALLOC(diff);
|
||||
|
||||
/* make iterators have matching icase behavior */
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_DELTAS_ARE_ICASE)) {
|
||||
if (git_iterator_set_ignore_case(old_iter, true) < 0 ||
|
||||
git_iterator_set_ignore_case(new_iter, true) < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (git_iterator_current(&oitem, old_iter) < 0 ||
|
||||
if (diff_list_apply_options(diff, opts) < 0 ||
|
||||
git_iterator_current(&oitem, old_iter) < 0 ||
|
||||
git_iterator_current(&nitem, new_iter) < 0)
|
||||
goto fail;
|
||||
|
||||
@ -859,12 +915,20 @@ int git_diff_tree_to_tree(
|
||||
const git_diff_options *opts)
|
||||
{
|
||||
int error = 0;
|
||||
git_iterator_flag_t iflag = GIT_ITERATOR_DONT_IGNORE_CASE;
|
||||
|
||||
assert(diff && repo);
|
||||
|
||||
/* for tree to tree diff, be case sensitive even if the index is
|
||||
* currently case insensitive, unless the user explicitly asked
|
||||
* for case insensitivity
|
||||
*/
|
||||
if (opts && (opts->flags & GIT_DIFF_DELTAS_ARE_ICASE) != 0)
|
||||
iflag = GIT_ITERATOR_IGNORE_CASE;
|
||||
|
||||
DIFF_FROM_ITERATORS(
|
||||
git_iterator_for_tree(&a, old_tree, 0, pfx, pfx),
|
||||
git_iterator_for_tree(&b, new_tree, 0, pfx, pfx)
|
||||
git_iterator_for_tree(&a, old_tree, iflag, pfx, pfx),
|
||||
git_iterator_for_tree(&b, new_tree, iflag, pfx, pfx)
|
||||
);
|
||||
|
||||
return error;
|
||||
|
||||
@ -1114,11 +1114,20 @@ int git_diff_print_compact(
|
||||
|
||||
static int print_oid_range(diff_print_info *pi, const git_diff_delta *delta)
|
||||
{
|
||||
char start_oid[8], end_oid[8];
|
||||
int abbrevlen;
|
||||
char start_oid[GIT_OID_HEXSZ+1], end_oid[GIT_OID_HEXSZ+1];
|
||||
|
||||
/* TODO: Determine a good actual OID range to print */
|
||||
git_oid_tostr(start_oid, sizeof(start_oid), &delta->old_file.oid);
|
||||
git_oid_tostr(end_oid, sizeof(end_oid), &delta->new_file.oid);
|
||||
if (git_repository__cvar(&abbrevlen, pi->diff->repo, GIT_CVAR_ABBREV) < 0)
|
||||
return -1;
|
||||
|
||||
abbrevlen += 1; /* for NUL byte */
|
||||
if (abbrevlen < 2)
|
||||
abbrevlen = 2;
|
||||
else if (abbrevlen > (int)sizeof(start_oid))
|
||||
abbrevlen = (int)sizeof(start_oid);
|
||||
|
||||
git_oid_tostr(start_oid, abbrevlen, &delta->old_file.oid);
|
||||
git_oid_tostr(end_oid, abbrevlen, &delta->new_file.oid);
|
||||
|
||||
/* TODO: Match git diff more closely */
|
||||
if (delta->old_file.mode == delta->new_file.mode) {
|
||||
|
||||
36
src/ignore.c
36
src/ignore.c
@ -15,24 +15,14 @@ static int parse_ignore_file(
|
||||
git_attr_fnmatch *match = NULL;
|
||||
const char *scan = NULL;
|
||||
char *context = NULL;
|
||||
bool ignore_case = false;
|
||||
git_config *cfg = NULL;
|
||||
int val;
|
||||
int ignore_case = false;
|
||||
|
||||
/* Prefer to have the caller pass in a git_ignores as the parsedata object.
|
||||
* If they did not, then we can (much more slowly) find the value of
|
||||
* ignore_case by using the repository object. */
|
||||
if (parsedata != NULL) {
|
||||
/* Prefer to have the caller pass in a git_ignores as the parsedata
|
||||
* object. If they did not, then look up the value of ignore_case */
|
||||
if (parsedata != NULL)
|
||||
ignore_case = ((git_ignores *)parsedata)->ignore_case;
|
||||
} else {
|
||||
if ((error = git_repository_config(&cfg, repo)) < 0)
|
||||
return error;
|
||||
|
||||
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
|
||||
ignore_case = (val != 0);
|
||||
|
||||
git_config_free(cfg);
|
||||
}
|
||||
else if (git_repository__cvar(&ignore_case, repo, GIT_CVAR_IGNORECASE) < 0)
|
||||
return error;
|
||||
|
||||
if (ignores->key && git__suffixcmp(ignores->key, "/" GIT_IGNORE_FILE) == 0) {
|
||||
context = ignores->key + 2;
|
||||
@ -109,8 +99,6 @@ int git_ignore__for_path(
|
||||
{
|
||||
int error = 0;
|
||||
const char *workdir = git_repository_workdir(repo);
|
||||
git_config *cfg = NULL;
|
||||
int val;
|
||||
|
||||
assert(ignores);
|
||||
|
||||
@ -118,17 +106,11 @@ int git_ignore__for_path(
|
||||
git_buf_init(&ignores->dir, 0);
|
||||
ignores->ign_internal = NULL;
|
||||
|
||||
/* Set the ignore_case flag appropriately */
|
||||
if ((error = git_repository_config(&cfg, repo)) < 0)
|
||||
/* Read the ignore_case flag */
|
||||
if ((error = git_repository__cvar(
|
||||
&ignores->ignore_case, repo, GIT_CVAR_IGNORECASE)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
|
||||
ignores->ignore_case = (val != 0);
|
||||
else
|
||||
ignores->ignore_case = 0;
|
||||
|
||||
git_config_free(cfg);
|
||||
|
||||
if ((error = git_vector_init(&ignores->ign_path, 8, NULL)) < 0 ||
|
||||
(error = git_vector_init(&ignores->ign_global, 2, NULL)) < 0 ||
|
||||
(error = git_attr_cache__init(repo)) < 0)
|
||||
|
||||
@ -28,7 +28,7 @@ typedef struct {
|
||||
git_attr_file *ign_internal;
|
||||
git_vector ign_path;
|
||||
git_vector ign_global;
|
||||
unsigned int ignore_case:1;
|
||||
int ignore_case;
|
||||
} git_ignores;
|
||||
|
||||
extern int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ign);
|
||||
|
||||
17
src/index.c
17
src/index.c
@ -330,7 +330,7 @@ void git_index_clear(git_index *index)
|
||||
git_vector_clear(&index->entries);
|
||||
|
||||
git_index_reuc_clear(index);
|
||||
|
||||
|
||||
git_futils_filestamp_set(&index->stamp, NULL);
|
||||
|
||||
git_tree_cache_free(index->tree);
|
||||
@ -352,19 +352,18 @@ int git_index_set_caps(git_index *index, unsigned int caps)
|
||||
old_ignore_case = index->ignore_case;
|
||||
|
||||
if (caps == GIT_INDEXCAP_FROM_OWNER) {
|
||||
git_config *cfg;
|
||||
git_repository *repo = INDEX_OWNER(index);
|
||||
int val;
|
||||
|
||||
if (INDEX_OWNER(index) == NULL ||
|
||||
git_repository_config__weakptr(&cfg, INDEX_OWNER(index)) < 0)
|
||||
return create_index_error(-1,
|
||||
"Cannot get repository config to set index caps");
|
||||
if (!repo)
|
||||
return create_index_error(
|
||||
-1, "Cannot access repository to set index caps");
|
||||
|
||||
if (git_config_get_bool(&val, cfg, "core.ignorecase") == 0)
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_IGNORECASE))
|
||||
index->ignore_case = (val != 0);
|
||||
if (git_config_get_bool(&val, cfg, "core.filemode") == 0)
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_FILEMODE))
|
||||
index->distrust_filemode = (val == 0);
|
||||
if (git_config_get_bool(&val, cfg, "core.symlinks") == 0)
|
||||
if (!git_repository__cvar(&val, repo, GIT_CVAR_SYMLINKS))
|
||||
index->no_symlinks = (val == 0);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "git2/odb.h"
|
||||
#include "git2/repository.h"
|
||||
#include "git2/object.h"
|
||||
#include "git2/config.h"
|
||||
|
||||
#include "index.h"
|
||||
#include "cache.h"
|
||||
@ -31,7 +32,13 @@
|
||||
/** Cvar cache identifiers */
|
||||
typedef enum {
|
||||
GIT_CVAR_AUTO_CRLF = 0, /* core.autocrlf */
|
||||
GIT_CVAR_EOL, /* core.eol */
|
||||
GIT_CVAR_EOL, /* core.eol */
|
||||
GIT_CVAR_SYMLINKS, /* core.symlinks */
|
||||
GIT_CVAR_IGNORECASE, /* core.ignorecase */
|
||||
GIT_CVAR_FILEMODE, /* core.filemode */
|
||||
GIT_CVAR_IGNORESTAT, /* core.ignorestat */
|
||||
GIT_CVAR_TRUSTCTIME, /* core.trustctime */
|
||||
GIT_CVAR_ABBREV, /* core.abbrev */
|
||||
GIT_CVAR_CACHE_MAX
|
||||
} git_cvar_cached;
|
||||
|
||||
@ -67,7 +74,21 @@ typedef enum {
|
||||
#else
|
||||
GIT_EOL_NATIVE = GIT_EOL_LF,
|
||||
#endif
|
||||
GIT_EOL_DEFAULT = GIT_EOL_NATIVE
|
||||
GIT_EOL_DEFAULT = GIT_EOL_NATIVE,
|
||||
|
||||
/* core.symlinks: bool */
|
||||
GIT_SYMLINKS_DEFAULT = GIT_CVAR_TRUE,
|
||||
/* core.ignorecase */
|
||||
GIT_IGNORECASE_DEFAULT = GIT_CVAR_FALSE,
|
||||
/* core.filemode */
|
||||
GIT_FILEMODE_DEFAULT = GIT_CVAR_TRUE,
|
||||
/* core.ignorestat */
|
||||
GIT_IGNORESTAT_DEFAULT = GIT_CVAR_FALSE,
|
||||
/* core.trustctime */
|
||||
GIT_TRUSTCTIME_DEFAULT = GIT_CVAR_TRUE,
|
||||
/* core.abbrev */
|
||||
GIT_ABBREV_DEFAULT = 7,
|
||||
|
||||
} git_cvar_value;
|
||||
|
||||
/* internal repository init flags */
|
||||
|
||||
@ -135,6 +135,84 @@ void test_diff_patch__to_string(void)
|
||||
git_tree_free(one);
|
||||
}
|
||||
|
||||
void test_diff_patch__config_options(void)
|
||||
{
|
||||
const char *one_sha = "26a125e"; /* current HEAD */
|
||||
git_tree *one;
|
||||
git_config *cfg;
|
||||
git_diff_list *diff;
|
||||
git_diff_patch *patch;
|
||||
char *text;
|
||||
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
|
||||
char *onefile = "staged_changes_modified_file";
|
||||
const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
|
||||
const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
|
||||
const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
|
||||
const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
|
||||
|
||||
g_repo = cl_git_sandbox_init("status");
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
one = resolve_commit_oid_to_tree(g_repo, one_sha);
|
||||
opts.pathspec.count = 1;
|
||||
opts.pathspec.strings = &onefile;
|
||||
|
||||
|
||||
cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true"));
|
||||
|
||||
cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
|
||||
|
||||
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
|
||||
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
|
||||
cl_git_pass(git_diff_patch_to_str(&text, patch));
|
||||
cl_assert_equal_s(expected1, text);
|
||||
|
||||
git__free(text);
|
||||
git_diff_patch_free(patch);
|
||||
git_diff_list_free(diff);
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
|
||||
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
|
||||
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
|
||||
cl_git_pass(git_diff_patch_to_str(&text, patch));
|
||||
cl_assert_equal_s(expected2, text);
|
||||
|
||||
git__free(text);
|
||||
git_diff_patch_free(patch);
|
||||
git_diff_list_free(diff);
|
||||
|
||||
|
||||
cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true"));
|
||||
|
||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||
|
||||
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
|
||||
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
|
||||
cl_git_pass(git_diff_patch_to_str(&text, patch));
|
||||
cl_assert_equal_s(expected3, text);
|
||||
|
||||
git__free(text);
|
||||
git_diff_patch_free(patch);
|
||||
git_diff_list_free(diff);
|
||||
|
||||
|
||||
cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12));
|
||||
|
||||
cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
|
||||
|
||||
cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
|
||||
cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 0));
|
||||
cl_git_pass(git_diff_patch_to_str(&text, patch));
|
||||
cl_assert_equal_s(expected4, text);
|
||||
|
||||
git__free(text);
|
||||
git_diff_patch_free(patch);
|
||||
git_diff_list_free(diff);
|
||||
|
||||
git_tree_free(one);
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_diff_patch__hunks_have_correct_line_numbers(void)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
@ -454,3 +454,77 @@ void test_diff_tree__issue_1397(void)
|
||||
cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
|
||||
cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]);
|
||||
}
|
||||
|
||||
static void set_config_int(git_repository *repo, const char *name, int value)
|
||||
{
|
||||
git_config *cfg;
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, repo));
|
||||
cl_git_pass(git_config_set_int32(cfg, name, value));
|
||||
git_config_free(cfg);
|
||||
}
|
||||
|
||||
void test_diff_tree__diff_configs(void)
|
||||
{
|
||||
const char *a_commit = "d70d245e";
|
||||
const char *b_commit = "7a9e0b02";
|
||||
|
||||
g_repo = cl_git_sandbox_init("diff");
|
||||
|
||||
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
|
||||
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
|
||||
|
||||
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
|
||||
|
||||
cl_git_pass(git_diff_foreach(
|
||||
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
|
||||
|
||||
cl_assert_equal_i(2, expect.files);
|
||||
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(6, expect.hunks);
|
||||
cl_assert_equal_i(55, expect.lines);
|
||||
cl_assert_equal_i(33, expect.line_ctxt);
|
||||
cl_assert_equal_i(7, expect.line_adds);
|
||||
cl_assert_equal_i(15, expect.line_dels);
|
||||
|
||||
git_diff_list_free(diff);
|
||||
diff = NULL;
|
||||
|
||||
set_config_int(g_repo, "diff.context", 1);
|
||||
|
||||
memset(&expect, 0, sizeof(expect));
|
||||
|
||||
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
|
||||
|
||||
cl_git_pass(git_diff_foreach(
|
||||
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
|
||||
|
||||
cl_assert_equal_i(2, expect.files);
|
||||
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(7, expect.hunks);
|
||||
cl_assert_equal_i(34, expect.lines);
|
||||
cl_assert_equal_i(12, expect.line_ctxt);
|
||||
cl_assert_equal_i(7, expect.line_adds);
|
||||
cl_assert_equal_i(15, expect.line_dels);
|
||||
|
||||
git_diff_list_free(diff);
|
||||
diff = NULL;
|
||||
|
||||
set_config_int(g_repo, "diff.context", 0);
|
||||
set_config_int(g_repo, "diff.noprefix", 1);
|
||||
|
||||
memset(&expect, 0, sizeof(expect));
|
||||
|
||||
cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
|
||||
|
||||
cl_git_pass(git_diff_foreach(
|
||||
diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &expect));
|
||||
|
||||
cl_assert_equal_i(2, expect.files);
|
||||
cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
|
||||
cl_assert_equal_i(7, expect.hunks);
|
||||
cl_assert_equal_i(22, expect.lines);
|
||||
cl_assert_equal_i(0, expect.line_ctxt);
|
||||
cl_assert_equal_i(7, expect.line_adds);
|
||||
cl_assert_equal_i(15, expect.line_dels);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user