mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-30 08:12:42 +00:00
Merge pull request #2215 from libgit2/rb/submodule-cache-fixes
Improve submodule cache management
This commit is contained in:
commit
923c84008d
@ -13,6 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This example demonstrates the use of the libgit2 status APIs,
|
* This example demonstrates the use of the libgit2 status APIs,
|
||||||
@ -44,19 +45,22 @@ enum {
|
|||||||
#define MAX_PATHSPEC 8
|
#define MAX_PATHSPEC 8
|
||||||
|
|
||||||
struct opts {
|
struct opts {
|
||||||
git_status_options statusopt;
|
git_status_options statusopt;
|
||||||
char *repodir;
|
char *repodir;
|
||||||
char *pathspec[MAX_PATHSPEC];
|
char *pathspec[MAX_PATHSPEC];
|
||||||
int npaths;
|
int npaths;
|
||||||
int format;
|
int format;
|
||||||
int zterm;
|
int zterm;
|
||||||
int showbranch;
|
int showbranch;
|
||||||
|
int showsubmod;
|
||||||
|
int repeat;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
static void parse_opts(struct opts *o, int argc, char *argv[]);
|
||||||
static void show_branch(git_repository *repo, int format);
|
static void show_branch(git_repository *repo, int format);
|
||||||
static void print_long(git_status_list *status);
|
static void print_long(git_status_list *status);
|
||||||
static void print_short(git_repository *repo, git_status_list *status);
|
static void print_short(git_repository *repo, git_status_list *status);
|
||||||
|
static int print_submod(git_submodule *sm, const char *name, void *payload);
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -84,6 +88,10 @@ int main(int argc, char *argv[])
|
|||||||
fatal("Cannot report status on bare repository",
|
fatal("Cannot report status on bare repository",
|
||||||
git_repository_path(repo));
|
git_repository_path(repo));
|
||||||
|
|
||||||
|
show_status:
|
||||||
|
if (o.repeat)
|
||||||
|
printf("\033[H\033[2J");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run status on the repository
|
* Run status on the repository
|
||||||
*
|
*
|
||||||
@ -98,17 +106,29 @@ int main(int argc, char *argv[])
|
|||||||
* about what results are presented.
|
* about what results are presented.
|
||||||
*/
|
*/
|
||||||
check_lg2(git_status_list_new(&status, repo, &o.statusopt),
|
check_lg2(git_status_list_new(&status, repo, &o.statusopt),
|
||||||
"Could not get status", NULL);
|
"Could not get status", NULL);
|
||||||
|
|
||||||
if (o.showbranch)
|
if (o.showbranch)
|
||||||
show_branch(repo, o.format);
|
show_branch(repo, o.format);
|
||||||
|
|
||||||
|
if (o.showsubmod) {
|
||||||
|
int submod_count = 0;
|
||||||
|
check_lg2(git_submodule_foreach(repo, print_submod, &submod_count),
|
||||||
|
"Cannot iterate submodules", o.repodir);
|
||||||
|
}
|
||||||
|
|
||||||
if (o.format == FORMAT_LONG)
|
if (o.format == FORMAT_LONG)
|
||||||
print_long(status);
|
print_long(status);
|
||||||
else
|
else
|
||||||
print_short(repo, status);
|
print_short(repo, status);
|
||||||
|
|
||||||
git_status_list_free(status);
|
git_status_list_free(status);
|
||||||
|
|
||||||
|
if (o.repeat) {
|
||||||
|
sleep(o.repeat);
|
||||||
|
goto show_status;
|
||||||
|
}
|
||||||
|
|
||||||
git_repository_free(repo);
|
git_repository_free(repo);
|
||||||
git_threads_shutdown();
|
git_threads_shutdown();
|
||||||
|
|
||||||
@ -381,7 +401,7 @@ static void print_short(git_repository *repo, git_status_list *status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Now that we have all the information, it's time to format the output.
|
* Now that we have all the information, format the output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (s->head_to_index) {
|
if (s->head_to_index) {
|
||||||
@ -417,6 +437,21 @@ static void print_short(git_repository *repo, git_status_list *status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_submod(git_submodule *sm, const char *name, void *payload)
|
||||||
|
{
|
||||||
|
int *count = payload;
|
||||||
|
(void)name;
|
||||||
|
|
||||||
|
if (*count == 0)
|
||||||
|
printf("# Submodules\n");
|
||||||
|
(*count)++;
|
||||||
|
|
||||||
|
printf("# - submodule '%s' at %s\n",
|
||||||
|
git_submodule_name(sm), git_submodule_path(sm));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse options that git's status command supports.
|
* Parse options that git's status command supports.
|
||||||
*/
|
*/
|
||||||
@ -462,6 +497,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
|
|||||||
o->statusopt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
|
o->statusopt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
|
||||||
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
|
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
|
||||||
o->repodir = a + strlen("--git-dir=");
|
o->repodir = a + strlen("--git-dir=");
|
||||||
|
else if (!strcmp(a, "--repeat"))
|
||||||
|
o->repeat = 10;
|
||||||
|
else if (match_int_arg(&o->repeat, &args, "--repeat", 0))
|
||||||
|
/* okay */;
|
||||||
|
else if (!strcmp(a, "--list-submodules"))
|
||||||
|
o->showsubmod = 1;
|
||||||
else
|
else
|
||||||
check_lg2(-1, "Unsupported option", a);
|
check_lg2(-1, "Unsupported option", a);
|
||||||
}
|
}
|
||||||
|
53
src/buffer.c
53
src/buffer.c
@ -467,6 +467,59 @@ int git_buf_join(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_buf_join3(
|
||||||
|
git_buf *buf,
|
||||||
|
char separator,
|
||||||
|
const char *str_a,
|
||||||
|
const char *str_b,
|
||||||
|
const char *str_c)
|
||||||
|
{
|
||||||
|
size_t len_a = strlen(str_a), len_b = strlen(str_b), len_c = strlen(str_c);
|
||||||
|
int sep_a = 0, sep_b = 0;
|
||||||
|
char *tgt;
|
||||||
|
|
||||||
|
/* for this function, disallow pointers into the existing buffer */
|
||||||
|
assert(str_a < buf->ptr || str_a >= buf->ptr + buf->size);
|
||||||
|
assert(str_b < buf->ptr || str_b >= buf->ptr + buf->size);
|
||||||
|
assert(str_c < buf->ptr || str_c >= buf->ptr + buf->size);
|
||||||
|
|
||||||
|
if (separator) {
|
||||||
|
if (len_a > 0) {
|
||||||
|
while (*str_b == separator) { str_b++; len_b--; }
|
||||||
|
sep_a = (str_a[len_a - 1] != separator);
|
||||||
|
}
|
||||||
|
if (len_a > 0 || len_b > 0)
|
||||||
|
while (*str_c == separator) { str_c++; len_c--; }
|
||||||
|
if (len_b > 0)
|
||||||
|
sep_b = (str_b[len_b - 1] != separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tgt = buf->ptr;
|
||||||
|
|
||||||
|
if (len_a) {
|
||||||
|
memcpy(tgt, str_a, len_a);
|
||||||
|
tgt += len_a;
|
||||||
|
}
|
||||||
|
if (sep_a)
|
||||||
|
*tgt++ = separator;
|
||||||
|
if (len_b) {
|
||||||
|
memcpy(tgt, str_b, len_b);
|
||||||
|
tgt += len_b;
|
||||||
|
}
|
||||||
|
if (sep_b)
|
||||||
|
*tgt++ = separator;
|
||||||
|
if (len_c)
|
||||||
|
memcpy(tgt, str_c, len_c);
|
||||||
|
|
||||||
|
buf->size = len_a + sep_a + len_b + sep_b + len_c;
|
||||||
|
buf->ptr[buf->size] = '\0';
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void git_buf_rtrim(git_buf *buf)
|
void git_buf_rtrim(git_buf *buf)
|
||||||
{
|
{
|
||||||
while (buf->size > 0) {
|
while (buf->size > 0) {
|
||||||
|
@ -98,8 +98,12 @@ void git_buf_truncate(git_buf *buf, size_t len);
|
|||||||
void git_buf_shorten(git_buf *buf, size_t amount);
|
void git_buf_shorten(git_buf *buf, size_t amount);
|
||||||
void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||||
|
|
||||||
|
/** General join with separator */
|
||||||
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
|
||||||
|
/** Fast join of two strings - first may legally point into `buf` data */
|
||||||
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
|
||||||
|
/** Fast join of three strings - cannot reference `buf` data */
|
||||||
|
int git_buf_join3(git_buf *buf, char separator, const char *str_a, const char *str_b, const char *str_c);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join two strings as paths, inserting a slash between as needed.
|
* Join two strings as paths, inserting a slash between as needed.
|
||||||
|
30
src/config.c
30
src/config.c
@ -615,6 +615,36 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_config__update_entry(
|
||||||
|
git_config *config,
|
||||||
|
const char *key,
|
||||||
|
const char *value,
|
||||||
|
bool overwrite_existing,
|
||||||
|
bool only_if_existing)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
const git_config_entry *ce = NULL;
|
||||||
|
|
||||||
|
if ((error = git_config__lookup_entry(&ce, config, key, false)) < 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (!ce && only_if_existing) /* entry doesn't exist */
|
||||||
|
return 0;
|
||||||
|
if (ce && !overwrite_existing) /* entry would be overwritten */
|
||||||
|
return 0;
|
||||||
|
if (value && ce && ce->value && !strcmp(ce->value, value)) /* no change */
|
||||||
|
return 0;
|
||||||
|
if (!value && (!ce || !ce->value)) /* asked to delete absent entry */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!value)
|
||||||
|
error = git_config_delete_entry(config, key);
|
||||||
|
else
|
||||||
|
error = git_config_set_string(config, key, value);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
/***********
|
/***********
|
||||||
* Getters
|
* Getters
|
||||||
***********/
|
***********/
|
||||||
|
@ -53,6 +53,14 @@ extern int git_config__lookup_entry(
|
|||||||
const char *key,
|
const char *key,
|
||||||
bool no_errors);
|
bool no_errors);
|
||||||
|
|
||||||
|
/* internal only: update and/or delete entry string with constraints */
|
||||||
|
extern int git_config__update_entry(
|
||||||
|
git_config *cfg,
|
||||||
|
const char *key,
|
||||||
|
const char *value,
|
||||||
|
bool overwrite_existing,
|
||||||
|
bool only_if_existing);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup functions that cannot fail. These functions look up a config
|
* Lookup functions that cannot fail. These functions look up a config
|
||||||
* value and return a fallback value if the value is missing or if any
|
* value and return a fallback value if the value is missing or if any
|
||||||
|
@ -16,7 +16,8 @@ GIT_INLINE(int) git_config_file_open(git_config_backend *cfg, unsigned int level
|
|||||||
|
|
||||||
GIT_INLINE(void) git_config_file_free(git_config_backend *cfg)
|
GIT_INLINE(void) git_config_file_free(git_config_backend *cfg)
|
||||||
{
|
{
|
||||||
cfg->free(cfg);
|
if (cfg)
|
||||||
|
cfg->free(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
GIT_INLINE(int) git_config_file_get_string(
|
GIT_INLINE(int) git_config_file_get_string(
|
||||||
|
12
src/index.c
12
src/index.c
@ -517,6 +517,18 @@ int git_index_read(git_index *index, int force)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_index__changed_relative_to(
|
||||||
|
git_index *index, const git_futils_filestamp *fs)
|
||||||
|
{
|
||||||
|
/* attempt to update index (ignoring errors) */
|
||||||
|
if (git_index_read(index, false) < 0)
|
||||||
|
giterr_clear();
|
||||||
|
|
||||||
|
return (index->stamp.mtime != fs->mtime ||
|
||||||
|
index->stamp.size != fs->size ||
|
||||||
|
index->stamp.ino != fs->ino);
|
||||||
|
}
|
||||||
|
|
||||||
int git_index_write(git_index *index)
|
int git_index_write(git_index *index)
|
||||||
{
|
{
|
||||||
git_filebuf file = GIT_FILEBUF_INIT;
|
git_filebuf file = GIT_FILEBUF_INIT;
|
||||||
|
@ -62,4 +62,11 @@ extern void git_index__set_ignore_case(git_index *index, bool ignore_case);
|
|||||||
|
|
||||||
extern unsigned int git_index__create_mode(unsigned int mode);
|
extern unsigned int git_index__create_mode(unsigned int mode);
|
||||||
|
|
||||||
|
GIT_INLINE(const git_futils_filestamp *) git_index__filestamp(git_index *index)
|
||||||
|
{
|
||||||
|
return &index->stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int git_index__changed_relative_to(git_index *index, const git_futils_filestamp *fs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -119,6 +119,14 @@ GIT_INLINE(void) git_path_mkposix(char *path)
|
|||||||
# define git_path_mkposix(p) /* blank */
|
# define git_path_mkposix(p) /* blank */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if string is a relative path (i.e. starts with "./" or "../")
|
||||||
|
*/
|
||||||
|
GIT_INLINE(int) git_path_is_relative(const char *p)
|
||||||
|
{
|
||||||
|
return (p[0] == '.' && (p[1] == '/' || (p[1] == '.' && p[2] == '/')));
|
||||||
|
}
|
||||||
|
|
||||||
extern int git__percent_decode(git_buf *decoded_out, const char *input);
|
extern int git__percent_decode(git_buf *decoded_out, const char *input);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1432,7 +1432,7 @@ static int create_new_reflog_file(const char *filepath)
|
|||||||
|
|
||||||
GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
|
GIT_INLINE(int) retrieve_reflog_path(git_buf *path, git_repository *repo, const char *name)
|
||||||
{
|
{
|
||||||
return git_buf_join_n(path, '/', 3, repo->path_repository, GIT_REFLOG_DIR, name);
|
return git_buf_join3(path, '/', repo->path_repository, GIT_REFLOG_DIR, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
|
static int refdb_reflog_fs__ensure_log(git_refdb_backend *_backend, const char *name)
|
||||||
|
88
src/remote.c
88
src/remote.c
@ -495,9 +495,10 @@ cleanup:
|
|||||||
int git_remote_save(const git_remote *remote)
|
int git_remote_save(const git_remote *remote)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
git_config *config;
|
git_config *cfg;
|
||||||
const char *tagopt = NULL;
|
const char *tagopt = NULL;
|
||||||
git_buf buf = GIT_BUF_INIT;
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
const git_config_entry *existing;
|
||||||
|
|
||||||
assert(remote);
|
assert(remote);
|
||||||
|
|
||||||
@ -509,43 +510,31 @@ int git_remote_save(const git_remote *remote)
|
|||||||
if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
|
if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (git_repository_config__weakptr(&config, remote->repo) < 0)
|
if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
|
||||||
return -1;
|
return error;
|
||||||
|
|
||||||
if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
|
if ((error = git_buf_printf(&buf, "remote.%s.url", remote->name)) < 0)
|
||||||
return -1;
|
return error;
|
||||||
|
|
||||||
if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
|
/* after this point, buffer is allocated so end with cleanup */
|
||||||
git_buf_free(&buf);
|
|
||||||
return -1;
|
if ((error = git_config_set_string(
|
||||||
}
|
cfg, git_buf_cstr(&buf), remote->url)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
git_buf_clear(&buf);
|
git_buf_clear(&buf);
|
||||||
if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
|
if ((error = git_buf_printf(&buf, "remote.%s.pushurl", remote->name)) < 0)
|
||||||
return -1;
|
goto cleanup;
|
||||||
|
|
||||||
if (remote->pushurl) {
|
if ((error = git_config__update_entry(
|
||||||
if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
|
cfg, git_buf_cstr(&buf), remote->pushurl, true, false)) < 0)
|
||||||
git_buf_free(&buf);
|
goto cleanup;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int error = git_config_delete_entry(config, git_buf_cstr(&buf));
|
|
||||||
if (error == GIT_ENOTFOUND) {
|
|
||||||
error = 0;
|
|
||||||
giterr_clear();
|
|
||||||
}
|
|
||||||
if (error < 0) {
|
|
||||||
git_buf_free(&buf);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
|
if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
|
||||||
goto on_error;
|
goto cleanup;
|
||||||
|
|
||||||
if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
|
if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
|
||||||
goto on_error;
|
goto cleanup;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* What action to take depends on the old and new values. This
|
* What action to take depends on the old and new values. This
|
||||||
@ -561,31 +550,26 @@ int git_remote_save(const git_remote *remote)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
git_buf_clear(&buf);
|
git_buf_clear(&buf);
|
||||||
if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
|
if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
|
||||||
goto on_error;
|
goto cleanup;
|
||||||
|
|
||||||
error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
|
if ((error = git_config__lookup_entry(
|
||||||
if (error < 0 && error != GIT_ENOTFOUND)
|
&existing, cfg, git_buf_cstr(&buf), false)) < 0)
|
||||||
goto on_error;
|
goto cleanup;
|
||||||
|
|
||||||
if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
|
if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
|
||||||
if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
|
tagopt = "--tags";
|
||||||
goto on_error;
|
else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
|
||||||
} else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
|
tagopt = "--no-tags";
|
||||||
if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
|
else if (existing != NULL)
|
||||||
goto on_error;
|
tagopt = NULL;
|
||||||
} else if (tagopt) {
|
|
||||||
if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
|
|
||||||
goto on_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
error = git_config__update_entry(
|
||||||
|
cfg, git_buf_cstr(&buf), tagopt, true, false);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
git_buf_free(&buf);
|
git_buf_free(&buf);
|
||||||
|
return error;
|
||||||
return 0;
|
|
||||||
|
|
||||||
on_error:
|
|
||||||
git_buf_free(&buf);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *git_remote_name(const git_remote *remote)
|
const char *git_remote_name(const git_remote *remote)
|
||||||
|
@ -93,6 +93,7 @@ void git_repository__cleanup(git_repository *repo)
|
|||||||
|
|
||||||
git_cache_clear(&repo->objects);
|
git_cache_clear(&repo->objects);
|
||||||
git_attr_cache_flush(repo);
|
git_attr_cache_flush(repo);
|
||||||
|
git_submodule_cache_free(repo);
|
||||||
|
|
||||||
set_config(repo, NULL);
|
set_config(repo, NULL);
|
||||||
set_index(repo, NULL);
|
set_index(repo, NULL);
|
||||||
@ -108,7 +109,6 @@ void git_repository_free(git_repository *repo)
|
|||||||
git_repository__cleanup(repo);
|
git_repository__cleanup(repo);
|
||||||
|
|
||||||
git_cache_free(&repo->objects);
|
git_cache_free(&repo->objects);
|
||||||
git_submodule_config_free(repo);
|
|
||||||
|
|
||||||
git_diff_driver_registry_free(repo->diff_drivers);
|
git_diff_driver_registry_free(repo->diff_drivers);
|
||||||
repo->diff_drivers = NULL;
|
repo->diff_drivers = NULL;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "attrcache.h"
|
#include "attrcache.h"
|
||||||
#include "strmap.h"
|
#include "submodule.h"
|
||||||
#include "diff_driver.h"
|
#include "diff_driver.h"
|
||||||
|
|
||||||
#define DOT_GIT ".git"
|
#define DOT_GIT ".git"
|
||||||
@ -105,10 +105,10 @@ struct git_repository {
|
|||||||
git_refdb *_refdb;
|
git_refdb *_refdb;
|
||||||
git_config *_config;
|
git_config *_config;
|
||||||
git_index *_index;
|
git_index *_index;
|
||||||
|
git_submodule_cache *_submodules;
|
||||||
|
|
||||||
git_cache objects;
|
git_cache objects;
|
||||||
git_attr_cache attrcache;
|
git_attr_cache attrcache;
|
||||||
git_strmap *submodules;
|
|
||||||
git_diff_driver_registry *diff_drivers;
|
git_diff_driver_registry *diff_drivers;
|
||||||
|
|
||||||
char *path_repository;
|
char *path_repository;
|
||||||
@ -149,11 +149,6 @@ int git_repository_index__weakptr(git_index **out, git_repository *repo);
|
|||||||
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar);
|
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar);
|
||||||
void git_repository__cvar_cache_clear(git_repository *repo);
|
void git_repository__cvar_cache_clear(git_repository *repo);
|
||||||
|
|
||||||
/*
|
|
||||||
* Submodule cache
|
|
||||||
*/
|
|
||||||
extern void git_submodule_config_free(git_repository *repo);
|
|
||||||
|
|
||||||
GIT_INLINE(int) git_repository__ensure_not_bare(
|
GIT_INLINE(int) git_repository__ensure_not_bare(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
const char *operation_name)
|
const char *operation_name)
|
||||||
|
958
src/submodule.c
958
src/submodule.c
File diff suppressed because it is too large
Load Diff
@ -99,6 +99,29 @@ struct git_submodule {
|
|||||||
git_oid wd_oid;
|
git_oid wd_oid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The git_submodule_cache stores known submodules along with timestamps,
|
||||||
|
* etc. about when they were loaded
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
git_repository *repo;
|
||||||
|
git_strmap *submodules;
|
||||||
|
git_mutex lock;
|
||||||
|
|
||||||
|
/* cache invalidation data */
|
||||||
|
git_oid head_id;
|
||||||
|
git_futils_filestamp index_stamp;
|
||||||
|
git_buf gitmodules_path;
|
||||||
|
git_futils_filestamp gitmodules_stamp;
|
||||||
|
git_futils_filestamp config_stamp;
|
||||||
|
} git_submodule_cache;
|
||||||
|
|
||||||
|
/* Force revalidation of submodule data cache (alloc as needed) */
|
||||||
|
extern int git_submodule_cache_refresh(git_repository *repo);
|
||||||
|
|
||||||
|
/* Release all submodules */
|
||||||
|
extern void git_submodule_cache_free(git_repository *repo);
|
||||||
|
|
||||||
/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
|
/* Additional flags on top of public GIT_SUBMODULE_STATUS values */
|
||||||
enum {
|
enum {
|
||||||
GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
|
GIT_SUBMODULE_STATUS__WD_SCANNED = (1u << 20),
|
||||||
@ -111,17 +134,16 @@ enum {
|
|||||||
GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
|
GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES = (1u << 27),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GIT_SUBMODULE_STATUS__ALL_WD_FLAGS \
|
|
||||||
(GIT_SUBMODULE_STATUS_IN_WD | \
|
|
||||||
GIT_SUBMODULE_STATUS__WD_OID_VALID | \
|
|
||||||
GIT_SUBMODULE_STATUS__WD_FLAGS)
|
|
||||||
|
|
||||||
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
|
#define GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(S) \
|
||||||
((S) & ~(0xFFFFFFFFu << 20))
|
((S) & ~(0xFFFFFFFFu << 20))
|
||||||
|
|
||||||
/* Internal submodule check does not attempt to refresh cached data */
|
/* Internal submodule check does not attempt to refresh cached data */
|
||||||
extern bool git_submodule__is_submodule(git_repository *repo, const char *name);
|
extern bool git_submodule__is_submodule(git_repository *repo, const char *name);
|
||||||
|
|
||||||
|
/* Internal lookup does not attempt to refresh cached data */
|
||||||
|
extern int git_submodule__lookup(
|
||||||
|
git_submodule **out, git_repository *repo, const char *path);
|
||||||
|
|
||||||
/* Internal status fn returns status and optionally the various OIDs */
|
/* Internal status fn returns status and optionally the various OIDs */
|
||||||
extern int git_submodule__status(
|
extern int git_submodule__status(
|
||||||
unsigned int *out_status,
|
unsigned int *out_status,
|
||||||
@ -143,5 +165,6 @@ extern int git_submodule_parse_update(
|
|||||||
|
|
||||||
extern const char *git_submodule_ignore_to_str(git_submodule_ignore_t);
|
extern const char *git_submodule_ignore_to_str(git_submodule_ignore_t);
|
||||||
extern const char *git_submodule_update_to_str(git_submodule_update_t);
|
extern const char *git_submodule_update_to_str(git_submodule_update_t);
|
||||||
|
extern const char *git_submodule_recurse_to_str(git_submodule_recurse_t);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,7 +54,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
|
|||||||
bytes = src->length * sizeof(void *);
|
bytes = src->length * sizeof(void *);
|
||||||
|
|
||||||
v->_alloc_size = src->length;
|
v->_alloc_size = src->length;
|
||||||
v->_cmp = cmp;
|
v->_cmp = cmp ? cmp : src->_cmp;
|
||||||
v->length = src->length;
|
v->length = src->length;
|
||||||
v->flags = src->flags;
|
v->flags = src->flags;
|
||||||
if (cmp != src->_cmp)
|
if (cmp != src->_cmp)
|
||||||
|
@ -599,6 +599,38 @@ void test_core_buffer__10(void)
|
|||||||
git_buf_free(&a);
|
git_buf_free(&a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_core_buffer__join3(void)
|
||||||
|
{
|
||||||
|
git_buf a = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "test", "string", "join"));
|
||||||
|
cl_assert_equal_s("test/string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "test/", "string", "join"));
|
||||||
|
cl_assert_equal_s("test/string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string", "join"));
|
||||||
|
cl_assert_equal_s("test/string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "join"));
|
||||||
|
cl_assert_equal_s("test/string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "test/", "/string/", "/join"));
|
||||||
|
cl_assert_equal_s("test/string/join", a.ptr);
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "", "string", "join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "", "string/", "/join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "string", "", "join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
cl_git_pass(git_buf_join3(&a, '/', "string/", "", "/join"));
|
||||||
|
cl_assert_equal_s("string/join", a.ptr);
|
||||||
|
|
||||||
|
git_buf_free(&a);
|
||||||
|
}
|
||||||
|
|
||||||
void test_core_buffer__11(void)
|
void test_core_buffer__11(void)
|
||||||
{
|
{
|
||||||
git_buf a = GIT_BUF_INIT;
|
git_buf a = GIT_BUF_INIT;
|
||||||
|
@ -131,8 +131,6 @@ void test_diff_submodules__dirty_submodule_2(void)
|
|||||||
|
|
||||||
g_repo = setup_fixture_submodules();
|
g_repo = setup_fixture_submodules();
|
||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
|
||||||
|
|
||||||
opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
|
opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
|
||||||
GIT_DIFF_SHOW_UNTRACKED_CONTENT |
|
GIT_DIFF_SHOW_UNTRACKED_CONTENT |
|
||||||
GIT_DIFF_RECURSE_UNTRACKED_DIRS |
|
GIT_DIFF_RECURSE_UNTRACKED_DIRS |
|
||||||
@ -165,8 +163,6 @@ void test_diff_submodules__dirty_submodule_2(void)
|
|||||||
|
|
||||||
git_diff_free(diff);
|
git_diff_free(diff);
|
||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
|
||||||
|
|
||||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||||
check_diff_patches(diff, expected_dirty);
|
check_diff_patches(diff, expected_dirty);
|
||||||
git_diff_free(diff);
|
git_diff_free(diff);
|
||||||
@ -299,7 +295,6 @@ void test_diff_submodules__invalid_cache(void)
|
|||||||
|
|
||||||
git_submodule_free(sm);
|
git_submodule_free(sm);
|
||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
|
||||||
cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
|
cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
|
||||||
|
|
||||||
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
|
||||||
|
117
tests/submodule/add.c
Normal file
117
tests/submodule/add.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include "clar_libgit2.h"
|
||||||
|
#include "posix.h"
|
||||||
|
#include "path.h"
|
||||||
|
#include "submodule_helpers.h"
|
||||||
|
|
||||||
|
static git_repository *g_repo = NULL;
|
||||||
|
|
||||||
|
void test_submodule_add__cleanup(void)
|
||||||
|
{
|
||||||
|
cl_git_sandbox_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert_submodule_url(const char* name, const char *url)
|
||||||
|
{
|
||||||
|
git_config *cfg;
|
||||||
|
const char *s;
|
||||||
|
git_buf key = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_printf(&key, "submodule.%s.url", name));
|
||||||
|
cl_git_pass(git_config_get_string(&s, cfg, git_buf_cstr(&key)));
|
||||||
|
cl_assert_equal_s(s, url);
|
||||||
|
|
||||||
|
git_config_free(cfg);
|
||||||
|
git_buf_free(&key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_submodule_add__url_absolute(void)
|
||||||
|
{
|
||||||
|
git_submodule *sm;
|
||||||
|
|
||||||
|
g_repo = setup_fixture_submod2();
|
||||||
|
|
||||||
|
/* re-add existing submodule */
|
||||||
|
cl_git_fail_with(
|
||||||
|
GIT_EEXISTS,
|
||||||
|
git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1));
|
||||||
|
|
||||||
|
/* add a submodule using a gitlink */
|
||||||
|
|
||||||
|
cl_git_pass(
|
||||||
|
git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_libgit2", 1)
|
||||||
|
);
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
cl_assert(git_path_isfile("submod2/" "sm_libgit2" "/.git"));
|
||||||
|
|
||||||
|
cl_assert(git_path_isdir("submod2/.git/modules"));
|
||||||
|
cl_assert(git_path_isdir("submod2/.git/modules/" "sm_libgit2"));
|
||||||
|
cl_assert(git_path_isfile("submod2/.git/modules/" "sm_libgit2" "/HEAD"));
|
||||||
|
assert_submodule_url("sm_libgit2", "https://github.com/libgit2/libgit2.git");
|
||||||
|
|
||||||
|
/* add a submodule not using a gitlink */
|
||||||
|
|
||||||
|
cl_git_pass(
|
||||||
|
git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_libgit2b", 0)
|
||||||
|
);
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
cl_assert(git_path_isdir("submod2/" "sm_libgit2b" "/.git"));
|
||||||
|
cl_assert(git_path_isfile("submod2/" "sm_libgit2b" "/.git/HEAD"));
|
||||||
|
cl_assert(!git_path_exists("submod2/.git/modules/" "sm_libgit2b"));
|
||||||
|
assert_submodule_url("sm_libgit2b", "https://github.com/libgit2/libgit2.git");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_submodule_add__url_relative(void)
|
||||||
|
{
|
||||||
|
git_submodule *sm;
|
||||||
|
git_remote *remote;
|
||||||
|
|
||||||
|
/* default remote url is https://github.com/libgit2/false.git */
|
||||||
|
g_repo = cl_git_sandbox_init("testrepo2");
|
||||||
|
|
||||||
|
/* make sure we don't default to origin - rename origin -> test_remote */
|
||||||
|
cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
|
||||||
|
cl_git_pass(git_remote_rename(remote, "test_remote", NULL, NULL));
|
||||||
|
cl_git_fail(git_remote_load(&remote, g_repo, "origin"));
|
||||||
|
git_remote_free(remote);
|
||||||
|
|
||||||
|
cl_git_pass(
|
||||||
|
git_submodule_add_setup(&sm, g_repo, "../TestGitRepository", "TestGitRepository", 1)
|
||||||
|
);
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
assert_submodule_url("TestGitRepository", "https://github.com/libgit2/TestGitRepository");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_submodule_add__url_relative_to_origin(void)
|
||||||
|
{
|
||||||
|
git_submodule *sm;
|
||||||
|
|
||||||
|
/* default remote url is https://github.com/libgit2/false.git */
|
||||||
|
g_repo = cl_git_sandbox_init("testrepo2");
|
||||||
|
|
||||||
|
cl_git_pass(
|
||||||
|
git_submodule_add_setup(&sm, g_repo, "../TestGitRepository", "TestGitRepository", 1)
|
||||||
|
);
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
assert_submodule_url("TestGitRepository", "https://github.com/libgit2/TestGitRepository");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_submodule_add__url_relative_to_workdir(void)
|
||||||
|
{
|
||||||
|
git_submodule *sm;
|
||||||
|
|
||||||
|
/* In this repo, HEAD (master) has no remote tracking branc h*/
|
||||||
|
g_repo = cl_git_sandbox_init("testrepo");
|
||||||
|
|
||||||
|
cl_git_pass(
|
||||||
|
git_submodule_add_setup(&sm, g_repo, "./", "TestGitRepository", 1)
|
||||||
|
);
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
assert_submodule_url("TestGitRepository", git_repository_workdir(g_repo));
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#include "clar_libgit2.h"
|
#include "clar_libgit2.h"
|
||||||
#include "submodule_helpers.h"
|
#include "submodule_helpers.h"
|
||||||
#include "posix.h"
|
|
||||||
#include "git2/sys/repository.h"
|
#include "git2/sys/repository.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
static git_repository *g_repo = NULL;
|
static git_repository *g_repo = NULL;
|
||||||
|
|
||||||
@ -115,13 +115,7 @@ void test_submodule_lookup__lookup_even_with_unborn_head(void)
|
|||||||
&head, g_repo, "HEAD", "refs/heads/garbage", 1, NULL, NULL));
|
&head, g_repo, "HEAD", "refs/heads/garbage", 1, NULL, NULL));
|
||||||
git_reference_free(head);
|
git_reference_free(head);
|
||||||
|
|
||||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
test_submodule_lookup__simple_lookup(); /* baseline should still pass */
|
||||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
|
||||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
|
||||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
|
||||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
|
||||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
|
||||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_submodule_lookup__lookup_even_with_missing_index(void)
|
void test_submodule_lookup__lookup_even_with_missing_index(void)
|
||||||
@ -133,44 +127,145 @@ void test_submodule_lookup__lookup_even_with_missing_index(void)
|
|||||||
git_repository_set_index(g_repo, idx);
|
git_repository_set_index(g_repo, idx);
|
||||||
git_index_free(idx);
|
git_index_free(idx);
|
||||||
|
|
||||||
|
test_submodule_lookup__simple_lookup(); /* baseline should still pass */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void baseline_tests(void)
|
||||||
|
{
|
||||||
|
/* small baseline that should work even if we change the index or make
|
||||||
|
* commits from the index
|
||||||
|
*/
|
||||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
assert_submodule_exists(g_repo, "sm_unchanged");
|
||||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
|
||||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
||||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
||||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
}
|
||||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
|
||||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
static void add_submodule_with_commit(const char *name)
|
||||||
|
{
|
||||||
|
git_submodule *sm;
|
||||||
|
git_repository *smrepo;
|
||||||
|
git_index *idx;
|
||||||
|
git_buf p = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||||
|
"https://github.com/libgit2/libgit2.git", name, 1));
|
||||||
|
|
||||||
|
assert_submodule_exists(g_repo, name);
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_open(&smrepo, sm));
|
||||||
|
cl_git_pass(git_repository_index(&idx, smrepo));
|
||||||
|
|
||||||
|
cl_git_pass(git_buf_joinpath(&p, git_repository_workdir(smrepo), "file"));
|
||||||
|
cl_git_mkfile(p.ptr, "new file");
|
||||||
|
git_buf_free(&p);
|
||||||
|
|
||||||
|
cl_git_pass(git_index_add_bypath(idx, "file"));
|
||||||
|
cl_git_pass(git_index_write(idx));
|
||||||
|
git_index_free(idx);
|
||||||
|
|
||||||
|
cl_repo_commit_from_index(NULL, smrepo, NULL, 0, "initial commit");
|
||||||
|
git_repository_free(smrepo);
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_finalize(sm));
|
||||||
|
|
||||||
|
git_submodule_free(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_submodule_lookup__just_added(void)
|
void test_submodule_lookup__just_added(void)
|
||||||
{
|
{
|
||||||
git_submodule *sm;
|
git_submodule *sm;
|
||||||
|
git_buf snap1 = GIT_BUF_INIT, snap2 = GIT_BUF_INIT;
|
||||||
|
git_reference *original_head = NULL;
|
||||||
|
|
||||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_just_added", 1));
|
refute_submodule_exists(g_repo, "sm_just_added", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_2", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_idx", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_head", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||||
|
baseline_tests();
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&snap1, "submod2/.gitmodules"));
|
||||||
|
cl_git_pass(git_repository_head(&original_head, g_repo));
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||||
|
"https://github.com/libgit2/libgit2.git", "sm_just_added", 1));
|
||||||
git_submodule_free(sm);
|
git_submodule_free(sm);
|
||||||
assert_submodule_exists(g_repo, "sm_just_added");
|
assert_submodule_exists(g_repo, "sm_just_added");
|
||||||
|
|
||||||
cl_git_pass(git_submodule_add_setup(&sm, g_repo, "https://github.com/libgit2/libgit2.git", "sm_just_added_2", 1));
|
cl_git_pass(git_submodule_add_setup(&sm, g_repo,
|
||||||
|
"https://github.com/libgit2/libgit2.git", "sm_just_added_2", 1));
|
||||||
assert_submodule_exists(g_repo, "sm_just_added_2");
|
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||||
|
cl_git_fail(git_submodule_add_finalize(sm)); /* fails if no HEAD */
|
||||||
git_submodule_free(sm);
|
git_submodule_free(sm);
|
||||||
|
|
||||||
cl_git_append2file("submod2/.gitmodules", "\n[submodule \"mismatch_name\"]\n\tpath = mismatch_path\n\turl = https://example.com/example.git\n\n");
|
add_submodule_with_commit("sm_just_added_head");
|
||||||
|
cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "commit new sm to head");
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(g_repo, 1));
|
add_submodule_with_commit("sm_just_added_idx");
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&snap2, "submod2/.gitmodules"));
|
||||||
|
|
||||||
|
cl_git_append2file(
|
||||||
|
"submod2/.gitmodules",
|
||||||
|
"\n[submodule \"mismatch_name\"]\n"
|
||||||
|
"\tpath = mismatch_path\n"
|
||||||
|
"\turl = https://example.com/example.git\n\n");
|
||||||
|
|
||||||
assert_submodule_exists(g_repo, "mismatch_name");
|
assert_submodule_exists(g_repo, "mismatch_name");
|
||||||
assert_submodule_exists(g_repo, "mismatch_path");
|
assert_submodule_exists(g_repo, "mismatch_path");
|
||||||
|
|
||||||
assert_submodule_exists(g_repo, "sm_just_added");
|
assert_submodule_exists(g_repo, "sm_just_added");
|
||||||
assert_submodule_exists(g_repo, "sm_just_added_2");
|
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||||
|
baseline_tests();
|
||||||
|
|
||||||
/* all the regular ones should still be working right, too */
|
cl_git_rewritefile("submod2/.gitmodules", snap2.ptr);
|
||||||
|
git_buf_free(&snap2);
|
||||||
|
|
||||||
assert_submodule_exists(g_repo, "sm_unchanged");
|
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||||
assert_submodule_exists(g_repo, "sm_added_and_uncommited");
|
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||||
assert_submodule_exists(g_repo, "sm_gitmodules_only");
|
assert_submodule_exists(g_repo, "sm_just_added");
|
||||||
refute_submodule_exists(g_repo, "not-submodule", GIT_EEXISTS);
|
assert_submodule_exists(g_repo, "sm_just_added_2");
|
||||||
refute_submodule_exists(g_repo, "just_a_dir", GIT_ENOTFOUND);
|
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||||
refute_submodule_exists(g_repo, "just_a_file", GIT_ENOTFOUND);
|
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||||
refute_submodule_exists(g_repo, "no_such_file", GIT_ENOTFOUND);
|
baseline_tests();
|
||||||
|
|
||||||
|
cl_git_rewritefile("submod2/.gitmodules", snap1.ptr);
|
||||||
|
git_buf_free(&snap1);
|
||||||
|
|
||||||
|
refute_submodule_exists(g_repo, "mismatch_name", GIT_ENOTFOUND);
|
||||||
|
refute_submodule_exists(g_repo, "mismatch_path", GIT_ENOTFOUND);
|
||||||
|
/* note error code change, because add_setup made a repo in the workdir */
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added", GIT_EEXISTS);
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_2", GIT_EEXISTS);
|
||||||
|
/* these still exist in index and head respectively */
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_idx");
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||||
|
baseline_tests();
|
||||||
|
|
||||||
|
{
|
||||||
|
git_index *idx;
|
||||||
|
cl_git_pass(git_repository_index(&idx, g_repo));
|
||||||
|
cl_git_pass(git_index_remove_bypath(idx, "sm_just_added_idx"));
|
||||||
|
cl_git_pass(git_index_remove_bypath(idx, "sm_just_added_head"));
|
||||||
|
cl_git_pass(git_index_write(idx));
|
||||||
|
git_index_free(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_idx", GIT_EEXISTS);
|
||||||
|
assert_submodule_exists(g_repo, "sm_just_added_head");
|
||||||
|
|
||||||
|
{
|
||||||
|
git_signature *sig;
|
||||||
|
cl_git_pass(git_signature_now(&sig, "resetter", "resetter@email.com"));
|
||||||
|
cl_git_pass(git_reference_create(NULL, g_repo, "refs/heads/master", git_reference_target(original_head), 1, sig, "move head back"));
|
||||||
|
git_signature_free(sig);
|
||||||
|
git_reference_free(original_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_submodule_exists(g_repo, "sm_just_added_head", GIT_EEXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,61 +7,12 @@ static git_repository *g_repo = NULL;
|
|||||||
|
|
||||||
#define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git"
|
#define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git"
|
||||||
#define SM_LIBGIT2 "sm_libgit2"
|
#define SM_LIBGIT2 "sm_libgit2"
|
||||||
#define SM_LIBGIT2B "sm_libgit2b"
|
|
||||||
|
|
||||||
void test_submodule_modify__initialize(void)
|
void test_submodule_modify__initialize(void)
|
||||||
{
|
{
|
||||||
g_repo = setup_fixture_submod2();
|
g_repo = setup_fixture_submod2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_submodule_modify__add(void)
|
|
||||||
{
|
|
||||||
git_submodule *sm;
|
|
||||||
git_config *cfg;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
/* re-add existing submodule */
|
|
||||||
cl_assert_equal_i(
|
|
||||||
GIT_EEXISTS,
|
|
||||||
git_submodule_add_setup(NULL, g_repo, "whatever", "sm_unchanged", 1));
|
|
||||||
|
|
||||||
/* add a submodule using a gitlink */
|
|
||||||
|
|
||||||
cl_git_pass(
|
|
||||||
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2, 1)
|
|
||||||
);
|
|
||||||
git_submodule_free(sm);
|
|
||||||
|
|
||||||
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2 "/.git"));
|
|
||||||
|
|
||||||
cl_assert(git_path_isdir("submod2/.git/modules"));
|
|
||||||
cl_assert(git_path_isdir("submod2/.git/modules/" SM_LIBGIT2));
|
|
||||||
cl_assert(git_path_isfile("submod2/.git/modules/" SM_LIBGIT2 "/HEAD"));
|
|
||||||
|
|
||||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
|
||||||
cl_git_pass(
|
|
||||||
git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2 ".url"));
|
|
||||||
cl_assert_equal_s(s, SM_LIBGIT2_URL);
|
|
||||||
git_config_free(cfg);
|
|
||||||
|
|
||||||
/* add a submodule not using a gitlink */
|
|
||||||
|
|
||||||
cl_git_pass(
|
|
||||||
git_submodule_add_setup(&sm, g_repo, SM_LIBGIT2_URL, SM_LIBGIT2B, 0)
|
|
||||||
);
|
|
||||||
git_submodule_free(sm);
|
|
||||||
|
|
||||||
cl_assert(git_path_isdir("submod2/" SM_LIBGIT2B "/.git"));
|
|
||||||
cl_assert(git_path_isfile("submod2/" SM_LIBGIT2B "/.git/HEAD"));
|
|
||||||
cl_assert(!git_path_exists("submod2/.git/modules/" SM_LIBGIT2B));
|
|
||||||
|
|
||||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
|
||||||
cl_git_pass(
|
|
||||||
git_config_get_string(&s, cfg, "submodule." SM_LIBGIT2B ".url"));
|
|
||||||
cl_assert_equal_s(s, SM_LIBGIT2_URL);
|
|
||||||
git_config_free(cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int delete_one_config(const git_config_entry *entry, void *payload)
|
static int delete_one_config(const git_config_entry *entry, void *payload)
|
||||||
{
|
{
|
||||||
git_config *cfg = payload;
|
git_config *cfg = payload;
|
||||||
@ -118,6 +69,26 @@ static int sync_one_submodule(
|
|||||||
return git_submodule_sync(sm);
|
return git_submodule_sync(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void assert_submodule_url_is_synced(
|
||||||
|
git_submodule *sm, const char *parent_key, const char *child_key)
|
||||||
|
{
|
||||||
|
git_config *cfg;
|
||||||
|
const char *str;
|
||||||
|
git_repository *smrepo;
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, parent_key));
|
||||||
|
cl_assert_equal_s(git_submodule_url(sm), str);
|
||||||
|
git_config_free(cfg);
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_open(&smrepo, sm));
|
||||||
|
cl_git_pass(git_repository_config(&cfg, smrepo));
|
||||||
|
cl_git_pass(git_config_get_string(&str, cfg, child_key));
|
||||||
|
cl_assert_equal_s(git_submodule_url(sm), str);
|
||||||
|
git_config_free(cfg);
|
||||||
|
git_repository_free(smrepo);
|
||||||
|
}
|
||||||
|
|
||||||
void test_submodule_modify__sync(void)
|
void test_submodule_modify__sync(void)
|
||||||
{
|
{
|
||||||
git_submodule *sm1, *sm2, *sm3;
|
git_submodule *sm1, *sm2, *sm3;
|
||||||
@ -153,14 +124,12 @@ void test_submodule_modify__sync(void)
|
|||||||
cl_git_pass(git_submodule_foreach(g_repo, sync_one_submodule, NULL));
|
cl_git_pass(git_submodule_foreach(g_repo, sync_one_submodule, NULL));
|
||||||
|
|
||||||
/* check that submodule config is updated */
|
/* check that submodule config is updated */
|
||||||
cl_git_pass(git_repository_config(&cfg, g_repo));
|
assert_submodule_url_is_synced(
|
||||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM1".url"));
|
sm1, "submodule."SM1".url", "branch.origin.remote");
|
||||||
cl_assert_equal_s(git_submodule_url(sm1), str);
|
assert_submodule_url_is_synced(
|
||||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM2".url"));
|
sm2, "submodule."SM2".url", "branch.origin.remote");
|
||||||
cl_assert_equal_s(git_submodule_url(sm2), str);
|
assert_submodule_url_is_synced(
|
||||||
cl_git_pass(git_config_get_string(&str, cfg, "submodule."SM3".url"));
|
sm3, "submodule."SM3".url", "branch.origin.remote");
|
||||||
cl_assert_equal_s(git_submodule_url(sm3), str);
|
|
||||||
git_config_free(cfg);
|
|
||||||
|
|
||||||
git_submodule_free(sm1);
|
git_submodule_free(sm1);
|
||||||
git_submodule_free(sm2);
|
git_submodule_free(sm2);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "clar_libgit2.h"
|
#include "clar_libgit2.h"
|
||||||
#include "posix.h"
|
#include "posix.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
void test_submodule_nosubs__cleanup(void)
|
void test_submodule_nosubs__cleanup(void)
|
||||||
{
|
{
|
||||||
@ -68,7 +69,10 @@ void test_submodule_nosubs__reload_add_reload(void)
|
|||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(repo, 0));
|
cl_git_pass(git_submodule_reload_all(repo, 0));
|
||||||
|
|
||||||
cl_git_pass(git_submodule_add_setup(&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
/* try one add with a reload (to make sure no errors happen) */
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_setup(&sm, repo,
|
||||||
|
"https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
||||||
|
|
||||||
cl_git_pass(git_submodule_reload_all(repo, 0));
|
cl_git_pass(git_submodule_reload_all(repo, 0));
|
||||||
|
|
||||||
@ -78,6 +82,17 @@ void test_submodule_nosubs__reload_add_reload(void)
|
|||||||
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||||
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||||
git_submodule_free(sm);
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
/* try one add without a reload (to make sure cache inval works, too) */
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_setup(&sm, repo,
|
||||||
|
"https://github.com/libgit2/libgit2.git", "libgit2-again", 1));
|
||||||
|
cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2-again"));
|
||||||
|
cl_assert_equal_s("libgit2-again", git_submodule_name(sm));
|
||||||
|
git_submodule_free(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_submodule_nosubs__bad_gitmodules(void)
|
void test_submodule_nosubs__bad_gitmodules(void)
|
||||||
@ -93,3 +108,69 @@ void test_submodule_nosubs__bad_gitmodules(void)
|
|||||||
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
|
cl_git_pass(git_submodule_lookup(NULL, repo, "foobar"));
|
||||||
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));
|
cl_assert_equal_i(GIT_ENOTFOUND, git_submodule_lookup(NULL, repo, "subdir"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_submodule_nosubs__add_and_delete(void)
|
||||||
|
{
|
||||||
|
git_repository *repo = cl_git_sandbox_init("status");
|
||||||
|
git_submodule *sm;
|
||||||
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
/* note lack of calls to git_submodule_reload_all - this *should* work */
|
||||||
|
|
||||||
|
cl_git_fail(git_submodule_lookup(NULL, repo, "libgit2"));
|
||||||
|
cl_git_fail(git_submodule_lookup(NULL, repo, "submodules/libgit2"));
|
||||||
|
|
||||||
|
/* create */
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_add_setup(
|
||||||
|
&sm, repo, "https://github.com/libgit2/libgit2.git", "submodules/libgit2", 1));
|
||||||
|
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||||
|
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_readbuffer(&buf, "status/.gitmodules"));
|
||||||
|
cl_assert(strstr(buf.ptr, "[submodule \"submodules/libgit2\"]") != NULL);
|
||||||
|
cl_assert(strstr(buf.ptr, "path = submodules/libgit2") != NULL);
|
||||||
|
git_buf_free(&buf);
|
||||||
|
|
||||||
|
/* lookup */
|
||||||
|
|
||||||
|
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||||
|
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||||
|
cl_assert_equal_s("submodules/libgit2", git_submodule_name(sm));
|
||||||
|
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
/* update name */
|
||||||
|
|
||||||
|
cl_git_rewritefile(
|
||||||
|
"status/.gitmodules",
|
||||||
|
"[submodule \"libgit2\"]\n"
|
||||||
|
" path = submodules/libgit2\n"
|
||||||
|
" url = https://github.com/libgit2/libgit2.git\n");
|
||||||
|
|
||||||
|
cl_git_pass(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||||
|
cl_assert_equal_s("libgit2", git_submodule_name(sm));
|
||||||
|
cl_assert_equal_s("submodules/libgit2", git_submodule_path(sm));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
/* revert name update */
|
||||||
|
|
||||||
|
cl_git_rewritefile(
|
||||||
|
"status/.gitmodules",
|
||||||
|
"[submodule \"submodules/libgit2\"]\n"
|
||||||
|
" path = submodules/libgit2\n"
|
||||||
|
" url = https://github.com/libgit2/libgit2.git\n");
|
||||||
|
|
||||||
|
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||||
|
cl_git_pass(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||||
|
git_submodule_free(sm);
|
||||||
|
|
||||||
|
/* remove completely */
|
||||||
|
|
||||||
|
cl_must_pass(p_unlink("status/.gitmodules"));
|
||||||
|
cl_git_fail(git_submodule_lookup(&sm, repo, "libgit2"));
|
||||||
|
cl_git_fail(git_submodule_lookup(&sm, repo, "submodules/libgit2"));
|
||||||
|
}
|
||||||
|
@ -126,20 +126,26 @@ git_repository *setup_fixture_submod2(void)
|
|||||||
return repo;
|
return repo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void assert_submodule_exists(git_repository *repo, const char *name)
|
void assert__submodule_exists(
|
||||||
|
git_repository *repo, const char *name,
|
||||||
|
const char *msg, const char *file, int line)
|
||||||
{
|
{
|
||||||
git_submodule *sm;
|
git_submodule *sm;
|
||||||
cl_git_pass(git_submodule_lookup(&sm, repo, name));
|
int error = git_submodule_lookup(&sm, repo, name);
|
||||||
cl_assert(sm);
|
if (error)
|
||||||
|
cl_git_report_failure(error, file, line, msg);
|
||||||
|
cl_assert_at_line(sm != NULL, file, line);
|
||||||
git_submodule_free(sm);
|
git_submodule_free(sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void refute_submodule_exists(
|
void refute__submodule_exists(
|
||||||
git_repository *repo, const char *name, int expected_error)
|
git_repository *repo, const char *name, int expected_error,
|
||||||
|
const char *msg, const char *file, int line)
|
||||||
{
|
{
|
||||||
git_submodule *sm;
|
git_submodule *sm;
|
||||||
cl_assert_equal_i(
|
clar__assert_equal(
|
||||||
expected_error, git_submodule_lookup(&sm, repo, name));
|
file, line, msg, 1, "%i",
|
||||||
|
expected_error, (int)(git_submodule_lookup(&sm, repo, name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_submodule_status(git_repository *repo, const char *name)
|
unsigned int get_submodule_status(git_repository *repo, const char *name)
|
||||||
@ -154,3 +160,19 @@ unsigned int get_submodule_status(git_repository *repo, const char *name)
|
|||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int print_submodules(git_submodule *sm, const char *name, void *p)
|
||||||
|
{
|
||||||
|
unsigned int loc = 0;
|
||||||
|
GIT_UNUSED(p);
|
||||||
|
git_submodule_location(&loc, sm);
|
||||||
|
fprintf(stderr, "# submodule %s (at %s) flags %x\n",
|
||||||
|
name, git_submodule_path(sm), loc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_submodules(git_repository *repo)
|
||||||
|
{
|
||||||
|
git_submodule_foreach(repo, print_submodules, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -6,5 +6,16 @@ extern git_repository *setup_fixture_submod2(void);
|
|||||||
|
|
||||||
extern unsigned int get_submodule_status(git_repository *, const char *);
|
extern unsigned int get_submodule_status(git_repository *, const char *);
|
||||||
|
|
||||||
extern void assert_submodule_exists(git_repository *, const char *);
|
extern void assert__submodule_exists(
|
||||||
extern void refute_submodule_exists(git_repository *, const char *, int err);
|
git_repository *, const char *, const char *, const char *, int);
|
||||||
|
|
||||||
|
#define assert_submodule_exists(repo,name) \
|
||||||
|
assert__submodule_exists(repo, name, "git_submodule_lookup(" #name ") failed", __FILE__, __LINE__)
|
||||||
|
|
||||||
|
extern void refute__submodule_exists(
|
||||||
|
git_repository *, const char *, int err, const char *, const char *, int);
|
||||||
|
|
||||||
|
#define refute_submodule_exists(repo,name,code) \
|
||||||
|
refute__submodule_exists(repo, name, code, "expected git_submodule_lookup(" #name ") to fail with error " #code, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
extern void dump_submodules(git_repository *repo);
|
||||||
|
Loading…
Reference in New Issue
Block a user