int git_commit_create( git_oid *oid, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_tree *tree, int parent_count, const git_commit *parents[]) { git_buf commit = GIT_BUF_INIT; int i; git_odb *odb; assert(git_object_owner((const git_object *)tree) == repo); git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); for (i = 0; i < parent_count; ++i) { assert(git_object_owner((const git_object *)parents[i]) == repo); git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); } git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); if (message_encoding != NULL) git_buf_printf(&commit, "encoding %s\n", message_encoding); git_buf_putc(&commit, '\n'); if (git_buf_puts(&commit, message) < 0) goto on_error; if (git_repository_odb__weakptr(&odb, repo) < 0) goto on_error; if (git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0) goto on_error; git_buf_free(&commit); if (update_ref != NULL) return git_reference__update(repo, oid, update_ref); return 0; on_error: git_buf_free(&commit); giterr_set(GITERR_OBJECT, "Failed to create commit."); return -1; }
int git_object_lookup_bypath( git_object **out, const git_object *treeish, const char *path, git_otype type) { int error = -1; git_tree *tree = NULL; git_tree_entry *entry = NULL; assert(out && treeish && path); if ((error = git_object_peel((git_object**)&tree, treeish, GIT_OBJ_TREE)) < 0 || (error = git_tree_entry_bypath(&entry, tree, path)) < 0) { goto cleanup; } if (type != GIT_OBJ_ANY && git_tree_entry_type(entry) != type) { giterr_set(GITERR_OBJECT, "object at path '%s' is not of the asked-for type %d", path, type); error = GIT_EINVALIDSPEC; goto cleanup; } error = git_tree_entry_to_object(out, git_object_owner(treeish), entry); cleanup: git_tree_entry_free(entry); git_tree_free(tree); return error; }
static int handle_colon_syntax( git_object **out, git_object *obj, const char *path) { git_object *tree; int error = -1; git_tree_entry *entry = NULL; if ((error = git_object_peel(&tree, obj, GIT_OBJ_TREE)) < 0) return error == GIT_ENOTFOUND ? GIT_EINVALIDSPEC : error; if (*path == '\0') { *out = tree; return 0; } /* * TODO: Handle the relative path syntax * (:./relative/path and :../relative/path) */ if ((error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0) goto cleanup; error = git_tree_entry_to_object(out, git_object_owner(tree), entry); cleanup: git_tree_entry_free(entry); git_object_free(tree); return error; }
int git_branch_create( git_reference **ref_out, git_repository *repository, const char *branch_name, const git_commit *commit, int force) { git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT; int error = -1; assert(branch_name && commit && ref_out); assert(git_object_owner((const git_object *)commit) == repository); if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; error = git_reference_create(&branch, repository, git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force); if (!error) *ref_out = branch; cleanup: git_buf_free(&canonical_branch_name); return error; }
int git_branch_create( git_reference **ref_out, git_repository *repository, const char *branch_name, const git_object *target, int force) { git_object *commit = NULL; git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT; int error = -1; assert(branch_name && target && ref_out); assert(git_object_owner(target) == repository); if (git_object_peel(&commit, (git_object *)target, GIT_OBJ_COMMIT) < 0) return create_error_invalid("The given target does not resolve to a commit"); if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; error = git_reference_create_oid(&branch, repository, git_buf_cstr(&canonical_branch_name), git_object_id(commit), force); if (!error) *ref_out = branch; cleanup: git_object_free(commit); git_buf_free(&canonical_branch_name); return error; }
int git_branch_create( git_oid *oid_out, git_repository *repo, const char *branch_name, const git_object *target, int force) { git_otype target_type = GIT_OBJ_BAD; git_object *commit = NULL; git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT; int error = -1; assert(repo && branch_name && target && oid_out); if (git_object_owner(target) != repo) return create_error_invalid("The given target does not belong to this repository"); target_type = git_object_type(target); switch (target_type) { case GIT_OBJ_TAG: if (git_tag_peel(&commit, (git_tag *)target) < 0) goto cleanup; if (git_object_type(commit) != GIT_OBJ_COMMIT) { create_error_invalid("The given target does not resolve to a commit"); goto cleanup; } break; case GIT_OBJ_COMMIT: commit = (git_object *)target; break; default: return create_error_invalid("Only git_tag and git_commit objects are valid targets."); } if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; if (git_reference_create_oid(&branch, repo, git_buf_cstr(&canonical_branch_name), git_object_id(commit), force) < 0) goto cleanup; git_oid_cpy(oid_out, git_reference_oid(branch)); error = 0; cleanup: if (target_type == GIT_OBJ_TAG) git_object_free(commit); git_reference_free(branch); git_buf_free(&canonical_branch_name); return error; }
static VALUE rb_git_tag_target_SET(VALUE self, VALUE val) { git_tag *tag; git_object *target; Data_Get_Struct(self, git_tag, tag); target = rugged_object_rb2c(git_object_owner((git_object *)tag), val, GIT_OBJ_ANY); git_tag_set_target(tag, target); return Qnil; }
static VALUE rb_git_commit_tree_SET(VALUE self, VALUE val) { git_commit *commit; git_tree *tree; Data_Get_Struct(self, git_commit, commit); tree = (git_tree *)rugged_object_rb2c(git_object_owner((git_object *)commit), val, GIT_OBJ_TREE); git_commit_set_tree(commit, tree); return Qnil; }
static VALUE rb_git_commit_tree_SET(VALUE self, VALUE val) { git_commit *commit; git_tree *tree; RUGGED_OBJ_UNWRAP(self, git_commit, commit); tree = (git_tree *)rugged_object_get(git_object_owner((git_object *)commit), val, GIT_OBJ_TREE); git_commit_set_tree(commit, tree); return Qnil; }
static VALUE rb_git_tag_target_SET(VALUE self, VALUE val) { git_tag *tag; git_object *target; RUGGED_OBJ_UNWRAP(self, git_tag, tag); target = rugged_object_get(git_object_owner((git_object *)tag), val, GIT_OBJ_ANY); git_tag_set_target(tag, target); return Qnil; }
/** * ggit_object_get_owner: * @object: a #GgitObject. * * Gets the #GgitRepository that owns @object. * * Returns: (transfer full): the #GgitRepository that owns this object. * The returned value must be free'd calling g_object_unref(). */ GgitRepository * ggit_object_get_owner (GgitObject *object) { git_repository *repository; g_return_val_if_fail (GGIT_IS_OBJECT (object), NULL); repository = git_object_owner (object->priv->obj); return _ggit_repository_new (repository); }
static int create_branch( git_reference **ref_out, git_repository *repository, const char *branch_name, const git_commit *commit, const char *from, int force) { int is_unmovable_head = 0; git_reference *branch = NULL; git_buf canonical_branch_name = GIT_BUF_INIT, log_message = GIT_BUF_INIT; int error = -1; int bare = git_repository_is_bare(repository); assert(branch_name && commit && ref_out); assert(git_object_owner((const git_object *)commit) == repository); if (force && !bare && git_branch_lookup(&branch, repository, branch_name, GIT_BRANCH_LOCAL) == 0) { error = git_branch_is_head(branch); git_reference_free(branch); branch = NULL; if (error < 0) goto cleanup; is_unmovable_head = error; } if (is_unmovable_head && force) { giterr_set(GITERR_REFERENCE, "Cannot force update branch '%s' as it is " "the current HEAD of the repository.", branch_name); error = -1; goto cleanup; } if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0) goto cleanup; if (git_buf_printf(&log_message, "branch: Created from %s", from) < 0) goto cleanup; error = git_reference_create(&branch, repository, git_buf_cstr(&canonical_branch_name), git_commit_id(commit), force, git_buf_cstr(&log_message)); if (!error) *ref_out = branch; cleanup: git_buf_free(&canonical_branch_name); git_buf_free(&log_message); return error; }
static int blob_content_to_file( git_blob *blob, const char *path, mode_t entry_filemode, git_checkout_opts *opts) { int error = -1, nb_filters = 0; mode_t file_mode = opts->file_mode; bool dont_free_filtered = false; git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_vector filters = GIT_VECTOR_INIT; if (opts->disable_filters || (nb_filters = git_filters_load( &filters, git_object_owner((git_object *)blob), path, GIT_FILTER_TO_WORKTREE)) == 0) { /* Create a fake git_buf from the blob raw data... */ filtered.ptr = blob->odb_object->raw.data; filtered.size = blob->odb_object->raw.len; /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; } if (nb_filters < 0) return nb_filters; if (nb_filters > 0) { if ((error = git_blob__getbuf(&unfiltered, blob)) < 0) goto cleanup; if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0) goto cleanup; } /* Allow overriding of file mode */ if (!file_mode) file_mode = entry_filemode; error = buffer_to_file(&filtered, path, opts->dir_mode, opts->file_open_flags, file_mode); cleanup: git_filters_free(&filters); git_buf_free(&unfiltered); if (!dont_free_filtered) git_buf_free(&filtered); return error; }
void reset_index_to_treeish(git_object *treeish) { git_object *tree; git_index *index; git_repository *repo = git_object_owner(treeish); cl_git_pass(git_object_peel(&tree, treeish, GIT_OBJ_TREE)); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_read_tree(index, (git_tree *)tree)); cl_git_pass(git_index_write(index)); git_object_free(tree); git_index_free(index); }
static int git_tag_create__internal( git_oid *oid, git_repository *repo, const char *tag_name, const git_object *target, const git_signature *tagger, const char *message, int allow_ref_overwrite, int create_tag_annotation) { git_reference *new_ref = NULL; git_buf ref_name = GIT_BUF_INIT; int error; assert(repo && tag_name && target); assert(!create_tag_annotation || (tagger && message)); if (git_object_owner(target) != repo) { giterr_set(GITERR_INVALID, "The given target does not belong to this repository"); return -1; } error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); if (error < 0 && error != GIT_ENOTFOUND) goto cleanup; /** Ensure the tag name doesn't conflict with an already existing * reference unless overwriting has explicitly been requested **/ if (error == 0 && !allow_ref_overwrite) { git_buf_free(&ref_name); giterr_set(GITERR_TAG, "Tag already exists"); return GIT_EEXISTS; } if (create_tag_annotation) { if (write_tag_annotation(oid, repo, tag_name, target, tagger, message) < 0) return -1; } else git_oid_cpy(oid, git_object_id(target)); error = git_reference_create(&new_ref, repo, ref_name.ptr, oid, allow_ref_overwrite, NULL); cleanup: git_reference_free(new_ref); git_buf_free(&ref_name); return error; }
static int handle_caret_curly_syntax(git_object **out, git_object *obj, const char *curly_braces_content) { git_otype expected_type; if (*curly_braces_content == '\0') return dereference_to_non_tag(out, obj); if (*curly_braces_content == '/') return handle_grep_syntax(out, git_object_owner(obj), git_object_id(obj), curly_braces_content + 1); expected_type = parse_obj_type(curly_braces_content); if (expected_type == GIT_OBJ_BAD) return GIT_EINVALIDSPEC; return git_object_peel(out, obj, expected_type); }
int git_object_short_id(git_buf *out, const git_object *obj) { git_repository *repo; int len = GIT_ABBREV_DEFAULT, error; git_oid id = {{0}}; git_odb *odb; assert(out && obj); git_buf_sanitize(out); repo = git_object_owner(obj); if ((error = git_repository__cvar(&len, repo, GIT_CVAR_ABBREV)) < 0) return error; if ((error = git_repository_odb(&odb, repo)) < 0) return error; while (len < GIT_OID_HEXSZ) { /* set up short oid */ memcpy(&id.id, &obj->cached.oid.id, (len + 1) / 2); if (len & 1) id.id[len / 2] &= 0xf0; error = git_odb_exists_prefix(NULL, odb, &id, len); if (error != GIT_EAMBIGUOUS) break; giterr_clear(); len++; } if (!error && !(error = git_buf_grow(out, len + 1))) { git_oid_tostr(out->ptr, len + 1, &id); out->size = len; } git_odb_free(odb); return error; }
int git_reset( git_repository *repo, const git_object *target, git_reset_type reset_type) { git_otype target_type = GIT_OBJ_BAD; git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = -1; assert(repo && target); assert(reset_type == GIT_RESET_SOFT || reset_type == GIT_RESET_MIXED); if (git_object_owner(target) != repo) return reset_error_invalid("The given target does not belong to this repository."); if (reset_type == GIT_RESET_MIXED && git_repository_is_bare(repo)) return reset_error_invalid("Mixed reset is not allowed in a bare repository."); target_type = git_object_type(target); switch (target_type) { case GIT_OBJ_TAG: if (git_tag_peel(&commit, (git_tag *)target) < 0) goto cleanup; if (git_object_type(commit) != GIT_OBJ_COMMIT) { reset_error_invalid("The given target does not resolve to a commit."); goto cleanup; } break; case GIT_OBJ_COMMIT: commit = (git_object *)target; break; default: return reset_error_invalid("Only git_tag and git_commit objects are valid targets."); } //TODO: Check for unmerged entries if (git_reference__update(repo, git_object_id(commit), GIT_HEAD_FILE) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT) { error = 0; goto cleanup; } if (git_commit_tree(&tree, (git_commit *)commit) < 0) { giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the commit tree.", ERROR_MSG); goto cleanup; } if (git_repository_index(&index, repo) < 0) { giterr_set(GITERR_OBJECT, "%s - Failed to retrieve the index.", ERROR_MSG); goto cleanup; } if (git_index_read_tree(index, tree) < 0) { giterr_set(GITERR_INDEX, "%s - Failed to update the index.", ERROR_MSG); goto cleanup; } if (git_index_write(index) < 0) { giterr_set(GITERR_INDEX, "%s - Failed to write the index.", ERROR_MSG); goto cleanup; } error = 0; cleanup: if (target_type == GIT_OBJ_TAG) git_object_free(commit); git_index_free(index); git_tree_free(tree); return error; }
int git_reset_default( git_repository *repo, const git_object *target, const git_strarray* pathspecs) { git_object *commit = NULL; git_tree *tree = NULL; git_diff *diff = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; size_t i, max_i; git_index_entry entry; int error; git_index *index = NULL; assert(pathspecs != NULL && pathspecs->count > 0); memset(&entry, 0, sizeof(git_index_entry)); if ((error = git_repository_index(&index, repo)) < 0) goto cleanup; if (target) { if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s_default - The given target does not belong to this repository.", ERROR_MSG); return -1; } if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; } opts.pathspec = *pathspecs; opts.flags = GIT_DIFF_REVERSE; if ((error = git_diff_tree_to_index( &diff, repo, tree, index, &opts)) < 0) goto cleanup; for (i = 0, max_i = git_diff_num_deltas(diff); i < max_i; ++i) { const git_diff_delta *delta = git_diff_get_delta(diff, i); assert(delta->status == GIT_DELTA_ADDED || delta->status == GIT_DELTA_MODIFIED || delta->status == GIT_DELTA_CONFLICTED || delta->status == GIT_DELTA_DELETED); error = git_index_conflict_remove(index, delta->old_file.path); if (error < 0) { if (delta->status == GIT_DELTA_ADDED && error == GIT_ENOTFOUND) giterr_clear(); else goto cleanup; } if (delta->status == GIT_DELTA_DELETED) { if ((error = git_index_remove(index, delta->old_file.path, 0)) < 0) goto cleanup; } else { entry.mode = delta->new_file.mode; git_oid_cpy(&entry.id, &delta->new_file.id); entry.path = (char *)delta->new_file.path; if ((error = git_index_add(index, &entry)) < 0) goto cleanup; } } error = git_index_write(index); cleanup: git_object_free(commit); git_tree_free(tree); git_index_free(index); git_diff_free(diff); return error; }
static int reset( git_repository *repo, const git_object *target, const char *to, git_reset_t reset_type, const git_checkout_options *checkout_opts) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_buf log_message = GIT_BUF_INIT; assert(repo && target); if (checkout_opts) opts = *checkout_opts; if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJECT_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } if ((error = git_buf_printf(&log_message, "reset: moving to %s", to)) < 0) return error; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with the new tree */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } /* move HEAD to the new target */ if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, git_object_id(commit), NULL, git_buf_cstr(&log_message))) < 0) goto cleanup; if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_state_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); git_buf_dispose(&log_message); return error; }
int git_reset( git_repository *repo, git_object *target, git_reset_t reset_type) { git_object *commit = NULL; git_index *index = NULL; git_tree *tree = NULL; int error = 0; git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; assert(repo && target); if (git_object_owner(target) != repo) { giterr_set(GITERR_OBJECT, "%s - The given target does not belong to this repository.", ERROR_MSG); return -1; } if (reset_type != GIT_RESET_SOFT && (error = git_repository__ensure_not_bare(repo, reset_type == GIT_RESET_MIXED ? "reset mixed" : "reset hard")) < 0) return error; if ((error = git_object_peel(&commit, target, GIT_OBJ_COMMIT)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_commit_tree(&tree, (git_commit *)commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_SOFT && (git_repository_state(repo) == GIT_REPOSITORY_STATE_MERGE || git_index_has_conflicts(index))) { giterr_set(GITERR_OBJECT, "%s (soft) in the middle of a merge.", ERROR_MSG); error = GIT_EUNMERGED; goto cleanup; } /* move HEAD to the new target */ if ((error = update_head(repo, commit)) < 0) goto cleanup; if (reset_type == GIT_RESET_HARD) { /* overwrite working directory with HEAD */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; if ((error = git_checkout_tree(repo, (git_object *)tree, &opts)) < 0) goto cleanup; } if (reset_type > GIT_RESET_SOFT) { /* reset index to the target content */ if ((error = git_index_read_tree(index, tree)) < 0 || (error = git_index_write(index)) < 0) goto cleanup; if ((error = git_repository_merge_cleanup(repo)) < 0) { giterr_set(GITERR_INDEX, "%s - failed to clean up merge data", ERROR_MSG); goto cleanup; } } cleanup: git_object_free(commit); git_index_free(index); git_tree_free(tree); return error; }
int git_commit_create( git_oid *oid, git_repository *repo, const char *update_ref, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message, const git_tree *tree, int parent_count, const git_commit *parents[]) { git_buf commit = GIT_BUF_INIT; int error, i; if (git_object_owner((const git_object *)tree) != repo) return git__throw(GIT_EINVALIDARGS, "The given tree does not belong to this repository"); git_oid__writebuf(&commit, "tree ", git_object_id((const git_object *)tree)); for (i = 0; i < parent_count; ++i) { if (git_object_owner((const git_object *)parents[i]) != repo) { error = git__throw(GIT_EINVALIDARGS, "The given parent does not belong to this repository"); goto cleanup; } git_oid__writebuf(&commit, "parent ", git_object_id((const git_object *)parents[i])); } git_signature__writebuf(&commit, "author ", author); git_signature__writebuf(&commit, "committer ", committer); if (message_encoding != NULL) git_buf_printf(&commit, "encoding %s\n", message_encoding); git_buf_putc(&commit, '\n'); git_buf_puts(&commit, message); if (git_buf_oom(&commit)) { error = git__throw(GIT_ENOMEM, "Not enough memory to build the commit data"); goto cleanup; } error = git_odb_write(oid, git_repository_database(repo), commit.ptr, commit.size, GIT_OBJ_COMMIT); git_buf_free(&commit); if (error == GIT_SUCCESS && update_ref != NULL) { git_reference *head; error = git_reference_lookup(&head, repo, update_ref); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to create commit"); error = git_reference_resolve(&head, head); if (error < GIT_SUCCESS) { if (error != GIT_ENOTFOUND) return git__rethrow(error, "Failed to create commit"); /* * The target of the reference was not found. This can happen * just after a repository has been initialized (the master * branch doesn't exist yet, as it doesn't have anything to * point to) or after an orphan checkout, so if the target * branch doesn't exist yet, create it and return. */ return git_reference_create_oid(&head, repo, git_reference_target(head), oid, 1); } error = git_reference_set_oid(head, oid); } if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to create commit"); return GIT_SUCCESS; cleanup: git_buf_free(&commit); return error; }