/** * Init a repository. * * @param path A path to where to init a git repository * @param bare If TRUE, a Git repository without a working directory * is created at the pointed path. If FALSE, provided path will be * considered as the working directory into which the .git directory * will be created. * @return R_NilValue */ SEXP git2r_repository_init(SEXP path, SEXP bare) { int err; git_repository *repository = NULL; if (git2r_arg_check_string(path)) git2r_error(git2r_err_string_arg, __func__, "path"); if (git2r_arg_check_logical(bare)) git2r_error(git2r_err_logical_arg, __func__, "bare"); err = git_repository_init(&repository, CHAR(STRING_ELT(path, 0)), LOGICAL(bare)[0]); if (GIT_OK != err) git2r_error("Error in '%s': Unable to init repository", __func__, NULL); if (repository) git_repository_free(repository); return R_NilValue; }
/** * Fetch new data and update tips * * @param repo S4 class git_repository * @param name The name of the remote to fetch from * @param credentials The credentials for remote repository access. * @param msg The one line long message to be appended to the reflog * @param verbose Print information each time a reference is updated locally. * @param refspecs The refspecs to use for this fetch. Pass R_NilValue * to use the base refspecs. * @return R_NilValue */ SEXP git2r_remote_fetch( SEXP repo, SEXP name, SEXP credentials, SEXP msg, SEXP verbose, SEXP refspecs) { int err; SEXP result = R_NilValue; const git_transfer_progress *stats; git_remote *remote = NULL; git_repository *repository = NULL; git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; git2r_transfer_data payload = GIT2R_TRANSFER_DATA_INIT; git_strarray refs = {0}; if (git2r_arg_check_string(name)) git2r_error(__func__, NULL, "'name'", git2r_err_string_arg); if (git2r_arg_check_credentials(credentials)) git2r_error(__func__, NULL, "'credentials'", git2r_err_credentials_arg); if (git2r_arg_check_string(msg)) git2r_error(__func__, NULL, "'msg'", git2r_err_string_arg); if (git2r_arg_check_logical(verbose)) git2r_error(__func__, NULL, "'verbose'", git2r_err_logical_arg); if (refspecs != R_NilValue && git2r_arg_check_string_vec(refspecs)) git2r_error(__func__, NULL, "'refspecs'", git2r_err_string_vec_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); err = git_remote_lookup(&remote, repository, CHAR(STRING_ELT(name, 0))); if (err) goto cleanup; if (refspecs != R_NilValue) { size_t i, len; /* Count number of non NA values */ len = length(refspecs); for (i = 0; i < len; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.count++; if (refs.count) { /* Allocate the strings in refs */ refs.strings = malloc(refs.count * sizeof(char*)); if (!refs.strings) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); err = GIT_ERROR; goto cleanup; } /* Populate the strings in refs */ for (i = 0; i < refs.count; i++) if (NA_STRING != STRING_ELT(refspecs, i)) refs.strings[i] = (char *)CHAR(STRING_ELT(refspecs, i)); } } if (LOGICAL(verbose)[0]) payload.verbose = 1; payload.credentials = credentials; fetch_opts.callbacks.payload = &payload; fetch_opts.callbacks.credentials = &git2r_cred_acquire_cb; fetch_opts.callbacks.update_tips = &git2r_update_tips_cb; err = git_remote_fetch(remote, &refs, &fetch_opts, CHAR(STRING_ELT(msg, 0))); if (err) goto cleanup; stats = git_remote_stats(remote); PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_transfer_progress"))); git2r_transfer_progress_init(stats, result); cleanup: if (refs.strings) free(refs.strings); if (remote) { if (git_remote_connected(remote)) git_remote_disconnect(remote); git_remote_free(remote); } if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error( __func__, giterr_last(), git2r_err_unable_to_authenticate, NULL); return result; }
/** * Merge branch into HEAD * * @param branch S4 class git_branch to merge into HEAD. * @param merger Who is performing the merge * @param commit_on_success Commit merge commit, if one was created * during a normal merge * @return S4 class git_merge_result */ SEXP git2r_merge_branch(SEXP branch, SEXP merger, SEXP commit_on_success) { int err; SEXP result = R_NilValue; const char *name; git_buf buf = GIT_BUF_INIT; git_branch_t type; git_annotated_commit **merge_heads = NULL; git_reference *reference = NULL; git_repository *repository = NULL; git_signature *who = NULL; if (git2r_arg_check_branch(branch)) git2r_error(__func__, NULL, "'branch'", git2r_err_branch_arg); if (git2r_arg_check_logical(commit_on_success)) git2r_error(__func__, NULL, "'commit_on_success'", git2r_err_logical_arg); if (git2r_arg_check_signature(merger)) git2r_error(__func__, NULL, "'merger'", git2r_err_signature_arg); err = git2r_signature_from_arg(&who, merger); if (err) goto cleanup; repository = git2r_repository_open(GET_SLOT(branch, Rf_install("repo"))); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); name = CHAR(STRING_ELT(GET_SLOT(branch, Rf_install("name")), 0)); type = INTEGER(GET_SLOT(branch, Rf_install("type")))[0]; err = git_branch_lookup(&reference, repository, name, type); if (err) goto cleanup; merge_heads = calloc(1, sizeof(git_annotated_commit*)); if (NULL == merge_heads) { giterr_set_str(GITERR_NONE, git2r_err_alloc_memory_buffer); goto cleanup; } err = git_annotated_commit_from_ref( &(merge_heads[0]), repository, reference); if (err) goto cleanup; err = git_buf_printf(&buf, "merge %s", name); if (err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_merge_result"))); err = git2r_merge( result, repository, (const git_annotated_commit **)merge_heads, 1, GIT_MERGE_PREFERENCE_NONE, buf.ptr, who, LOGICAL(commit_on_success)[0]); cleanup: git_buf_free(&buf); if (who) git_signature_free(who); if (merge_heads) git2r_merge_heads_free(merge_heads, 1); if (reference) git_reference_free(reference); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (err) git2r_error(__func__, giterr_last(), NULL, NULL); return result; }
/** * Stash * * @param repo The repository * @param message Optional description * @param index All changes already added to the index are left * intact in the working directory. Default is FALSE * @param untracked All untracked files are also stashed and then * cleaned up from the working directory. Default is FALSE * @param ignored All ignored files are also stashed and then cleaned * up from the working directory. Default is FALSE * @param stasher Signature with stasher and time of stash * @return S3 class git_stash */ SEXP git2r_stash_save( SEXP repo, SEXP message, SEXP index, SEXP untracked, SEXP ignored, SEXP stasher) { int error, nprotect = 0; SEXP result = R_NilValue, class; git_oid oid; git_stash_flags flags = GIT_STASH_DEFAULT; git_commit *commit = NULL; git_repository *repository = NULL; git_signature *c_stasher = NULL; if (git2r_arg_check_logical(index)) git2r_error(__func__, NULL, "'index'", git2r_err_logical_arg); if (git2r_arg_check_logical(untracked)) git2r_error(__func__, NULL, "'untracked'", git2r_err_logical_arg); if (git2r_arg_check_logical(ignored)) git2r_error(__func__, NULL, "'ignored'", git2r_err_logical_arg); if (git2r_arg_check_signature(stasher)) git2r_error(__func__, NULL, "'stasher'", git2r_err_signature_arg); repository = git2r_repository_open(repo); if (!repository) git2r_error(__func__, NULL, git2r_err_invalid_repository, NULL); if (LOGICAL(index)[0]) flags |= GIT_STASH_KEEP_INDEX; if (LOGICAL(untracked)[0]) flags |= GIT_STASH_INCLUDE_UNTRACKED; if (LOGICAL(ignored)[0]) flags |= GIT_STASH_INCLUDE_IGNORED; error = git2r_signature_from_arg(&c_stasher, stasher); if (error) goto cleanup; error = git_stash_save( &oid, repository, c_stasher, CHAR(STRING_ELT(message, 0)), flags); if (error) { if (GIT_ENOTFOUND == error) error = GIT_OK; goto cleanup; } PROTECT(result = Rf_mkNamed(VECSXP, git2r_S3_items__git_commit)); nprotect++; Rf_setAttrib(result, R_ClassSymbol, class = Rf_allocVector(STRSXP, 2)); SET_STRING_ELT(class, 0, Rf_mkChar("git_stash")); SET_STRING_ELT(class, 1, Rf_mkChar("git_commit")); error = git2r_stash_init(&oid, repository, repo, result); cleanup: git_commit_free(commit); git_signature_free(c_stasher); git_repository_free(repository); if (nprotect) UNPROTECT(nprotect); if (error) git2r_error(__func__, GIT2R_ERROR_LAST(), NULL, NULL); return result; }
/** * Add a note for an object * * @param repo S4 class git_repository * @param sha The sha string of object * @param commit S4 class git_commit * @param message Content of the note to add * @param ref Canonical name of the reference to use * @param author Signature of the notes note author * @param committer Signature of the notes note committer * @param force Overwrite existing note * @return S4 class git_note */ SEXP git2r_note_create( SEXP repo, SEXP sha, SEXP message, SEXP ref, SEXP author, SEXP committer, SEXP force) { int err; SEXP result = R_NilValue; int overwrite = 0; git_oid note_oid; git_oid object_oid; git_signature *sig_author = NULL; git_signature *sig_committer = NULL; git_repository *repository = NULL; if (git2r_arg_check_sha(sha)) git2r_error(git2r_err_sha_arg, __func__, "sha"); if (git2r_arg_check_string(message)) git2r_error(git2r_err_string_arg, __func__, "message"); if (git2r_arg_check_string(ref)) git2r_error(git2r_err_string_arg, __func__, "ref"); if (git2r_arg_check_signature(author)) git2r_error(git2r_err_signature_arg, __func__, "author"); if (git2r_arg_check_signature(committer)) git2r_error(git2r_err_signature_arg, __func__, "committer"); if (git2r_arg_check_logical(force)) git2r_error(git2r_err_logical_arg, __func__, "force"); repository = git2r_repository_open(repo); if (!repository) git2r_error(git2r_err_invalid_repository, __func__, NULL); err = git2r_signature_from_arg(&sig_author, author); if (GIT_OK != err) goto cleanup; err = git2r_signature_from_arg(&sig_committer, committer); if (GIT_OK != err) goto cleanup; err = git_oid_fromstr(&object_oid, CHAR(STRING_ELT(sha, 0))); if (GIT_OK != err) goto cleanup; if (LOGICAL(force)[0]) overwrite = 1; err = git_note_create( ¬e_oid, repository, CHAR(STRING_ELT(ref, 0)), sig_author, sig_committer, &object_oid, CHAR(STRING_ELT(message, 0)), overwrite); if (GIT_OK != err) goto cleanup; PROTECT(result = NEW_OBJECT(MAKE_CLASS("git_note"))); err = git2r_note_init(¬e_oid, &object_oid, repository, CHAR(STRING_ELT(ref, 0)), repo, result); cleanup: if (sig_author) git_signature_free(sig_author); if (sig_committer) git_signature_free(sig_committer); if (repository) git_repository_free(repository); if (R_NilValue != result) UNPROTECT(1); if (GIT_OK != err) git2r_error(git2r_err_from_libgit2, __func__, giterr_last()->message); return result; }