31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
46#ifndef GIT_OID_SHA1_HEXSIZE
47#define GIT_OID_SHA1_HEXSIZE GIT_OID_HEXSZ
59#if LIBGIT2_VER_MAJOR > 1 || (LIBGIT2_VER_MAJOR == 1 && (LIBGIT2_VER_MINOR > 4 || (LIBGIT2_VER_MINOR == 4 && LIBGIT2_VER_REVISION >= 3)))
64 git_libgit2_opts(GIT_OPT_SET_OWNER_VALIDATION, 0);
75 const git_error* err = git_error_last();
88#if defined(__MINGW32__) || defined(__MINGW64__)
90#elif defined(__GNUC__) || defined(__clang__)
141static int _n_git_diff_print_cb(
const git_diff_delta* delta,
const git_diff_hunk* hunk,
const git_diff_line* line,
void* payload) {
147 if (line->content && line->content_len > 0) {
149 Malloc(tmp,
char, line->content_len + 2);
151 memcpy(tmp, line->content, line->content_len);
152 tmp[line->content_len] =
'\0';
172 ngit->
path = strdup(path);
179 int err = git_repository_open(&ngit->
repo, path);
214 ngit->
path = strdup(path);
221 git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
222 opts.flags = GIT_REPOSITORY_INIT_MKPATH;
223 if (initial_branch && initial_branch[0]) {
224 opts.initial_head = initial_branch;
227 int err = git_repository_init_ext(&ngit->
repo, path, &opts);
246 git_repository_free((*repo)->repo);
247 (*repo)->repo = NULL;
250 if ((*repo)->remote_auth) {
251 FreeNoLog((*repo)->remote_auth->username);
252 FreeNoLog((*repo)->remote_auth->password);
253 FreeNoLog((*repo)->remote_auth->ssh_pubkey_path);
254 FreeNoLog((*repo)->remote_auth->ssh_privkey_path);
255 FreeNoLog((*repo)->remote_auth->ssh_passphrase);
270 git_status_options opts = GIT_STATUS_OPTIONS_INIT;
271 opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
272 opts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
274 git_status_list* status_list = NULL;
275 int err = git_status_list_new(&status_list, repo->
repo, &opts);
283 git_status_list_free(status_list);
287 size_t count = git_status_list_entrycount(status_list);
288 for (
size_t i = 0; i < count; i++) {
289 const git_status_entry* entry = git_status_byindex(status_list, i);
290 if (!entry)
continue;
296 const char* fpath = NULL;
297 if (entry->head_to_index && entry->head_to_index->new_file.path) {
298 fpath = entry->head_to_index->new_file.path;
299 }
else if (entry->index_to_workdir && entry->index_to_workdir->new_file.path) {
300 fpath = entry->index_to_workdir->new_file.path;
301 }
else if (entry->index_to_workdir && entry->index_to_workdir->old_file.path) {
302 fpath = entry->index_to_workdir->old_file.path;
306 snprintf(se->
path,
sizeof(se->
path),
"%s", fpath);
312 if (entry->status & GIT_STATUS_INDEX_NEW) {
315 if (entry->status & GIT_STATUS_INDEX_MODIFIED) {
318 if (entry->status & GIT_STATUS_INDEX_DELETED) {
323 if (entry->status & GIT_STATUS_WT_NEW) {
326 if (entry->status & GIT_STATUS_WT_MODIFIED) {
329 if (entry->status & GIT_STATUS_WT_DELETED) {
336 git_status_list_free(status_list);
359 git_index* index = NULL;
362 int err = git_repository_index(&index, repo->
repo);
369 size_t len = strlen(filepath);
375 if (len > 0 && filepath[len - 1] ==
'/') {
376 char* pathspec_str = (
char*)filepath;
377 git_strarray pathspec;
378 pathspec.strings = &pathspec_str;
381 err = git_index_add_all(index, &pathspec, GIT_INDEX_ADD_DEFAULT, NULL, NULL);
388 err = git_index_add_bypath(index, filepath);
396 err = git_index_write(index);
407 git_index_free(index);
420 git_index* index = NULL;
423 int err = git_repository_index(&index, repo->
repo);
430 err = git_index_add_all(index, NULL, GIT_INDEX_ADD_DEFAULT, NULL, NULL);
437 err = git_index_write(index);
448 git_index_free(index);
463 git_reference* head_ref = NULL;
464 git_object* head_obj = NULL;
468 int err = git_repository_head(&head_ref, repo->
repo);
470 err = git_reference_peel(&head_obj, head_ref, GIT_OBJECT_COMMIT);
479 char* path_str = (
char*)filepath;
480 paths.strings = &path_str;
483 err = git_reset_default(repo->
repo, head_obj, &paths);
494 if (head_obj) git_object_free(head_obj);
495 if (head_ref) git_reference_free(head_ref);
514 git_index* index = NULL;
517 git_tree* tree = NULL;
518 git_signature* sig = NULL;
519 git_commit* parent_commit = NULL;
520 git_reference* head_ref = NULL;
523 int err = git_repository_index(&index, repo->
repo);
530 err = git_index_write_tree(&tree_oid, index);
537 err = git_tree_lookup(&tree, repo->
repo, &tree_oid);
544 err = git_signature_now(&sig, author_name, author_email);
553 err = git_repository_head(&head_ref, repo->
repo);
555 err = git_reference_peel((git_object**)&parent_commit, head_ref, GIT_OBJECT_COMMIT);
562 const git_commit* parents[] = {parent_commit};
563 err = git_commit_create(&commit_oid, repo->
repo,
"HEAD", sig, sig,
"UTF-8", message, tree, 1, parents);
565 err = git_commit_create(&commit_oid, repo->
repo,
"HEAD", sig, sig,
"UTF-8", message, tree, 0, NULL);
576 git_oid_tostr(hex,
sizeof(hex), &commit_oid);
582 if (parent_commit) git_commit_free(parent_commit);
583 if (head_ref) git_reference_free(head_ref);
584 if (sig) git_signature_free(sig);
585 if (tree) git_tree_free(tree);
586 git_index_free(index);
600 git_revwalk* walker = NULL;
601 int err = git_revwalk_new(&walker, repo->
repo);
607 git_revwalk_sorting(walker, GIT_SORT_TIME);
609 err = git_revwalk_push_head(walker);
617 git_revwalk_free(walker);
618 int unborn = git_repository_head_unborn(repo->
repo);
630 git_revwalk_free(walker);
636 while (count < max_entries && git_revwalk_next(&oid, walker) == 0) {
637 git_commit* commit = NULL;
638 err = git_commit_lookup(&commit, repo->
repo, &oid);
647 git_commit_free(commit);
653 git_oid_tostr(hex,
sizeof(hex), &oid);
654 snprintf(info->
hash,
sizeof(info->
hash),
"%s", hex);
658 const char* msg = git_commit_message(commit);
664 const git_signature* author = git_commit_author(commit);
666 snprintf(info->
author,
sizeof(info->
author),
"%s <%s>", author->name ? author->name :
"", author->email ? author->email :
"");
667 info->
timestamp = (int64_t)author->when.time;
671 git_commit_free(commit);
675 git_revwalk_free(walker);
688 git_diff* diff = NULL;
689 int err = git_diff_index_to_workdir(&diff, repo->
repo, NULL, NULL);
720 git_object* obj_a = NULL;
721 git_object* obj_b = NULL;
722 git_commit* commit_a = NULL;
723 git_commit* commit_b = NULL;
724 git_tree* tree_a = NULL;
725 git_tree* tree_b = NULL;
726 git_diff* diff = NULL;
727 N_STR* result = NULL;
730 err = git_revparse_single(&obj_a, repo->
repo, hash_a);
736 err = git_revparse_single(&obj_b, repo->
repo, hash_b);
742 err = git_commit_lookup(&commit_a, repo->
repo, git_object_id(obj_a));
748 err = git_commit_lookup(&commit_b, repo->
repo, git_object_id(obj_b));
754 err = git_commit_tree(&tree_a, commit_a);
760 err = git_commit_tree(&tree_b, commit_b);
766 err = git_diff_tree_to_tree(&diff, repo->
repo, tree_a, tree_b, NULL);
780 if (diff) git_diff_free(diff);
781 if (tree_b) git_tree_free(tree_b);
782 if (tree_a) git_tree_free(tree_a);
783 if (commit_b) git_commit_free(commit_b);
784 if (commit_a) git_commit_free(commit_a);
785 if (obj_b) git_object_free(obj_b);
786 if (obj_a) git_object_free(obj_a);
801 char* path_str = (
char*)filepath;
803 paths.strings = &path_str;
806 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
807 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
810 int err = git_checkout_head(repo->
repo, &opts);
832 git_object* obj = NULL;
835 int err = git_revparse_single(&obj, repo->
repo, hash);
841 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
842 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
844 err = git_checkout_tree(repo->
repo, obj, &opts);
850 err = git_repository_set_head_detached(repo->
repo, git_object_id(obj));
859 git_object_free(obj);
872 git_branch_iterator* iter = NULL;
873 int err = git_branch_iterator_new(&iter, repo->
repo, GIT_BRANCH_LOCAL);
881 git_branch_iterator_free(iter);
885 git_reference* ref = NULL;
887 while (git_branch_next(&ref, &type, iter) == 0) {
888 const char* name = NULL;
889 err = git_branch_name(&name, ref);
890 if (err == 0 && name) {
891 char* dup = strdup(name);
896 git_reference_free(ref);
899 git_branch_iterator_free(iter);
916 git_reference* head_ref = NULL;
917 git_commit* head_commit = NULL;
918 git_reference* new_branch = NULL;
921 int err = git_repository_head(&head_ref, repo->
repo);
922 if (err == GIT_EUNBORNBRANCH) {
928 int n = snprintf(refname,
sizeof(refname),
"refs/heads/%s", branch_name);
929 if (n < 0 || (
size_t)n >=
sizeof(refname)) {
930 n_log(
LOG_ERR,
"n_git_create_branch: branch name too long");
933 git_reference* new_ref = NULL;
934 int sym_err = git_reference_symbolic_create(&new_ref, repo->
repo,
"HEAD", refname, 1,
"n_git_create_branch: set HEAD on empty repo");
939 git_reference_free(new_ref);
940 n_log(
LOG_INFO,
"n_git_create_branch: set HEAD to '%s' on empty repository", branch_name);
950 err = git_reference_peel((git_object**)&head_commit, head_ref, GIT_OBJECT_COMMIT);
957 err = git_branch_create(&new_branch, repo->
repo, branch_name, head_commit, 0);
968 if (new_branch) git_reference_free(new_branch);
969 if (head_commit) git_commit_free(head_commit);
970 git_reference_free(head_ref);
985 git_reference* branch_ref = NULL;
988 int err = git_branch_lookup(&branch_ref, repo->
repo, branch_name, GIT_BRANCH_LOCAL);
996 snprintf(refname,
sizeof(refname),
"refs/heads/%s", branch_name);
998 err = git_repository_set_head(repo->
repo, refname);
1005 git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
1006 opts.checkout_strategy = GIT_CHECKOUT_FORCE;
1008 err = git_checkout_head(repo->
repo, &opts);
1019 git_reference_free(branch_ref);
1036 git_reference* head_ref = NULL;
1038 int err = git_repository_head(&head_ref, repo->
repo);
1040 const char* shorthand = git_reference_shorthand(head_ref);
1041 snprintf(out, out_size,
"%s", shorthand ? shorthand :
"");
1042 git_reference_free(head_ref);
1048 if (err == GIT_EUNBORNBRANCH) {
1049 git_reference* sym_ref = NULL;
1050 int sym_err = git_reference_lookup(&sym_ref, repo->
repo,
"HEAD");
1051 if (sym_err == 0 && git_reference_type(sym_ref) == GIT_REFERENCE_SYMBOLIC) {
1052 const char* target = git_reference_symbolic_target(sym_ref);
1055 const char* prefix =
"refs/heads/";
1056 size_t prefix_len = strlen(prefix);
1057 if (strncmp(target, prefix, prefix_len) == 0) {
1058 snprintf(out, out_size,
"%s", target + prefix_len);
1060 snprintf(out, out_size,
"%s", target);
1062 git_reference_free(sym_ref);
1066 if (sym_ref) git_reference_free(sym_ref);
1084 git_reference* branch_ref = NULL;
1086 int err = git_branch_lookup(&branch_ref, repo->
repo, branch_name, GIT_BRANCH_LOCAL);
1092 err = git_branch_delete(branch_ref);
1093 git_reference_free(branch_ref);
1108static int _n_git_cred_cb(git_credential** out,
const char* url,
const char* username_from_url,
unsigned int allowed_types,
void* payload) {
1111 if (!auth)
return GIT_PASSTHROUGH;
1113 switch (auth->
type) {
1115 if ((allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) &&
1118 return git_credential_userpass_plaintext_new(out, user, auth->
password);
1123 if ((allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) &&
1125 return git_credential_userpass_plaintext_new(out, auth->
username, auth->
password);
1130 if ((allowed_types & GIT_CREDENTIAL_SSH_KEY) &&
1132 const char* user = auth->
username ? auth->
username : (username_from_url ? username_from_url :
"git");
1133 return git_credential_ssh_key_new(out, user,
1138 if (allowed_types & GIT_CREDENTIAL_SSH_KEY) {
1139 const char* user = auth->
username ? auth->
username : (username_from_url ? username_from_url :
"git");
1140 return git_credential_ssh_key_from_agent(out, user);
1148 return GIT_PASSTHROUGH;
1171 memset(a, 0,
sizeof(*a));
1194 git_remote* remote = NULL;
1195 int err = git_remote_lookup(&remote, repo->
repo,
"origin");
1198 const char* current_url = git_remote_url(remote);
1199 if (!current_url || strcmp(current_url, url) != 0) {
1200 git_remote_free(remote);
1201 err = git_remote_set_url(repo->
repo,
"origin", url);
1207 git_remote_free(remote);
1211 err = git_remote_create(&remote, repo->
repo,
"origin", url);
1216 git_remote_free(remote);
1233 int unborn = git_repository_head_unborn(repo->
repo);
1240 n_log(
LOG_ERR,
"n_git_push: repository has no commits, commit first before pushing");
1248 n_log(
LOG_ERR,
"n_git_push: cannot determine current branch");
1255 snprintf(refspec,
sizeof(refspec),
"refs/heads/%s:refs/heads/%s",
1258 git_remote* remote = NULL;
1259 int err = git_remote_lookup(&remote, repo->
repo,
"origin");
1267 git_push_options opts = GIT_PUSH_OPTIONS_INIT;
1273 const char* refspecs[] = {refspec};
1274 git_strarray refspec_arr = {(
char**)refspecs, 1};
1276 err = git_remote_push(remote, &refspec_arr, &opts);
1277 git_remote_free(remote);
1280 const git_error* gerr = git_error_last();
1283 (gerr && gerr->message) ? gerr->message :
"unknown error");
1302 git_remote* remote = NULL;
1303 int err = git_remote_lookup(&remote, repo->
repo,
"origin");
1310 git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
1316 err = git_remote_fetch(remote, NULL, &fetch_opts,
"pull");
1317 git_remote_free(remote);
1320 const git_error* gerr = git_error_last();
1323 (gerr && gerr->message) ? gerr->message :
"unknown error");
1330 n_log(
LOG_ERR,
"n_git_pull: cannot determine current branch");
1336 char remote_ref[300];
1337 snprintf(remote_ref,
sizeof(remote_ref),
"refs/remotes/origin/%s", branch);
1340 err = git_reference_name_to_id(&remote_oid, repo->
repo, remote_ref);
1343 _n_git_set_status(repo,
"pull failed: no remote tracking branch for '%s'", branch);
1349 err = git_reference_name_to_id(&local_oid, repo->
repo,
"HEAD");
1357 if (git_oid_equal(&local_oid, &remote_oid)) {
1364 git_annotated_commit* remote_commit = NULL;
1365 err = git_annotated_commit_lookup(&remote_commit, repo->
repo, &remote_oid);
1372 git_merge_analysis_t analysis;
1373 git_merge_preference_t preference;
1374 const git_annotated_commit* their_heads[] = {remote_commit};
1375 err = git_merge_analysis(&analysis, &preference, repo->
repo, their_heads, 1);
1377 git_annotated_commit_free(remote_commit);
1383 if (analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) {
1384 git_annotated_commit_free(remote_commit);
1390 if (analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) {
1392 git_reference* head_ref = NULL;
1393 err = git_repository_head(&head_ref, repo->
repo);
1395 git_annotated_commit_free(remote_commit);
1401 git_reference* new_ref = NULL;
1402 err = git_reference_set_target(&new_ref, head_ref, &remote_oid,
"pull: fast-forward");
1403 git_reference_free(head_ref);
1405 git_annotated_commit_free(remote_commit);
1410 git_reference_free(new_ref);
1413 git_object* target = NULL;
1414 git_object_lookup(&target, repo->
repo, &remote_oid, GIT_OBJECT_COMMIT);
1416 git_checkout_options co_opts = GIT_CHECKOUT_OPTIONS_INIT;
1417 co_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
1418 git_checkout_tree(repo->
repo, target, &co_opts);
1419 git_object_free(target);
1422 git_annotated_commit_free(remote_commit);
1429 git_annotated_commit_free(remote_commit);
1430 n_log(
LOG_ERR,
"n_git_pull: cannot fast-forward, manual merge required");
1431 _n_git_set_status(repo,
"pull failed: cannot fast-forward, manual merge required");
1444 git_remote* remote = NULL;
1445 int err = git_remote_lookup(&remote, repo->
repo,
"origin");
1452 git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
1458 err = git_remote_fetch(remote, NULL, &fetch_opts,
"fetch");
1459 git_remote_free(remote);
1462 const git_error* gerr = git_error_last();
1465 (gerr && gerr->message) ? gerr->message :
"unknown error");
1483 if (ahead) *ahead = 0;
1484 if (behind) *behind = 0;
1487 int unborn = git_repository_head_unborn(repo->
repo);
1508 int err = git_reference_name_to_id(&local_oid, repo->
repo,
"HEAD");
1516 char remote_ref[512];
1517 int ref_len = snprintf(remote_ref,
sizeof(remote_ref),
1518 "refs/remotes/origin/%s", branch);
1519 if (ref_len < 0 || (
size_t)ref_len >=
sizeof(remote_ref)) {
1524 err = git_reference_name_to_id(&remote_oid, repo->
repo, remote_ref);
1527 if (err == GIT_ENOTFOUND || err == GIT_EINVALIDSPEC) {
1528 _n_git_set_status(repo,
"ahead/behind: no remote tracking branch for '%s'", branch);
1532 e = git_error_last();
1533 if (e && e->message) {
1543 if (git_oid_equal(&local_oid, &remote_oid)) {
1549 size_t a = 0, b = 0;
1550 err = git_graph_ahead_behind(&a, &b, repo->
repo, &local_oid, &remote_oid);
1557 if (ahead) *ahead = a;
1558 if (behind) *behind = b;
1564#pragma GCC diagnostic pop
#define FreeNoLog(__ptr)
Free Handler without log.
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
#define __n_assert(__ptr, __ret)
macro to assert things
char short_hash[10]
short (abbreviated) hex hash
char author[256]
author name and email
int64_t timestamp
unix timestamp of the commit
char message[512]
first line of commit message
char * password
password or personal access token, or NULL
char * ssh_privkey_path
path to SSH private key file, or NULL
char hash[42]
full hex hash
char * ssh_pubkey_path
path to SSH public key file, or NULL (derived from private key + ".pub")
int flags
combination of N_GIT_STATUS_* flags
char * path
filesystem path to the repository
git_repository * repo
libgit2 repository handle
char * ssh_passphrase
passphrase for SSH key, or NULL
char last_status[512]
human-readable status message from the last operation
int type
auth type: N_GIT_AUTH_NONE/TOKEN/BASIC/SSH
char * username
username for basic auth or SSH, or NULL
char path[512]
relative path of the file
N_GIT_REMOTE_AUTH * remote_auth
credentials for remote operations, or NULL
void n_git_close(N_GIT_REPO **repo)
Close a Git repository and free resources.
#define N_GIT_AUTH_TOKEN
Remote auth: personal access token (used as password with empty or "x-access-token" user)
N_STR * n_git_diff_commits(N_GIT_REPO *repo, const char *hash_a, const char *hash_b)
Get a diff between two commits identified by hash.
#define N_GIT_STATUS_NEW
File is new / untracked.
int n_git_fetch(N_GIT_REPO *repo)
Fetch from the "origin" remote without merging.
int n_git_push(N_GIT_REPO *repo)
Push the current branch to the "origin" remote.
int n_git_remote_set_url(N_GIT_REPO *repo, const char *url)
Ensure a remote named "origin" exists with the given URL.
int n_git_switch_branch(N_GIT_REPO *repo, const char *branch_name)
Switch to an existing local branch.
int n_git_pull(N_GIT_REPO *repo)
Fetch from "origin" and fast-forward merge the current branch.
int n_git_checkout_path(N_GIT_REPO *repo, const char *filepath)
Restore a single file from HEAD (discard working directory changes).
#define N_GIT_STATUS_MODIFIED
File has been modified.
LIST * n_git_list_branches(N_GIT_REPO *repo)
List all local branch names.
LIST * n_git_status(N_GIT_REPO *repo)
Get the status of all files in the working directory.
int n_git_unstage(N_GIT_REPO *repo, const char *filepath)
Unstage a single file (reset from HEAD).
int n_git_set_remote_auth(N_GIT_REPO *repo, const N_GIT_REMOTE_AUTH *auth)
Set remote authentication credentials on a repo handle.
LIST * n_git_log(N_GIT_REPO *repo, size_t max_entries)
Retrieve commit log entries starting from HEAD.
#define N_GIT_STATUS_STAGED
File is staged in the index.
#define N_GIT_AUTH_SSH
Remote auth: SSH key file.
N_GIT_REPO * n_git_init_ex(const char *path, const char *initial_branch)
Initialize a new Git repository with a custom initial branch name.
#define N_GIT_AUTH_BASIC
Remote auth: username + password.
int n_git_stage_all(N_GIT_REPO *repo)
Stage all modified and untracked files.
int n_git_stage(N_GIT_REPO *repo, const char *filepath)
Stage a file or directory by path.
int n_git_ahead_behind(N_GIT_REPO *repo, size_t *ahead, size_t *behind)
Count commits ahead and behind relative to the remote tracking branch.
int n_git_create_branch(N_GIT_REPO *repo, const char *branch_name)
Create a new branch from HEAD.
int n_git_current_branch(N_GIT_REPO *repo, char *out, size_t out_size)
Get the name of the current branch.
int n_git_checkout_commit(N_GIT_REPO *repo, const char *hash)
Checkout a specific commit (detached HEAD).
#define N_GIT_STATUS_DELETED
File has been deleted.
int n_git_commit(N_GIT_REPO *repo, const char *message, const char *author_name, const char *author_email)
Create a commit from the current index.
N_GIT_REPO * n_git_open(const char *path)
Open an existing Git repository.
N_STR * n_git_diff_workdir(N_GIT_REPO *repo)
Get a diff of the working directory against the index.
N_GIT_REPO * n_git_init(const char *path)
Initialize a new Git repository.
int n_git_delete_branch(N_GIT_REPO *repo, const char *branch_name)
Delete a local branch.
Credentials for remote operations.
Wrapper around a git_repository handle.
Single file status entry.
#define UNLIMITED_LIST_ITEMS
flag to pass to new_generic_list for an unlimited number of item in the list.
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Structure of a generic LIST container.
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
#define LOG_INFO
informational
#define nstrprintf_cat(__nstr_var, __format,...)
Macro to quickly allocate and sprintf and cat to a N_STR.
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
A box including a string and his lenght.
Common headers and low-level functions & define.
static int _n_git_cred_cb(git_credential **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload)
libgit2 credential callback for remote operations.
static void _n_git_status_entry_destroy(void *ptr)
Destructor for N_GIT_STATUS_ENTRY used by LIST.
static void _n_git_string_destroy(void *ptr)
Destructor for char* branch name strings used by LIST.
static void _n_git_log_error(const char *func_name)
Log the last libgit2 error.
static void _n_git_ensure_init(void)
Ensure libgit2 is initialized (idempotent).
#define GIT_OID_SHA1_HEXSIZE
static void _n_git_commit_info_destroy(void *ptr)
Destructor for N_GIT_COMMIT_INFO used by LIST.
static void _n_git_set_status(N_GIT_REPO *repo, const char *fmt,...)
Set the last_status message on a repo handle.
static int _n_git_diff_print_cb(const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload)
Callback for git_diff_print, appends each line to an N_STR.
static int _n_git_initialized
static flag ensuring git_libgit2_init is called only once
libgit2 wrapper for Git repository operations