mirror of
https://git.proxmox.com/git/libgit2
synced 2026-01-07 02:13:13 +00:00
Merge pull request #1608 from arrbee/various-cleanups-and-tweaks
Various cleanups and tweaks
This commit is contained in:
commit
85281328be
@ -103,10 +103,10 @@ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
|
||||
/**
|
||||
* Combinations of these values describe the capabilities of libgit2.
|
||||
*/
|
||||
enum {
|
||||
typedef enum {
|
||||
GIT_CAP_THREADS = ( 1 << 0 ),
|
||||
GIT_CAP_HTTPS = ( 1 << 1 )
|
||||
};
|
||||
} git_cap_t;
|
||||
|
||||
/**
|
||||
* Query compile time options for libgit2.
|
||||
@ -114,17 +114,18 @@ enum {
|
||||
* @return A combination of GIT_CAP_* values.
|
||||
*
|
||||
* - GIT_CAP_THREADS
|
||||
* Libgit2 was compiled with thread support. Note that thread support is still to be seen as a
|
||||
* 'work in progress'.
|
||||
* Libgit2 was compiled with thread support. Note that thread support is
|
||||
* still to be seen as a 'work in progress' - basic object lookups are
|
||||
* believed to be threadsafe, but other operations may not be.
|
||||
*
|
||||
* - GIT_CAP_HTTPS
|
||||
* Libgit2 supports the https:// protocol. This requires the open ssl library to be
|
||||
* found when compiling libgit2.
|
||||
* Libgit2 supports the https:// protocol. This requires the openssl
|
||||
* library to be found when compiling libgit2.
|
||||
*/
|
||||
GIT_EXTERN(int) git_libgit2_capabilities(void);
|
||||
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
GIT_OPT_GET_MWINDOW_SIZE,
|
||||
GIT_OPT_SET_MWINDOW_SIZE,
|
||||
GIT_OPT_GET_MWINDOW_MAPPED_LIMIT,
|
||||
@ -135,7 +136,7 @@ enum {
|
||||
GIT_OPT_SET_CACHE_MAX_SIZE,
|
||||
GIT_OPT_ENABLE_CACHING,
|
||||
GIT_OPT_GET_CACHED_MEMORY
|
||||
};
|
||||
} git_libgit2_opt_t;
|
||||
|
||||
/**
|
||||
* Set or query a library global option
|
||||
@ -179,6 +180,35 @@ enum {
|
||||
* > - `level` must be GIT_CONFIG_LEVEL_SYSTEM, GIT_CONFIG_LEVEL_GLOBAL,
|
||||
* > or GIT_CONFIG_LEVEL_XDG.
|
||||
*
|
||||
* * opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, git_otype type, size_t size)
|
||||
*
|
||||
* > Set the maximum data size for the given type of object to be
|
||||
* > considered eligible for caching in memory. Setting to value to
|
||||
* > zero means that that type of object will not be cached.
|
||||
* > Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache blobs) and 4k
|
||||
* > for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG.
|
||||
*
|
||||
* * opts(GIT_OPT_SET_CACHE_MAX_SIZE, ssize_t max_storage_bytes)
|
||||
*
|
||||
* > Set the maximum total data size that will be cached in memory
|
||||
* > across all repositories before libgit2 starts evicting objects
|
||||
* > from the cache. This is a soft limit, in that the library might
|
||||
* > briefly exceed it, but will start aggressively evicting objects
|
||||
* > from cache when that happens. The default cache size is 256Mb.
|
||||
*
|
||||
* * opts(GIT_OPT_ENABLE_CACHING, int enabled)
|
||||
*
|
||||
* > Enable or disable caching completely.
|
||||
* >
|
||||
* > Because caches are repository-specific, disabling the cache
|
||||
* > cannot immediately clear all cached objects, but each cache will
|
||||
* > be cleared on the next attempt to update anything in it.
|
||||
*
|
||||
* * opts(GIT_OPT_GET_CACHED_MEMORY, ssize_t *current, ssize_t *allowed)
|
||||
*
|
||||
* > Get the current bytes in cache and the maximum that would be
|
||||
* > allowed in the cache.
|
||||
*
|
||||
* @param option Option key
|
||||
* @param ... value to set the option
|
||||
* @return 0 on success, <0 on failure
|
||||
|
||||
@ -27,18 +27,33 @@ GIT_BEGIN_DECL
|
||||
* git_config_open_default() and git_repository_config() honor those
|
||||
* priority levels as well.
|
||||
*/
|
||||
enum {
|
||||
GIT_CONFIG_LEVEL_SYSTEM = 1, /**< System-wide configuration file. */
|
||||
GIT_CONFIG_LEVEL_XDG = 2, /**< XDG compatible configuration file (.config/git/config). */
|
||||
GIT_CONFIG_LEVEL_GLOBAL = 3, /**< User-specific configuration file, also called Global configuration file. */
|
||||
GIT_CONFIG_LEVEL_LOCAL = 4, /**< Repository specific configuration file. */
|
||||
GIT_CONFIG_HIGHEST_LEVEL = -1, /**< Represents the highest level of a config file. */
|
||||
};
|
||||
typedef enum {
|
||||
/** System-wide configuration file; /etc/gitconfig on Linux systems */
|
||||
GIT_CONFIG_LEVEL_SYSTEM = 1,
|
||||
|
||||
/** XDG compatible configuration file; typically ~/.config/git/config */
|
||||
GIT_CONFIG_LEVEL_XDG = 2,
|
||||
|
||||
/** User-specific configuration file (also called Global configuration
|
||||
* file); typically ~/.gitconfig
|
||||
*/
|
||||
GIT_CONFIG_LEVEL_GLOBAL = 3,
|
||||
|
||||
/** Repository specific configuration file; $WORK_DIR/.git/config on
|
||||
* non-bare repos
|
||||
*/
|
||||
GIT_CONFIG_LEVEL_LOCAL = 4,
|
||||
|
||||
/** Represents the highest level available config file (i.e. the most
|
||||
* specific config file available that actually is loaded)
|
||||
*/
|
||||
GIT_CONFIG_HIGHEST_LEVEL = -1,
|
||||
} git_config_level_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *value;
|
||||
unsigned int level;
|
||||
git_config_level_t level;
|
||||
} git_config_entry;
|
||||
|
||||
typedef int (*git_config_foreach_cb)(const git_config_entry *, void *);
|
||||
@ -155,7 +170,7 @@ GIT_EXTERN(int) git_config_new(git_config **out);
|
||||
GIT_EXTERN(int) git_config_add_file_ondisk(
|
||||
git_config *cfg,
|
||||
const char *path,
|
||||
unsigned int level,
|
||||
git_config_level_t level,
|
||||
int force);
|
||||
|
||||
/**
|
||||
@ -192,7 +207,7 @@ GIT_EXTERN(int) git_config_open_ondisk(git_config **out, const char *path);
|
||||
GIT_EXTERN(int) git_config_open_level(
|
||||
git_config **out,
|
||||
const git_config *parent,
|
||||
unsigned int level);
|
||||
git_config_level_t level);
|
||||
|
||||
/**
|
||||
* Open the global/XDG configuration file according to git's rules
|
||||
@ -241,7 +256,7 @@ GIT_EXTERN(void) git_config_free(git_config *cfg);
|
||||
* @return 0 or an error code
|
||||
*/
|
||||
GIT_EXTERN(int) git_config_get_entry(
|
||||
const git_config_entry **out,
|
||||
const git_config_entry **out,
|
||||
const git_config *cfg,
|
||||
const char *name);
|
||||
|
||||
|
||||
@ -89,9 +89,10 @@ typedef enum {
|
||||
/** Include unmodified files in the diff list */
|
||||
GIT_DIFF_INCLUDE_UNMODIFIED = (1 << 9),
|
||||
|
||||
/** Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked directory
|
||||
* will be marked with only a single entry in the diff list; this flag
|
||||
* adds all files under the directory as UNTRACKED entries, too.
|
||||
/** Even with GIT_DIFF_INCLUDE_UNTRACKED, an entire untracked
|
||||
* directory will be marked with only a single entry in the diff list
|
||||
* (a la what core Git does in `git status`); this flag adds *all*
|
||||
* files under untracked directories as UNTRACKED entries, too.
|
||||
*/
|
||||
GIT_DIFF_RECURSE_UNTRACKED_DIRS = (1 << 10),
|
||||
|
||||
@ -103,7 +104,11 @@ typedef enum {
|
||||
/** Use case insensitive filename comparisons */
|
||||
GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12),
|
||||
|
||||
/** When generating patch text, include the content of untracked files */
|
||||
/** When generating patch text, include the content of untracked
|
||||
* files. This automatically turns on GIT_DIFF_INCLUDE_UNTRACKED but
|
||||
* it does not turn on GIT_DIFF_RECURSE_UNTRACKED_DIRS. Add that
|
||||
* flag if you want the content of every single UNTRACKED file.
|
||||
*/
|
||||
GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13),
|
||||
|
||||
/** Disable updating of the `binary` flag in delta records. This is
|
||||
@ -139,7 +144,7 @@ typedef enum {
|
||||
* consider UNTRACKED only if it has an actual untracked file in it.
|
||||
* This scan is extra work for a case you often don't care about. This
|
||||
* flag makes libgit2 immediately label an untracked directory as
|
||||
* UNTRACKED without looking insde it (which differs from core Git).
|
||||
* UNTRACKED without looking inside it (which differs from core Git).
|
||||
* Of course, ignore rules are still checked for the directory itself.
|
||||
*/
|
||||
GIT_DIFF_FAST_UNTRACKED_DIRS = (1 << 19),
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
GIT_BEGIN_DECL
|
||||
|
||||
/** Generic return codes */
|
||||
enum {
|
||||
typedef enum {
|
||||
GIT_OK = 0,
|
||||
GIT_ERROR = -1,
|
||||
GIT_ENOTFOUND = -3,
|
||||
@ -35,7 +35,7 @@ enum {
|
||||
|
||||
GIT_PASSTHROUGH = -30,
|
||||
GIT_ITEROVER = -31,
|
||||
};
|
||||
} git_error_code;
|
||||
|
||||
typedef struct {
|
||||
char *message;
|
||||
|
||||
@ -59,11 +59,11 @@ GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects
|
||||
GIT_EXTERN(int) git_odb_backend_one_pack(git_odb_backend **out, const char *index_file);
|
||||
|
||||
/** Streaming mode */
|
||||
enum {
|
||||
typedef enum {
|
||||
GIT_STREAM_RDONLY = (1 << 1),
|
||||
GIT_STREAM_WRONLY = (1 << 2),
|
||||
GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY),
|
||||
};
|
||||
} git_odb_stream_t;
|
||||
|
||||
/** A stream to read/write from a backend */
|
||||
struct git_odb_stream {
|
||||
|
||||
@ -29,7 +29,7 @@ struct git_config_backend {
|
||||
struct git_config *cfg;
|
||||
|
||||
/* Open means open the file/database and parse if necessary */
|
||||
int (*open)(struct git_config_backend *, unsigned int level);
|
||||
int (*open)(struct git_config_backend *, git_config_level_t level);
|
||||
int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry);
|
||||
int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload);
|
||||
int (*set)(struct git_config_backend *, const char *key, const char *value);
|
||||
@ -63,7 +63,7 @@ struct git_config_backend {
|
||||
GIT_EXTERN(int) git_config_add_backend(
|
||||
git_config *cfg,
|
||||
git_config_backend *file,
|
||||
unsigned int level,
|
||||
git_config_level_t level,
|
||||
int force);
|
||||
|
||||
/** @} */
|
||||
|
||||
29
src/attr.c
29
src/attr.c
@ -596,26 +596,33 @@ static int collect_attr_files(
|
||||
}
|
||||
|
||||
static int attr_cache__lookup_path(
|
||||
const char **out, git_config *cfg, const char *key, const char *fallback)
|
||||
char **out, git_config *cfg, const char *key, const char *fallback)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
const char *cfgval = NULL;
|
||||
|
||||
if (!(error = git_config_get_string(out, cfg, key)))
|
||||
return 0;
|
||||
*out = NULL;
|
||||
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
if (!(error = git_config_get_string(&cfgval, cfg, key))) {
|
||||
|
||||
/* expand leading ~/ as needed */
|
||||
if (cfgval && cfgval[0] == '~' && cfgval[1] == '/' &&
|
||||
!git_futils_find_global_file(&buf, &cfgval[2]))
|
||||
*out = git_buf_detach(&buf);
|
||||
else if (cfgval)
|
||||
*out = git__strdup(cfgval);
|
||||
|
||||
} else if (error == GIT_ENOTFOUND) {
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
|
||||
if (!git_futils_find_xdg_file(&buf, fallback))
|
||||
*out = git_buf_detach(&buf);
|
||||
else
|
||||
*out = NULL;
|
||||
|
||||
git_buf_free(&buf);
|
||||
}
|
||||
|
||||
git_buf_free(&buf);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -696,6 +703,12 @@ void git_attr_cache_flush(
|
||||
|
||||
git_pool_clear(&cache->pool);
|
||||
|
||||
git__free(cache->cfg_attr_file);
|
||||
cache->cfg_attr_file = NULL;
|
||||
|
||||
git__free(cache->cfg_excl_file);
|
||||
cache->cfg_excl_file = NULL;
|
||||
|
||||
cache->initialized = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -13,10 +13,10 @@
|
||||
typedef struct {
|
||||
int initialized;
|
||||
git_pool pool;
|
||||
git_strmap *files; /* hash path to git_attr_file of rules */
|
||||
git_strmap *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_strmap *files; /* hash path to git_attr_file of rules */
|
||||
git_strmap *macros; /* hash name to vector<git_attr_assignment> */
|
||||
char *cfg_attr_file; /* cached value of core.attributesfile */
|
||||
char *cfg_excl_file; /* cached value of core.excludesfile */
|
||||
} git_attr_cache;
|
||||
|
||||
extern int git_attr_cache__init(git_repository *repo);
|
||||
|
||||
@ -174,6 +174,11 @@ static void *cache_store(git_cache *cache, git_cached_obj *entry)
|
||||
|
||||
git_cached_obj_incref(entry);
|
||||
|
||||
if (!git_cache__enabled && cache->used_memory > 0) {
|
||||
git_cache_clear(cache);
|
||||
return entry;
|
||||
}
|
||||
|
||||
if (!cache_should_store(entry->type, entry->size))
|
||||
return entry;
|
||||
|
||||
|
||||
24
src/config.c
24
src/config.c
@ -23,7 +23,7 @@ typedef struct {
|
||||
git_refcount rc;
|
||||
|
||||
git_config_backend *file;
|
||||
unsigned int level;
|
||||
git_config_level_t level;
|
||||
} file_internal;
|
||||
|
||||
static void file_internal_free(file_internal *internal)
|
||||
@ -87,7 +87,7 @@ int git_config_new(git_config **out)
|
||||
int git_config_add_file_ondisk(
|
||||
git_config *cfg,
|
||||
const char *path,
|
||||
unsigned int level,
|
||||
git_config_level_t level,
|
||||
int force)
|
||||
{
|
||||
git_config_backend *file = NULL;
|
||||
@ -138,11 +138,11 @@ int git_config_open_ondisk(git_config **out, const char *path)
|
||||
static int find_internal_file_by_level(
|
||||
file_internal **internal_out,
|
||||
const git_config *cfg,
|
||||
int level)
|
||||
git_config_level_t level)
|
||||
{
|
||||
int pos = -1;
|
||||
file_internal *internal;
|
||||
unsigned int i;
|
||||
size_t i;
|
||||
|
||||
/* when passing GIT_CONFIG_HIGHEST_LEVEL, the idea is to get the config file
|
||||
* which has the highest level. As config files are stored in a vector
|
||||
@ -153,14 +153,14 @@ static int find_internal_file_by_level(
|
||||
pos = 0;
|
||||
} else {
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
if (internal->level == (unsigned int)level)
|
||||
if (internal->level == level)
|
||||
pos = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == -1) {
|
||||
giterr_set(GITERR_CONFIG,
|
||||
"No config file exists for the given level '%i'", level);
|
||||
"No config file exists for the given level '%i'", (int)level);
|
||||
return GIT_ENOTFOUND;
|
||||
}
|
||||
|
||||
@ -175,17 +175,17 @@ static int duplicate_level(void **old_raw, void *new_raw)
|
||||
|
||||
GIT_UNUSED(new_raw);
|
||||
|
||||
giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (*old)->level);
|
||||
giterr_set(GITERR_CONFIG, "A file with the same level (%i) has already been added to the config", (int)(*old)->level);
|
||||
return GIT_EEXISTS;
|
||||
}
|
||||
|
||||
static void try_remove_existing_file_internal(
|
||||
git_config *cfg,
|
||||
unsigned int level)
|
||||
git_config_level_t level)
|
||||
{
|
||||
int pos = -1;
|
||||
file_internal *internal;
|
||||
unsigned int i;
|
||||
size_t i;
|
||||
|
||||
git_vector_foreach(&cfg->files, i, internal) {
|
||||
if (internal->level == level)
|
||||
@ -206,7 +206,7 @@ static void try_remove_existing_file_internal(
|
||||
static int git_config__add_internal(
|
||||
git_config *cfg,
|
||||
file_internal *internal,
|
||||
unsigned int level,
|
||||
git_config_level_t level,
|
||||
int force)
|
||||
{
|
||||
int result;
|
||||
@ -238,7 +238,7 @@ int git_config_open_global(git_config **cfg_out, git_config *cfg)
|
||||
int git_config_open_level(
|
||||
git_config **cfg_out,
|
||||
const git_config *cfg_parent,
|
||||
unsigned int level)
|
||||
git_config_level_t level)
|
||||
{
|
||||
git_config *cfg;
|
||||
file_internal *internal;
|
||||
@ -263,7 +263,7 @@ int git_config_open_level(
|
||||
int git_config_add_backend(
|
||||
git_config *cfg,
|
||||
git_config_backend *file,
|
||||
unsigned int level,
|
||||
git_config_level_t level,
|
||||
int force)
|
||||
{
|
||||
file_internal *internal;
|
||||
|
||||
@ -81,10 +81,10 @@ typedef struct {
|
||||
time_t file_mtime;
|
||||
size_t file_size;
|
||||
|
||||
unsigned int level;
|
||||
git_config_level_t level;
|
||||
} diskfile_backend;
|
||||
|
||||
static int config_parse(diskfile_backend *cfg_file, unsigned int level);
|
||||
static int config_parse(diskfile_backend *cfg_file, git_config_level_t level);
|
||||
static int parse_variable(diskfile_backend *cfg, char **var_name, char **var_value);
|
||||
static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value);
|
||||
static char *escape_value(const char *ptr);
|
||||
@ -181,7 +181,7 @@ static void free_vars(git_strmap *values)
|
||||
git_strmap_free(values);
|
||||
}
|
||||
|
||||
static int config_open(git_config_backend *cfg, unsigned int level)
|
||||
static int config_open(git_config_backend *cfg, git_config_level_t level)
|
||||
{
|
||||
int res;
|
||||
diskfile_backend *b = (diskfile_backend *)cfg;
|
||||
@ -965,7 +965,7 @@ static int strip_comments(char *line, int in_quotes)
|
||||
return quote_count;
|
||||
}
|
||||
|
||||
static int config_parse(diskfile_backend *cfg_file, unsigned int level)
|
||||
static int config_parse(diskfile_backend *cfg_file, git_config_level_t level)
|
||||
{
|
||||
int c;
|
||||
char *current_section = NULL;
|
||||
|
||||
@ -383,6 +383,10 @@ static int diff_list_apply_options(
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_TYPECHANGE_TREES))
|
||||
diff->opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE;
|
||||
|
||||
/* flag INCLUDE_UNTRACKED_CONTENT implies INCLUDE_UNTRACKED */
|
||||
if (DIFF_FLAG_IS_SET(diff, GIT_DIFF_INCLUDE_UNTRACKED_CONTENT))
|
||||
diff->opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
|
||||
|
||||
/* load config values that affect diff behavior */
|
||||
if (git_repository_config__weakptr(&cfg, repo) < 0)
|
||||
return -1;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "posix.h"
|
||||
#include "path.h"
|
||||
#include "fileops.h"
|
||||
|
||||
static git_repository *g_repo = NULL;
|
||||
|
||||
@ -20,7 +21,7 @@ void assert_is_ignored(bool expected, const char *filepath)
|
||||
int is_ignored;
|
||||
|
||||
cl_git_pass(git_ignore_path_is_ignored(&is_ignored, g_repo, filepath));
|
||||
cl_assert_equal_i(expected, is_ignored == 1);
|
||||
cl_assert_equal_b(expected, is_ignored);
|
||||
}
|
||||
|
||||
void test_attr_ignore__honor_temporary_rules(void)
|
||||
@ -46,3 +47,35 @@ void test_attr_ignore__skip_gitignore_directory(void)
|
||||
assert_is_ignored(true, "NewFolder/NewFolder");
|
||||
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
|
||||
}
|
||||
|
||||
void test_attr_ignore__expand_tilde_to_homedir(void)
|
||||
{
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
git_config *cfg;
|
||||
|
||||
assert_is_ignored(false, "example.global_with_tilde");
|
||||
|
||||
/* construct fake home with fake global excludes */
|
||||
|
||||
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));
|
||||
|
||||
cl_git_mkfile("home/globalexcludes", "# found me\n*.global_with_tilde\n");
|
||||
|
||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||
cl_git_pass(git_config_set_string(cfg, "core.excludesfile", "~/globalexcludes"));
|
||||
git_config_free(cfg);
|
||||
|
||||
git_attr_cache_flush(g_repo); /* must reset to pick up change */
|
||||
|
||||
assert_is_ignored(true, "example.global_with_tilde");
|
||||
|
||||
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
|
||||
|
||||
cl_git_pass(git_libgit2_opts(
|
||||
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, NULL));
|
||||
|
||||
git_buf_free(&path);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user