summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/checkout.c23
-rw-r--r--src/config.c11
-rw-r--r--src/config_cache.c31
-rw-r--r--src/diff.c230
-rw-r--r--src/diff_output.c17
-rw-r--r--src/ignore.c38
-rw-r--r--src/ignore.h2
-rw-r--r--src/index.c17
-rw-r--r--src/repository.h25
-rw-r--r--tests-clar/diff/patch.c78
-rw-r--r--tests-clar/diff/tree.c74
11 files changed, 396 insertions, 150 deletions
diff --git a/src/checkout.c b/src/checkout.c
index 62a73d6d0..e29fccd05 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -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) {
diff --git a/src/config.c b/src/config.c
index 1283522ca..3c0bbe9a7 100644
--- a/src/config.c
+++ b/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;
}
/***********
diff --git a/src/config_cache.c b/src/config_cache.c
index 2f36df7d1..84de3a5ed 100644
--- a/src/config_cache.c
+++ b/src/config_cache.c
@@ -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;
diff --git a/src/diff.c b/src/diff.c
index 37c89f3f1..881173cde 100644
--- a/src/diff.c
+++ b/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(opts->flags & GIT_DIFF_IGNORE_FILEMODE)
- diff->diffcaps = diff->diffcaps & ~GIT_DIFFCAPS_TRUST_MODE_BITS;
-
- /* pathspec init will do nothing for empty pathspec */
- if (git_pathspec_init(&diff->pathspec, &opts->pathspec, &diff->pool) < 0)
- goto fail;
+ /* 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;
- /* TODO: handle config diff.mnemonicprefix, diff.noprefix */
+ 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);
+ }
- 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;
diff --git a/src/diff_output.c b/src/diff_output.c
index 34a3e506c..b8bb73bf7 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -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) {
diff --git a/src/ignore.c b/src/ignore.c
index 17779522c..e150b9585 100644
--- a/src/ignore.c
+++ b/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;
-
- /* 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) {
- 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);
+ int ignore_case = false;
- git_config_free(cfg);
- }
+ /* 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 (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)
diff --git a/src/ignore.h b/src/ignore.h
index 5af8e8e7d..e00e4a8c8 100644
--- a/src/ignore.h
+++ b/src/ignore.h
@@ -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);
diff --git a/src/index.c b/src/index.c
index 2afd28158..d8ca78e52 100644
--- a/src/index.c
+++ b/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 {
diff --git a/src/repository.h b/src/repository.h
index cc2f8c2b8..f7f9ecb1f 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -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 */
diff --git a/tests-clar/diff/patch.c b/tests-clar/diff/patch.c
index d41f3f12d..40b191dd5 100644
--- a/tests-clar/diff/patch.c
+++ b/tests-clar/diff/patch.c
@@ -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;
diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c
index 850feefde..f05c7869e 100644
--- a/tests-clar/diff/tree.c
+++ b/tests-clar/diff/tree.c
@@ -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);
+}