static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree, git_commit_parent_callback parent_cb, void *parent_payload, const git_oid *current_id, bool validate) { size_t i; int error; git_oid *parent_cpy; const git_oid *parent; if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE)) return -1; i = 0; while ((parent = parent_cb(i, parent_payload)) != NULL) { if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) { error = -1; goto on_error; } parent_cpy = git_array_alloc(*parents); GITERR_CHECK_ALLOC(parent_cpy); git_oid_cpy(parent_cpy, parent); i++; } if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) { giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent"); error = GIT_EMODIFIED; goto on_error; } return 0; on_error: git_array_clear(*parents); return error; }
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) { git_reference *ref = NULL; int error = 0, matched_parent = 0; const git_oid *current_id = NULL; git_buf commit = GIT_BUF_INIT; size_t i = 0; git_odb *odb; const git_oid *parent; assert(id && repo && tree && parent_cb); if (validate && !git_object__is_valid(repo, tree, GIT_OBJ_TREE)) return -1; 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); git_oid__writebuf(&commit, "tree ", tree); while ((parent = parent_cb(i, parent_payload)) != NULL) { if (validate && !git_object__is_valid(repo, parent, GIT_OBJ_COMMIT)) { error = -1; goto on_error; } git_oid__writebuf(&commit, "parent ", parent); if (i == 0 && current_id && git_oid_equal(current_id, parent)) matched_parent = 1; i++; } if (ref && !matched_parent) { git_reference_free(ref); git_buf_free(&commit); giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent"); return GIT_EMODIFIED; } 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(id, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT) < 0) goto on_error; git_buf_free(&commit); if (update_ref != NULL) { error = git_reference__update_for_commit( repo, ref, update_ref, id, "commit"); git_reference_free(ref); return error; } return 0; on_error: git_buf_free(&commit); return -1; }
static int reference__create( git_reference **ref_out, git_repository *repo, const char *name, const git_oid *oid, const char *symbolic, int force, const git_signature *signature, const char *log_message, const git_oid *old_id, const char *old_target) { git_refname_t normalized; git_refdb *refdb; git_reference *ref = NULL; int error = 0; assert(repo && name); assert(symbolic || signature); if (ref_out) *ref_out = NULL; error = reference_normalize_for_repo(normalized, repo, name, true); if (error < 0) return error; error = git_repository_refdb__weakptr(&refdb, repo); if (error < 0) return error; if (oid != NULL) { assert(symbolic == NULL); if (!git_object__is_valid(repo, oid, GIT_OBJ_ANY)) { giterr_set(GITERR_REFERENCE, "target OID for the reference doesn't exist on the repository"); return -1; } ref = git_reference__alloc(normalized, oid, NULL); } else { git_refname_t normalized_target; error = reference_normalize_for_repo(normalized_target, repo, symbolic, git_reference__enable_symbolic_ref_target_validation); if (error < 0) return error; ref = git_reference__alloc_symbolic(normalized, normalized_target); } GITERR_CHECK_ALLOC(ref); if ((error = git_refdb_write(refdb, ref, force, signature, log_message, old_id, old_target)) < 0) { git_reference_free(ref); return error; } if (ref_out == NULL) git_reference_free(ref); else *ref_out = ref; return 0; }