static int futils__rmdir_empty_parent(void *opaque, git_buf *path) { futils__rmdir_data *data = opaque; int error; if (git_buf_len(path) <= data->baselen) return GIT_ITEROVER; error = p_rmdir(git_buf_cstr(path)); if (error) { int en = errno; if (en == ENOENT || en == ENOTDIR) { giterr_clear(); error = 0; } else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) { giterr_clear(); error = GIT_ITEROVER; } else { futils__error_cannot_rmdir(git_buf_cstr(path), NULL); } } return error; }
static int packfile_load__cb(void *data, git_buf *path) { struct pack_backend *backend = (pack_backend*) data; struct git_pack_file *pack; const char *path_str = git_buf_cstr(path); size_t i, cmp_len = git_buf_len(path); int error; if (cmp_len <= strlen(".idx") || git__suffixcmp(path_str, ".idx") != 0) return 0; /* not an index */ cmp_len -= strlen(".idx"); for (i = 0; i < backend->packs.length; ++i) { struct git_pack_file *p = (git_pack_file*) git_vector_get(&backend->packs, i); if (memcmp(p->pack_name, path_str, cmp_len) == 0) return 0; } error = git_mwindow_get_pack(&pack, path->ptr); /* ignore missing .pack file as git does */ if (error == GIT_ENOTFOUND) { giterr_clear(); return 0; } if (!error) error = git_vector_insert(&backend->packs, pack); return error; }
static int get_optional_config( bool *found, git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload) { int error = 0; const char *key = git_buf_cstr(buf); if (git_buf_oom(buf)) return -1; if (cb != NULL) error = git_config_get_multivar_foreach(config, key, NULL, cb, payload); else error = git_config_get_string(payload, config, key); if (found) *found = !error; if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } return error; }
int git_revwalk_next(git_oid *oid, git_revwalk *walk) { int error; git_commit_list_node *next; assert(walk && oid); if (!walk->walking) { if ((error = prepare_walk(walk)) < 0) return error; } error = walk->get_next(&next, walk); if (error == GIT_ITEROVER) { git_revwalk_reset(walk); giterr_clear(); return GIT_ITEROVER; } if (!error) git_oid_cpy(oid, &next->oid); return error; }
static int load_workdir(git_repository *repo, git_buf *parent_path) { int error; git_config *config; const char *worktree; git_buf worktree_buf = GIT_BUF_INIT; if (repo->is_bare) return 0; if (git_repository_config__weakptr(&config, repo) < 0) return -1; error = git_config_get_string(&worktree, config, "core.worktree"); if (!error && worktree != NULL) repo->workdir = git__strdup(worktree); else if (error != GIT_ENOTFOUND) return error; else { giterr_clear(); if (parent_path && git_path_isdir(parent_path->ptr)) repo->workdir = git_buf_detach(parent_path); else { git_path_dirname_r(&worktree_buf, repo->path_repository); git_path_to_dir(&worktree_buf); repo->workdir = git_buf_detach(&worktree_buf); } } GITERR_CHECK_ALLOC(repo->workdir); return 0; }
static void *create_refs(void *arg) { int *id = arg, i; git_oid head; char name[128]; git_reference *ref[10]; cl_git_pass(git_reference_name_to_id(&head, g_repo, "HEAD")); for (i = 0; i < 10; ++i) { p_snprintf(name, sizeof(name), "refs/heads/thread-%03d-%02d", *id, i); cl_git_pass(git_reference_create(&ref[i], g_repo, name, &head, 0, NULL)); if (i == 5) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); } } for (i = 0; i < 10; ++i) git_reference_free(ref[i]); giterr_clear(); return arg; }
static int certificate_check(winhttp_stream *s, int valid) { int error; winhttp_subtransport *t = OWNING_SUBTRANSPORT(s); PCERT_CONTEXT cert_ctx; DWORD cert_ctx_size = sizeof(cert_ctx); git_cert_x509 cert; /* If there is no override, we should fail if WinHTTP doesn't think it's fine */ if (t->owner->certificate_check_cb == NULL && !valid) return GIT_ECERTIFICATE; if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl) return 0; if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) { giterr_set(GITERR_OS, "failed to get server certificate"); return -1; } giterr_clear(); cert.cert_type = GIT_CERT_X509; cert.data = cert_ctx->pbCertEncoded; cert.len = cert_ctx->cbCertEncoded; error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->cred_acquire_payload); CertFreeCertificateContext(cert_ctx); if (error < 0 && !giterr_last()) giterr_set(GITERR_NET, "user cancelled certificate check"); return error; }
int git_submodule_foreach( git_repository *repo, int (*callback)(git_submodule *sm, const char *name, void *payload), void *payload) { int error; git_submodule *sm; git_vector seen = GIT_VECTOR_INIT; git_vector_set_cmp(&seen, submodule_cmp); assert(repo && callback); if ((error = load_submodule_config(repo)) < 0) return error; git_strmap_foreach_value(repo->submodules, sm, { /* Usually the following will not come into play - it just prevents * us from issuing a callback twice for a submodule where the name * and path are not the same. */ if (sm->refcount > 1) { if (git_vector_bsearch(NULL, &seen, sm) != GIT_ENOTFOUND) continue; if ((error = git_vector_insert(&seen, sm)) < 0) break; } if (callback(sm, sm->name, payload)) { giterr_clear(); error = GIT_EUSER; break; } });
static void *run_workdir_iterator(void *arg) { int error = 0; git_iterator *iter; const git_index_entry *entry = NULL; cl_git_pass(git_iterator_for_workdir( &iter, _repo, NULL, NULL, GIT_ITERATOR_DONT_AUTOEXPAND, NULL, NULL)); while (!error) { if (entry && entry->mode == GIT_FILEMODE_TREE) { error = git_iterator_advance_into(&entry, iter); if (error == GIT_ENOTFOUND) error = git_iterator_advance(&entry, iter); } else { error = git_iterator_advance(&entry, iter); } if (!error) (void)git_iterator_current_is_ignored(iter); } cl_assert_equal_i(GIT_ITEROVER, error); git_iterator_free(iter); giterr_clear(); return arg; }
size_t git_patch_size( git_patch *patch, int include_context, int include_hunk_headers, int include_file_headers) { size_t out; assert(patch); out = patch->content_size; if (!include_context) out -= patch->context_size; if (include_hunk_headers) out += patch->header_size; if (include_file_headers) { git_buf file_header = GIT_BUF_INIT; if (git_diff_delta__format_file_header( &file_header, patch->delta, NULL, NULL, 0) < 0) giterr_clear(); else out += git_buf_len(&file_header); git_buf_free(&file_header); } return out; }
int git_futils_rmdir_r( const char *path, const char *base, uint32_t flags) { int error; git_buf fullpath = GIT_BUF_INIT; futils__rmdir_data data; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0) return -1; memset(&data, 0, sizeof(data)); data.base = base ? base : ""; data.baselen = base ? strlen(base) : 0; data.flags = flags; error = futils__rmdir_recurs_foreach(&data, &fullpath); /* remove now-empty parents if requested */ if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) error = git_path_walk_up( &fullpath, base, futils__rmdir_empty_parent, &data); if (error == GIT_ITEROVER) { giterr_clear(); error = 0; } git_buf_free(&fullpath); return error; }
int git_diff_driver_lookup( git_diff_driver **out, git_repository *repo, const char *path) { int error = 0; const char *value; assert(out); *out = NULL; if (!repo || !path || !strlen(path)) /* just use the auto value */; else if ((error = git_attr_get(&value, repo, 0, path, "diff")) < 0) /* return error below */; else if (GIT_ATTR_UNSPECIFIED(value)) /* just use the auto value */; else if (GIT_ATTR_FALSE(value)) *out = &global_drivers[DIFF_DRIVER_BINARY]; else if (GIT_ATTR_TRUE(value)) *out = &global_drivers[DIFF_DRIVER_TEXT]; /* otherwise look for driver information in config and build driver */ else if ((error = git_diff_driver_load(out, repo, value)) < 0) { if (error == GIT_ENOTFOUND) { error = 0; giterr_clear(); } } if (!*out) *out = &global_drivers[DIFF_DRIVER_AUTO]; return error; }
/* * call-seq: * tree.count_recursive(limit=nil) -> count * * `limit` - The maximum number of blobs to the count in the repository. * Rugged will stop walking the tree after `limit` items to avoid long * execution times. * * Return the number of blobs (up to the limit) contained in the tree and * all subtrees. */ static VALUE rb_git_tree_entrycount_recursive(int argc, VALUE* argv, VALUE self) { git_tree *tree; int error; struct rugged_treecount_cb_payload payload; VALUE rb_limit; Data_Get_Struct(self, git_tree, tree); rb_scan_args(argc, argv, "01", &rb_limit); payload.limit = -1; payload.count = 0; if (!NIL_P(rb_limit)) { Check_Type(rb_limit, T_FIXNUM); payload.limit = FIX2INT(rb_limit); } error = git_tree_walk(tree, GIT_TREEWALK_PRE, &rugged__treecount_cb, (void *)&payload); if (error && giterr_last()->klass == GITERR_CALLBACK) { giterr_clear(); error = 0; } rugged_exception_check(error); return INT2FIX(payload.count); }
static void *delete_refs(void *arg) { int *id = arg, i; git_reference *ref; char name[128]; for (i = 0; i < 10; ++i) { p_snprintf( name, sizeof(name), "refs/heads/thread-%03d-%02d", (*id) & ~0x3, i); if (!git_reference_lookup(&ref, g_repo, name)) { cl_git_pass(git_reference_delete(ref)); git_reference_free(ref); } if (i == 5) { git_refdb *refdb; cl_git_pass(git_repository_refdb(&refdb, g_repo)); cl_git_pass(git_refdb_compress(refdb)); git_refdb_free(refdb); } } giterr_clear(); return arg; }
static int notes_ref_lookup(git_buf *out, git_rebase *rebase) { git_config *config = NULL; int do_rewrite, error; if (rebase->options.rewrite_notes_ref) { git_buf_attach_notowned(out, rebase->options.rewrite_notes_ref, strlen(rebase->options.rewrite_notes_ref)); return 0; } if ((error = git_repository_config(&config, rebase->repo)) < 0 || (error = git_config_get_bool(&do_rewrite, config, "notes.rewrite.rebase")) < 0) { if (error != GIT_ENOTFOUND) goto done; giterr_clear(); do_rewrite = 1; } error = do_rewrite ? git_config_get_string_buf(out, config, "notes.rewriteref") : GIT_ENOTFOUND; done: git_config_free(config); return error; }
git_vector_foreach(contents, i, ps) { /* skip if before start_stat or after end_stat */ cmp_len = min(start_len, ps->path_len); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) continue; cmp_len = min(end_len, ps->path_len); if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) continue; git_buf_truncate(&full, prefix_len); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) { if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; git_vector_remove(contents, i--); continue; } break; } if (S_ISDIR(ps->st.st_mode)) { ps->path[ps->path_len++] = '/'; ps->path[ps->path_len] = '\0'; } }
int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) { *out = repo->cvar_cache[(int)cvar]; if (*out == GIT_CVAR_NOT_CACHED) { struct map_data *data = &_cvar_maps[(int)cvar]; git_config *config; int error; error = git_repository_config__weakptr(&config, repo); if (error < 0) return error; if (data->maps) error = git_config_get_mapped( out, config, data->cvar_name, data->maps, data->map_count); else error = git_config_get_bool(out, config, data->cvar_name); if (error == GIT_ENOTFOUND) { giterr_clear(); *out = data->default_value; } else if (error < 0) return error; repo->cvar_cache[(int)cvar] = *out; } return 0; }
static int git_commit__create_internal( git_oid *id, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_oid *tree, git_commit_parent_callback parent_cb, void *parent_payload, bool validate) { int error; git_odb *odb; git_reference *ref = NULL; git_buf buf = GIT_BUF_INIT; const git_oid *current_id = NULL; git_array_oid_t parents = GIT_ARRAY_INIT; if (update_ref) { error = git_reference_lookup_resolved(&ref, repo, update_ref, 10); if (error < 0 && error != GIT_ENOTFOUND) return error; } giterr_clear(); if (ref) current_id = git_reference_target(ref); if ((error = validate_tree_and_parents(&parents, repo, tree, parent_cb, parent_payload, current_id, validate)) < 0) goto cleanup; error = git_commit__create_buffer_internal(&buf, author, committer, message_encoding, message, tree, &parents); if (error < 0) goto cleanup; if (git_repository_odb__weakptr(&odb, repo) < 0) goto cleanup; if (git_odb_write(id, odb, buf.ptr, buf.size, GIT_OBJ_COMMIT) < 0) goto cleanup; if (update_ref != NULL) { error = git_reference__update_for_commit( repo, ref, update_ref, id, "commit"); goto cleanup; } cleanup: git_array_clear(parents); git_reference_free(ref); git_buf_free(&buf); return error; }
static int diff_file_content_load_workdir_file( git_diff_file_content *fc, git_buf *path, git_diff_options *diff_opts) { int error = 0; git_filter_list *fl = NULL; git_file fd = git_futils_open_ro(git_buf_cstr(path)); git_buf raw = GIT_BUF_INIT; if (fd < 0) return fd; if (!fc->file->size && !(fc->file->size = git_futils_filesize(fd))) goto cleanup; if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 && diff_file_content_binary_by_size(fc)) goto cleanup; if ((error = git_filter_list_load( &fl, fc->repo, NULL, fc->file->path, GIT_FILTER_TO_ODB, GIT_FILTER_ALLOW_UNSAFE)) < 0) goto cleanup; /* if there are no filters, try to mmap the file */ if (fl == NULL) { if (!(error = git_futils_mmap_ro( &fc->map, fd, 0, (size_t)fc->file->size))) { fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA; goto cleanup; } /* if mmap failed, fall through to try readbuffer below */ giterr_clear(); } if (!(error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size))) { git_buf out = GIT_BUF_INIT; error = git_filter_list_apply_to_data(&out, fl, &raw); if (out.ptr != raw.ptr) git_buf_dispose(&raw); if (!error) { fc->map.len = out.size; fc->map.data = out.ptr; fc->flags |= GIT_DIFF_FLAG__FREE_DATA; } } cleanup: git_filter_list_free(fl); p_close(fd); return error; }
Exception::Exception() { const git_error *err = giterr_last(); if (err != NULL) { _msg = err->message; giterr_clear(); } }
static int checkout_create_the_new( void *cb_data, const git_diff_delta *delta, float progress) { int error = 0; struct checkout_diff_data *data = cb_data; git_checkout_opts *opts = data->checkout_opts; bool do_checkout = false, do_notify = false; GIT_UNUSED(progress); if (delta->status == GIT_DELTA_MODIFIED || delta->status == GIT_DELTA_TYPECHANGE) { if ((opts->checkout_strategy & GIT_CHECKOUT_OVERWRITE_MODIFIED) != 0) do_checkout = true; else if (opts->skipped_notify_cb != NULL) do_notify = !data->create_submodules; } else if (delta->status == GIT_DELTA_DELETED && (opts->checkout_strategy & GIT_CHECKOUT_CREATE_MISSING) != 0) do_checkout = true; if (do_notify) { if (opts->skipped_notify_cb( delta->old_file.path, &delta->old_file.oid, delta->old_file.mode, opts->notify_payload)) { giterr_clear(); error = GIT_EUSER; } } if (do_checkout) { bool is_submodule = S_ISGITLINK(delta->old_file.mode); if (is_submodule) { data->found_submodules = true; } if (!is_submodule && !data->create_submodules) { error = checkout_blob(data, &delta->old_file); data->completed_steps++; report_progress(data, delta->old_file.path); } else if (is_submodule && data->create_submodules) { error = checkout_submodule(data, &delta->old_file); data->completed_steps++; report_progress(data, delta->old_file.path); } } if (error) data->error = error; return error; }
static int diff_file_content_load_workdir_file( git_diff_file_content *fc, git_buf *path) { int error = 0; git_vector filters = GIT_VECTOR_INIT; git_buf raw = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_file fd = git_futils_open_ro(git_buf_cstr(path)); if (fd < 0) return fd; if (!fc->file->size && !(fc->file->size = git_futils_filesize(fd))) goto cleanup; if (diff_file_content_binary_by_size(fc)) goto cleanup; if ((error = git_filters_load( &filters, fc->repo, fc->file->path, GIT_FILTER_TO_ODB)) < 0) goto cleanup; /* error >= is a filter count */ if (error == 0) { if (!(error = git_futils_mmap_ro( &fc->map, fd, 0, (size_t)fc->file->size))) fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA; else /* fall through to try readbuffer below */ giterr_clear(); } if (error != 0) { error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size); if (error < 0) goto cleanup; if (!filters.length) git_buf_swap(&filtered, &raw); else error = git_filters_apply(&filtered, &raw, &filters); if (!error) { fc->map.len = git_buf_len(&filtered); fc->map.data = git_buf_detach(&filtered); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; } git_buf_free(&raw); git_buf_free(&filtered); } cleanup: git_filters_free(&filters); p_close(fd); return error; }
static int load_config( git_config **out, git_repository *repo, const char *global_config_path, const char *xdg_config_path, const char *system_config_path) { int error; git_buf config_path = GIT_BUF_INIT; git_config *cfg = NULL; assert(repo && out); if ((error = git_config_new(&cfg)) < 0) return error; error = git_buf_joinpath( &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO); if (error < 0) goto on_error; if ((error = git_config_add_file_ondisk( cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; git_buf_free(&config_path); if (global_config_path != NULL && (error = git_config_add_file_ondisk( cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (xdg_config_path != NULL && (error = git_config_add_file_ondisk( cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; if (system_config_path != NULL && (error = git_config_add_file_ondisk( cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0)) < 0 && error != GIT_ENOTFOUND) goto on_error; giterr_clear(); /* clear any lingering ENOTFOUND errors */ *out = cfg; return 0; on_error: git_buf_free(&config_path); git_config_free(cfg); *out = NULL; return error; }
int git_reference__is_valid_name(const char *refname, unsigned int flags) { if (git_reference__normalize_name(NULL, refname, flags) < 0) { giterr_clear(); return false; } return true; }
int cl_repo_get_bool(git_repository *repo, const char *cfg) { int val = 0; git_config *config; cl_git_pass(git_repository_config(&config, repo)); if (git_config_get_bool(&val, config, cfg) < 0) giterr_clear(); git_config_free(config); return val; }
mrb_value mrb_Git_Buf_replace(mrb_state * mrb, mrb_value self) { giterr_clear(); git_buf * native_self = mruby_unbox_git_buf(self); mrb_value str = mrb_nil_value(); mrb_get_args(mrb, "S", str); int err = git_buf_set(native_self, RSTRING_PTR(str), RSTRING_LEN(str)); RAISE_GIT_ERROR(err); return str; }
static int prepare_walk(git_revwalk *walk) { int error; git_commit_list *list; git_commit_list_node *next; /* If there were no pushes, we know that the walk is already over */ if (!walk->did_push) { giterr_clear(); return GIT_ITEROVER; } if (walk->did_hide && (error = premark_uninteresting(walk)) < 0) return error; for (list = walk->user_input; list; list = list->next) { if (process_commit(walk, list->item, list->item->uninteresting) < 0) return -1; } if (walk->sorting & GIT_SORT_TOPOLOGICAL) { unsigned short i; while ((error = walk->get_next(&next, walk)) == 0) { for (i = 0; i < next->out_degree; ++i) { git_commit_list_node *parent = next->parents[i]; parent->in_degree++; } if (git_commit_list_insert(next, &walk->iterator_topo) == NULL) return -1; } if (error != GIT_ITEROVER) return error; walk->get_next = &revwalk_next_toposort; } if (walk->sorting & GIT_SORT_REVERSE) { while ((error = walk->get_next(&next, walk)) == 0) if (git_commit_list_insert(next, &walk->iterator_reverse) == NULL) return -1; if (error != GIT_ITEROVER) return error; walk->get_next = &revwalk_next_reverse; } walk->walking = 1; return 0; }
static int lock_file(git_filebuf *file, int flags) { if (git_path_exists(file->path_lock) == true) { if (flags & GIT_FILEBUF_FORCE) p_unlink(file->path_lock); else { giterr_clear(); /* actual OS error code just confuses */ giterr_set(GITERR_OS, "Failed to lock file '%s' for writing", file->path_lock); return -1; } } /* create path to the file buffer is required */ if (flags & GIT_FILEBUF_FORCE) { /* XXX: Should dirmode here be configurable? Or is 0777 always fine? */ file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, GIT_LOCK_FILE_MODE); } else { file->fd = git_futils_creat_locked(file->path_lock, GIT_LOCK_FILE_MODE); } if (file->fd < 0) return -1; file->fd_is_open = true; if ((flags & GIT_FILEBUF_APPEND) && git_path_exists(file->path_original) == true) { git_file source; char buffer[2048]; ssize_t read_bytes; source = p_open(file->path_original, O_RDONLY); if (source < 0) { giterr_set(GITERR_OS, "Failed to open file '%s' for reading", file->path_original); return -1; } while ((read_bytes = p_read(source, buffer, sizeof(buffer))) > 0) { p_write(file->fd, buffer, read_bytes); if (file->digest) git_hash_update(file->digest, buffer, read_bytes); } p_close(source); if (read_bytes < 0) { giterr_set(GITERR_OS, "Failed to read file '%s'", file->path_original); return -1; } } return 0; }
static int rebase_copy_note( git_rebase *rebase, const char *notes_ref, git_oid *from, git_oid *to, const git_signature *committer) { git_note *note = NULL; git_oid note_id; git_signature *who = NULL; int error; if ((error = git_note_read(¬e, rebase->repo, notes_ref, from)) < 0) { if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; } goto done; } if (!committer) { if((error = git_signature_default(&who, rebase->repo)) < 0) { if (error != GIT_ENOTFOUND || (error = git_signature_now(&who, "unknown", "unknown")) < 0) goto done; giterr_clear(); } committer = who; } error = git_note_create(¬e_id, rebase->repo, notes_ref, git_note_author(note), committer, to, git_note_message(note), 0); done: git_note_free(note); git_signature_free(who); return error; }
GIT2PPP_NAMESPACE_BEGIN Exception::Exception(int errCode) noexcept: _errCode(errCode), _errMessage(nullptr) { const git_error * error = giterr_last(); if (error) { _errMessage = error->message; giterr_clear(); } }