Commit 95dfb031 by Russell Belfer

Improve config handling for diff,submodules,attrs

This adds support for a bunch of core.* settings that affect
diff and status, plus fixes up some incorrect implementations
of those settings from before.  Also, this cleans up the
handling of config settings in the new submodules code and
in the old attrs/ignore code.
parent bfc9ca59
......@@ -22,7 +22,7 @@ GIT_BEGIN_DECL
typedef enum {
GIT_SUBMODULE_UPDATE_CHECKOUT = 0,
GIT_SUBMOUDLE_UPDATE_REBASE = 1,
GIT_SUBMODULE_UPDATE_REBASE = 1,
GIT_SUBMODULE_UPDATE_MERGE = 2
} git_submodule_update_t;
......@@ -80,8 +80,6 @@ GIT_EXTERN(int) git_submodule_foreach(
int (*callback)(const char *name, void *payload),
void *payload);
#define GIT_SUBMODULE_HEAD "[internal]HEAD"
/**
* Lookup submodule information by name or path.
*
......
......@@ -196,7 +196,8 @@ bool git_attr_cache__is_cached(git_repository *repo, const char *path)
const char *cache_key = path;
if (repo && git__prefixcmp(cache_key, git_repository_workdir(repo)) == 0)
cache_key += strlen(git_repository_workdir(repo));
return (git_hashtable_lookup(repo->attrcache.files, cache_key) != NULL);
return (git_hashtable_lookup(
git_repository_attr_cache(repo)->files, cache_key) != NULL);
}
int git_attr_cache__lookup_or_create_file(
......@@ -207,7 +208,7 @@ int git_attr_cache__lookup_or_create_file(
git_attr_file **file_ptr)
{
int error;
git_attr_cache *cache = &repo->attrcache;
git_attr_cache *cache = git_repository_attr_cache(repo);
git_attr_file *file = NULL;
if ((file = git_hashtable_lookup(cache->files, key)) != NULL) {
......@@ -293,7 +294,6 @@ static int collect_attr_files(
{
int error;
git_buf dir = GIT_BUF_INIT;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info;
......@@ -312,7 +312,8 @@ static int collect_attr_files(
* - $GIT_PREFIX/etc/gitattributes
*/
error = push_attrs(repo, files, repo->path_repository, GIT_ATTR_FILE_INREPO);
error = push_attrs(
repo, files, git_repository_path(repo), GIT_ATTR_FILE_INREPO);
if (error < 0)
goto cleanup;
......@@ -322,22 +323,18 @@ static int collect_attr_files(
if (error < 0)
goto cleanup;
if (!(error = git_repository_config(&cfg, repo))) {
const char *core_attribs = NULL;
git_config_get_string(cfg, GIT_ATTR_CONFIG, &core_attribs);
git_clearerror(); /* don't care if attributesfile is not set */
if (core_attribs)
error = push_attrs(repo, files, NULL, core_attribs);
git_config_free(cfg);
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
error = push_attrs(
repo, files, NULL, git_repository_attr_cache(repo)->cfg_attr_file);
if (error < 0)
goto cleanup;
}
if (!error) {
error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
if (!error)
error = push_attrs(repo, files, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND)
error = 0;
}
error = git_futils_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
if (!error)
error = push_attrs(repo, files, NULL, dir.ptr);
else if (error == GIT_ENOTFOUND)
error = 0;
cleanup:
if (error < 0)
......@@ -350,11 +347,26 @@ static int collect_attr_files(
int git_attr_cache__init(git_repository *repo)
{
git_attr_cache *cache = &repo->attrcache;
git_attr_cache *cache = git_repository_attr_cache(repo);
git_config *cfg;
if (cache->initialized)
return 0;
/* cache config settings for attributes and ignores */
if (git_repository_config(&cfg, repo) < 0)
return -1;
if (git_config_get_string(cfg, GIT_ATTR_CONFIG, &cache->cfg_attr_file)) {
giterr_clear();
cache->cfg_attr_file = NULL;
}
if (git_config_get_string(cfg, GIT_IGNORE_CONFIG, &cache->cfg_excl_file)) {
giterr_clear();
cache->cfg_excl_file = NULL;
}
git_config_free(cfg);
/* allocate hashtable for attribute and ignore file contents */
if (cache->files == NULL) {
cache->files = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb);
......@@ -362,6 +374,7 @@ int git_attr_cache__init(git_repository *repo)
return -1;
}
/* allocate hashtable for attribute macros */
if (cache->macros == NULL) {
cache->macros = git_hashtable_alloc(
8, git_hash__strhash_cb, git_hash__strcmp_cb);
......@@ -378,30 +391,30 @@ int git_attr_cache__init(git_repository *repo)
void git_attr_cache_flush(
git_repository *repo)
{
git_hashtable *table;
if (!repo)
return;
if (repo->attrcache.files) {
if ((table = git_repository_attr_cache(repo)->files) != NULL) {
git_attr_file *file;
GIT_HASHTABLE_FOREACH_VALUE(repo->attrcache.files, file,
git_attr_file__free(file));
GIT_HASHTABLE_FOREACH_VALUE(table, file, git_attr_file__free(file));
git_hashtable_free(table);
git_hashtable_free(repo->attrcache.files);
repo->attrcache.files = NULL;
git_repository_attr_cache(repo)->files = NULL;
}
if (repo->attrcache.macros) {
if ((table = git_repository_attr_cache(repo)->macros) != NULL) {
git_attr_rule *rule;
GIT_HASHTABLE_FOREACH_VALUE(repo->attrcache.macros, rule,
git_attr_rule__free(rule));
GIT_HASHTABLE_FOREACH_VALUE(table, rule, git_attr_rule__free(rule));
git_hashtable_free(table);
git_hashtable_free(repo->attrcache.macros);
repo->attrcache.macros = NULL;
git_repository_attr_cache(repo)->macros = NULL;
}
repo->attrcache.initialized = 0;
git_repository_attr_cache(repo)->initialized = 0;
}
int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
......@@ -411,5 +424,5 @@ int git_attr_cache__insert_macro(git_repository *repo, git_attr_rule *macro)
return 0;
return git_hashtable_insert(
repo->attrcache.macros, macro->match.pattern, macro);
git_repository_attr_cache(repo)->macros, macro->match.pattern, macro);
}
......@@ -9,10 +9,15 @@
#include "attr_file.h"
#define GIT_ATTR_CONFIG "core.attributesfile"
#define GIT_IGNORE_CONFIG "core.excludesfile"
typedef struct {
int initialized;
git_hashtable *files; /* hash path to git_attr_file of rules */
git_hashtable *macros; /* hash name to vector<git_attr_assignment> */
const char *cfg_attr_file; /* cached value of core.attributesfile */
const char *cfg_excl_file; /* cached value of core.excludesfile */
} git_attr_cache;
extern int git_attr_cache__init(git_repository *repo);
......
......@@ -495,8 +495,8 @@ int git_attr_assignment__parse(
/* expand macros (if given a repo with a macro cache) */
if (repo != NULL && assign->value == git_attr__true) {
git_attr_rule *macro =
git_hashtable_lookup(repo->attrcache.macros, assign->name);
git_attr_rule *macro = git_hashtable_lookup(
git_repository_attr_cache(repo)->macros, assign->name);
if (macro != NULL) {
unsigned int i;
......
......@@ -14,7 +14,6 @@
#define GIT_ATTR_FILE ".gitattributes"
#define GIT_ATTR_FILE_INREPO "info/attributes"
#define GIT_ATTR_FILE_SYSTEM "gitattributes"
#define GIT_ATTR_CONFIG "core.attributesfile"
#define GIT_ATTR_FNMATCH_NEGATIVE (1U << 0)
#define GIT_ATTR_FNMATCH_DIRECTORY (1U << 1)
......
......@@ -140,7 +140,7 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority)
int git_config_foreach(git_config *cfg, int (*fn)(const char *, const char *, void *), void *data)
{
int ret = GIT_SUCCESS;
int ret = 0;
unsigned int i;
file_internal *internal;
git_config_file *file;
......@@ -206,20 +206,20 @@ int git_config_parse_bool(int *out, const char *value)
/* A missing value means true */
if (value == NULL) {
*out = 1;
return GIT_SUCCESS;
return 0;
}
if (!strcasecmp(value, "true") ||
!strcasecmp(value, "yes") ||
!strcasecmp(value, "on")) {
*out = 1;
return GIT_SUCCESS;
return 0;
}
if (!strcasecmp(value, "false") ||
!strcasecmp(value, "no") ||
!strcasecmp(value, "off")) {
*out = 0;
return GIT_SUCCESS;
return 0;
}
return GIT_EINVALIDTYPE;
......@@ -283,46 +283,58 @@ static int parse_int32(int32_t *out, const char *value)
/***********
* Getters
***********/
int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out)
int git_config_lookup_map_value(
git_cvar_map *maps, size_t map_n, const char *value, int *out)
{
size_t i;
const char *value;
int error;
error = git_config_get_string(cfg, name, &value);
if (error < GIT_SUCCESS)
return error;
if (!value)
return GIT_ENOTFOUND;
for (i = 0; i < map_n; ++i) {
git_cvar_map *m = maps + i;
switch (m->cvar_type) {
case GIT_CVAR_FALSE:
case GIT_CVAR_TRUE: {
int bool_val;
case GIT_CVAR_FALSE:
case GIT_CVAR_TRUE: {
int bool_val;
if (git_config_parse_bool(&bool_val, value) == 0 &&
bool_val == (int)m->cvar_type) {
*out = m->map_value;
return 0;
}
break;
}
if (git_config_parse_bool(&bool_val, value) == 0 &&
bool_val == (int)m->cvar_type) {
*out = m->map_value;
return 0;
}
case GIT_CVAR_INT32:
if (parse_int32(out, value) == 0)
return 0;
break;
break;
case GIT_CVAR_STRING:
if (strcasecmp(value, m->str_match) == 0) {
*out = m->map_value;
return 0;
}
break;
}
}
case GIT_CVAR_INT32:
if (parse_int32(out, value) == 0)
return 0;
return GIT_ENOTFOUND;
}
break;
int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out)
{
const char *value;
int error;
case GIT_CVAR_STRING:
if (strcasecmp(value, m->str_match) == 0) {
*out = m->map_value;
return 0;
}
}
}
error = git_config_get_string(cfg, name, &value);
if (error < 0)
return error;
if (!git_config_lookup_map_value(maps, map_n, value, out))
return 0;
giterr_set(GITERR_CONFIG,
"Failed to map the '%s' config variable with a valid value", name);
......@@ -449,7 +461,7 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
internal = git_vector_get(&cfg->files, i - 1);
file = internal->file;
ret = file->set_multivar(file, name, regexp, value);
if (ret < GIT_SUCCESS && ret != GIT_ENOTFOUND)
if (ret < 0 && ret != GIT_ENOTFOUND)
return ret;
}
......
......@@ -27,4 +27,7 @@ extern int git_config_find_system_r(git_buf *system_config_path);
extern int git_config_parse_bool(int *out, const char *bool_string);
extern int git_config_lookup_map_value(
git_cvar_map *maps, size_t map_n, const char *value, int *out);
#endif
......@@ -8,6 +8,7 @@
#include "git2/diff.h"
#include "diff.h"
#include "fileops.h"
#include "config.h"
static void diff_delta__free(git_diff_delta *delta)
{
......@@ -233,15 +234,38 @@ static int diff_delta__cmp(const void *a, const void *b)
return val ? val : ((int)da->status - (int)db->status);
}
static int config_bool(git_config *cfg, const char *name, int defvalue)
{
int val = defvalue;
if (git_config_get_bool(cfg, name, &val) < 0)
giterr_clear();
return val;
}
static git_diff_list *git_diff_list_alloc(
git_repository *repo, const git_diff_options *opts)
{
git_config *cfg;
git_diff_list *diff = git__calloc(1, sizeof(git_diff_list));
if (diff == NULL)
return NULL;
diff->repo = repo;
/* load config values that affect diff behavior */
if (git_repository_config(&cfg, repo) < 0)
goto fail;
if (config_bool(cfg, "core.symlinks", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_HAS_SYMLINKS;
if (config_bool(cfg, "core.ignorestat", 0))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_ASSUME_UNCHANGED;
if (config_bool(cfg, "core.filemode", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_EXEC_BIT;
if (config_bool(cfg, "core.trustctime", 1))
diff->diffcaps = diff->diffcaps | GIT_DIFFCAPS_TRUST_CTIME;
/* Don't set GIT_DIFFCAPS_USE_DEV - compile time option in core git */
git_config_free(cfg);
if (opts == NULL)
return diff;
......@@ -252,10 +276,8 @@ static git_diff_list *git_diff_list_alloc(
diff->opts.dst_prefix = diff_strdup_prefix(
opts->dst_prefix ? opts->dst_prefix : DIFF_DST_PREFIX_DEFAULT);
if (!diff->opts.src_prefix || !diff->opts.dst_prefix) {
git__free(diff);
return NULL;
}
if (!diff->opts.src_prefix || !diff->opts.dst_prefix)
goto fail;
if (diff->opts.flags & GIT_DIFF_REVERSE) {
char *swap = diff->opts.src_prefix;
......@@ -263,16 +285,19 @@ static git_diff_list *git_diff_list_alloc(
diff->opts.dst_prefix = swap;
}
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0) {
git__free(diff->opts.src_prefix);
git__free(diff->opts.dst_prefix);
git__free(diff);
return NULL;
}
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0)
goto fail;
/* TODO: do something safe with the pathspec strarray */
return diff;
fail:
git_vector_free(&diff->deltas);
git__free(diff->opts.src_prefix);
git__free(diff->opts.dst_prefix);
git__free(diff);
return NULL;
}
void git_diff_list_free(git_diff_list *diff)
......@@ -326,6 +351,8 @@ static int oid_for_workdir_item(
return result;
}
#define EXEC_BIT_MASK 0000111
static int maybe_modified(
git_iterator *old,
const git_index_entry *oitem,
......@@ -335,16 +362,33 @@ static int maybe_modified(
{
git_oid noid, *use_noid = NULL;
git_delta_t status = GIT_DELTA_MODIFIED;
unsigned int omode = oitem->mode;
unsigned int nmode = nitem->mode;
GIT_UNUSED(old);
/* support "assume unchanged" & "skip worktree" bits */
if ((oitem->flags_extended & GIT_IDXENTRY_INTENT_TO_ADD) != 0 ||
(oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
/* on platforms with no symlinks, promote plain files to symlinks */
if (S_ISLNK(omode) && S_ISREG(nmode) &&
!(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS))
nmode = GIT_MODE_TYPE(omode) | (nmode & GIT_MODE_PERMS_MASK);
/* on platforms with no execmode, clear exec bit from comparisons */
if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_EXEC_BIT)) {
omode = omode & ~EXEC_BIT_MASK;
nmode = nmode & ~EXEC_BIT_MASK;
}
/* support "assume unchanged" (badly, b/c we still stat everything) */
if ((diff->diffcaps & GIT_DIFFCAPS_ASSUME_UNCHANGED) != 0)
status = (oitem->flags_extended & GIT_IDXENTRY_INTENT_TO_ADD) ?
GIT_DELTA_MODIFIED : GIT_DELTA_UNMODIFIED;
/* support "skip worktree" index bit */
else if ((oitem->flags_extended & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
status = GIT_DELTA_UNMODIFIED;
/* if basic type of file changed, then split into delete and add */
else if (GIT_MODE_TYPE(oitem->mode) != GIT_MODE_TYPE(nitem->mode)) {
else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
return -1;
......@@ -353,24 +397,39 @@ static int maybe_modified(
/* if oids and modes match, then file is unmodified */
else if (git_oid_cmp(&oitem->oid, &nitem->oid) == 0 &&
oitem->mode == nitem->mode)
omode == nmode)
status = GIT_DELTA_UNMODIFIED;
/* if we have a workdir item with an unknown oid, check deeper */
else if (git_oid_iszero(&nitem->oid) && new->type == GIT_ITERATOR_WORKDIR) {
/* TODO: add check against index file st_mtime to avoid racy-git */
/* if they files look exactly alike, then we'll assume the same */
if (oitem->file_size == nitem->file_size &&
oitem->ctime.seconds == nitem->ctime.seconds &&
(!(diff->diffcaps & GIT_DIFFCAPS_TRUST_CTIME) ||
(oitem->ctime.seconds == nitem->ctime.seconds)) &&
oitem->mtime.seconds == nitem->mtime.seconds &&
oitem->dev == nitem->dev &&
(!(diff->diffcaps & GIT_DIFFCAPS_USE_DEV) ||
(oitem->dev == nitem->dev)) &&
oitem->ino == nitem->ino &&
oitem->uid == nitem->uid &&
oitem->gid == nitem->gid)
status = GIT_DELTA_UNMODIFIED;
/* TODO? should we do anything special with submodules? */
else if (S_ISGITLINK(nitem->mode))
status = GIT_DELTA_UNMODIFIED;
else if (S_ISGITLINK(nmode)) {
git_submodule *sub;
if ((diff->opts.flags & GIT_DIFF_IGNORE_SUBMODULES) != 0)
status = GIT_DELTA_UNMODIFIED;
else if (git_submodule_lookup(&sub, diff->repo, nitem->path) < 0)
return -1;
else if (sub->ignore == GIT_SUBMODULE_IGNORE_ALL)
status = GIT_DELTA_UNMODIFIED;
else {
/* TODO: support other GIT_SUBMODULE_IGNORE values */
status = GIT_DELTA_UNMODIFIED;
}
}
/* TODO: check git attributes so we will not have to read the file
* in if it is marked binary.
......@@ -380,7 +439,7 @@ static int maybe_modified(
return -1;
else if (git_oid_cmp(&oitem->oid, &noid) == 0 &&
oitem->mode == nitem->mode)
omode == nmode)
status = GIT_DELTA_UNMODIFIED;
/* store calculated oid so we don't have to recalc later */
......
......@@ -13,12 +13,21 @@
#include "iterator.h"
#include "repository.h"
enum {
GIT_DIFFCAPS_HAS_SYMLINKS = (1 << 0), /* symlinks on platform? */
GIT_DIFFCAPS_ASSUME_UNCHANGED = (1 << 1), /* use stat? */
GIT_DIFFCAPS_TRUST_EXEC_BIT = (1 << 2), /* use st_mode exec bit? */
GIT_DIFFCAPS_TRUST_CTIME = (1 << 3), /* use st_ctime? */
GIT_DIFFCAPS_USE_DEV = (1 << 4), /* use st_dev? */
};
struct git_diff_list {
git_repository *repo;
git_diff_options opts;
git_vector deltas; /* vector of git_diff_file_delta */
git_iterator_type_t old_src;
git_iterator_type_t new_src;
uint32_t diffcaps;
};
#endif
......
#include "ignore.h"
#include "path.h"
#include "git2/config.h"
#define GIT_IGNORE_INTERNAL "[internal]exclude"
#define GIT_IGNORE_FILE_INREPO "info/exclude"
#define GIT_IGNORE_FILE ".gitignore"
#define GIT_IGNORE_CONFIG "core.excludesfile"
static int load_ignore_file(
git_repository *repo, const char *path, git_attr_file *ignores)
......@@ -73,7 +71,6 @@ static int push_one_ignore(void *ref, git_buf *path)
int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ignores)
{
int error = 0;
git_config *cfg;
const char *workdir = git_repository_workdir(repo);
assert(ignores);
......@@ -104,26 +101,19 @@ int git_ignore__for_path(git_repository *repo, const char *path, git_ignores *ig
/* load .git/info/exclude */
error = push_ignore(repo, &ignores->ign_global,
repo->path_repository, GIT_IGNORE_FILE_INREPO);
git_repository_path(repo), GIT_IGNORE_FILE_INREPO);
if (error < 0)
goto cleanup;
/* load core.excludesfile */
if ((error = git_repository_config(&cfg, repo)) == 0) {
const char *core_ignore;
error = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &core_ignore);
if (error == 0 && core_ignore != NULL)
error = push_ignore(repo, &ignores->ign_global, NULL, core_ignore);
else {
error = 0;
giterr_clear(); /* don't care if attributesfile is not set */
}
git_config_free(cfg);
}
if (git_repository_attr_cache(repo)->cfg_excl_file != NULL)
error = push_ignore(repo, &ignores->ign_global, NULL,
git_repository_attr_cache(repo)->cfg_excl_file);
cleanup:
if (error < 0)
git_ignore__free(ignores);
return error;
}
......
......@@ -101,6 +101,11 @@ void git_object__free(void *object);
int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header);
void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid);
GIT_INLINE(git_attr_cache *) git_repository_attr_cache(git_repository *repo)
{
return &repo->attrcache;
}
/*
* Weak pointers to repository internals.
*
......
......@@ -19,30 +19,19 @@
#include "config.h"
#include "repository.h"
static const char *sm_update_values[] = {
"checkout",
"rebase",
"merge",
NULL
static git_cvar_map _sm_update_map[] = {
{GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
{GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
{GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE}
};
static const char *sm_ignore_values[] = {
"all",
"dirty",
"untracked",
"none",
NULL
static git_cvar_map _sm_ignore_map[] = {
{GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
{GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
{GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
{GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE}
};
static int lookup_enum(const char **values, const char *str)
{
int i;
for (i = 0; values[i]; ++i)
if (strcasecmp(str, values[i]) == 0)
return i;
return -1;
}
static uint32_t strhash_no_trailing_slash(const void *key, int hash_id)
{
static uint32_t hash_seeds[GIT_HASHTABLE_HASHES] = {
......@@ -212,8 +201,9 @@ static int submodule_from_config(
goto fail;
}
else if (strcmp(property, "update") == 0) {
int val = lookup_enum(sm_update_values, value);
if (val < 0) {
int val;
if (git_config_lookup_map_value(
_sm_update_map, ARRAY_SIZE(_sm_update_map), value, &val) < 0) {
giterr_set(GITERR_INVALID,
"Invalid value for submodule update property: '%s'", value);
goto fail;
......@@ -225,8 +215,9 @@ static int submodule_from_config(
goto fail;
}
else if (strcmp(property, "ignore") == 0) {
int val = lookup_enum(sm_ignore_values, value);
if (val < 0) {
int val;
if (git_config_lookup_map_value(
_sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value, &val) < 0) {
giterr_set(GITERR_INVALID,
"Invalid value for submodule ignore property: '%s'", value);
goto fail;
......
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