static void execute_test(void) { git_oid oid, check; git_commit *commit; git_tree *tree; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/branch1")); cl_git_pass(git_commit_lookup(&commit, g_repo, &oid)); cl_git_pass(git_commit_tree(&tree, commit)); opts.checkout_strategy = GIT_CHECKOUT_SAFE; cl_git_pass(git_checkout_tree(g_repo, (git_object *)tree, &opts)); git_tree_free(tree); git_commit_free(commit); /* Verify that the lenna.jpg file was checked out correctly */ cl_git_pass(git_oid_fromstr(&check, "8ab005d890fe53f65eda14b23672f60d9f4ec5a1")); cl_git_pass(git_odb_hashfile(&oid, "binaryunicode/lenna.jpg", GIT_OBJ_BLOB)); cl_assert(git_oid_equal(&oid, &check)); /* Verify that the text file was checked out correctly */ cl_git_pass(git_oid_fromstr(&check, "965b223880dd4249e2c66a0cc0b4cffe1dc40f5a")); cl_git_pass(git_odb_hashfile(&oid, "binaryunicode/utf16_withbom_noeol_crlf.txt", GIT_OBJ_BLOB)); cl_assert(git_oid_equal(&oid, &check)); }
int RemoteProgressCommand::RemoteUpdatetipsCallback(const char* refname, const git_oid* oldOid, const git_oid* newOid, void* data) { auto ptr = (CGitProgressList::Payload*)data; bool nonff = false; if (!git_oid_iszero(oldOid) && !git_oid_iszero(newOid)) { git_oid baseOid = { 0 }; if (!git_merge_base(&baseOid, ptr->repo, newOid, oldOid)) if (!git_oid_equal(oldOid, &baseOid)) nonff = true; } CString change; if (!git_oid_iszero(oldOid) && !git_oid_iszero(newOid)) { if (git_oid_equal(oldOid, newOid)) { change.LoadString(IDS_SAME); } else { size_t ahead = 0, behind = 0; if (!git_graph_ahead_behind(&ahead, &behind, ptr->repo, newOid, oldOid)) { if (ahead > 0 && behind == 0) { change.Format(IDS_FORWARDN, ahead); } else if (ahead == 0 && behind > 0) { change.Format(IDS_REWINDN, behind); } else { git_commit* oldCommit, * newCommit; git_time_t oldTime = 0, newTime = 0; if (!git_commit_lookup(&oldCommit, ptr->repo, oldOid)) oldTime = git_commit_committer(oldCommit)->when.time; if (!git_commit_lookup(&newCommit, ptr->repo, newOid)) newTime = git_commit_committer(newCommit)->when.time; if (oldTime < newTime) change.LoadString(IDS_SUBMODULEDIFF_NEWERTIME); else if (oldTime > newTime) change.LoadString(IDS_SUBMODULEDIFF_OLDERTIME); else change.LoadString(IDS_SUBMODULEDIFF_SAMETIME); } } } } else if (!git_oid_iszero(oldOid)) change.LoadString(IDS_DELETED); else if (!git_oid_iszero(newOid)) change.LoadString(IDS_NEW); ptr->list->AddNotify(new RefUpdateNotificationData(refname, oldOid, newOid, change)); return 0; }
static int try_to_update(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote, enum remote_transport rt) { git_oid base; const git_oid *local_id, *remote_id; if (!git_reference_cmp(local, remote)) return 0; // Dirty modified state in the working tree? We're not going // to update either way if (git_status_foreach(repo, check_clean, NULL)) return report_error("local cached copy is dirty, skipping update"); local_id = git_reference_target(local); remote_id = git_reference_target(remote); if (!local_id || !remote_id) return report_error("Unable to get local or remote SHA1"); if (git_merge_base(&base, repo, local_id, remote_id)) return report_error("Unable to find common commit of local and remote branches"); /* Is the remote strictly newer? Use it */ if (git_oid_equal(&base, local_id)) return reset_to_remote(repo, local, remote_id); /* Is the local repo the more recent one? See if we can update upstream */ if (git_oid_equal(&base, remote_id)) return update_remote(repo, origin, local, remote, rt); /* Merging a bare repository always needs user action */ if (git_repository_is_bare(repo)) return report_error("Local and remote have diverged, merge of bare branch needed"); /* Merging will definitely need the head branch too */ if (git_branch_is_head(local) != 1) return report_error("Local and remote do not match, local branch not HEAD - cannot update"); /* * Some day we migth try a clean merge here. * * But I couldn't find any good examples of this, so for now * you'd need to merge divergent histories manually. But we've * at least verified above that we have a working tree and the * current branch is checked out and clean, so we *could* try * to merge. */ return report_error("Local and remote have diverged, need to merge"); }
void test_repo_hashfile__filtered(void) { git_oid a, b; git_config *config; cl_git_pass(git_repository_config(&config, _repo)); cl_git_pass(git_config_set_bool(config, "core.autocrlf", true)); git_config_free(config); cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n"); /* create some sample content with CRLF in it */ cl_git_mkfile("status/testfile.txt", "content\r\n"); cl_git_mkfile("status/testfile.bin", "other\r\nstuff\r\n"); /* not equal hashes because of filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_cmp(&a, &b)); /* equal hashes because filter is binary */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); /* equal hashes when 'as_file' points to binary filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, "foo.bin")); cl_assert(git_oid_equal(&a, &b)); /* not equal hashes when 'as_file' points to text filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, "foo.txt")); cl_assert(git_oid_cmp(&a, &b)); /* equal hashes when 'as_file' is empty and turns off filtering */ cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_BLOB, "")); cl_assert(git_oid_equal(&a, &b)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJ_BLOB, "")); cl_assert(git_oid_equal(&a, &b)); /* some hash type failures */ cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0)); cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJ_ANY, NULL)); }
static inline int agb_git_tree_entry_equal(const git_tree_entry * tree_a, const git_tree_entry * tree_b ) { if(tree_a==NULL && tree_b==NULL) return 1; if(tree_a==NULL || tree_b==NULL) return 0; const git_oid * oid_a = git_tree_entry_id(tree_a); const git_oid * oid_b = git_tree_entry_id(tree_b); return git_oid_equal(oid_a,oid_b); }
void test_network_remote_defaultbranch__detached_sharing_nonbranch_id(void) { git_oid id, id_cloned; git_reference *ref; git_buf buf = GIT_BUF_INIT; git_repository *cloned_repo; cl_git_pass(git_reference_name_to_id(&id, g_repo_a, "HEAD")); cl_git_pass(git_repository_detach_head(g_repo_a, NULL, NULL)); cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/master")); cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/not-good")); cl_git_pass(git_reference_create(&ref, g_repo_a, "refs/foo/bar", &id, 1, NULL, NULL)); git_reference_free(ref); cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH)); cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, g_remote)); cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./local-detached", NULL)); cl_assert(git_repository_head_detached(cloned_repo)); cl_git_pass(git_reference_name_to_id(&id_cloned, g_repo_a, "HEAD")); cl_assert(git_oid_equal(&id, &id_cloned)); git_repository_free(cloned_repo); }
PyObject * Object_richcompare(PyObject *o1, PyObject *o2, int op) { PyObject *res; Object *obj1; Object *obj2; if (!PyObject_TypeCheck(o2, &ObjectType)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } switch (op) { case Py_NE: obj1 = (Object *) o1; obj2 = (Object *) o2; if (git_oid_equal(git_object_id(obj1->obj), git_object_id(obj2->obj))) { res = Py_False; } else { res = Py_True; } break; case Py_EQ: obj1 = (Object *) o1; obj2 = (Object *) o2; if (git_oid_equal(git_object_id(obj1->obj), git_object_id(obj2->obj))) { res = Py_True; } else { res = Py_False; } break; case Py_LT: case Py_LE: case Py_GT: case Py_GE: Py_INCREF(Py_NotImplemented); return Py_NotImplemented; default: PyErr_Format(PyExc_RuntimeError, "Unexpected '%d' op", op); return NULL; } Py_INCREF(res); return res; }
void test_status_worktree__conflict_has_no_oid(void) { git_repository *repo = cl_git_sandbox_init("status"); git_index *index; git_index_entry entry = {{0}}; git_status_list *statuslist; const git_status_entry *status; git_oid zero_id = {{0}}; entry.mode = 0100644; entry.path = "modified_file"; git_oid_fromstr(&entry.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); cl_git_pass(git_repository_index(&index, repo)); cl_git_pass(git_index_conflict_add(index, &entry, &entry, &entry)); git_status_list_new(&statuslist, repo, NULL); cl_assert_equal_i(16, git_status_list_entrycount(statuslist)); status = git_status_byindex(statuslist, 2); cl_assert_equal_i(GIT_STATUS_CONFLICTED, status->status); cl_assert_equal_s("modified_file", status->head_to_index->old_file.path); cl_assert(!git_oid_equal(&zero_id, &status->head_to_index->old_file.id)); cl_assert(0 != status->head_to_index->old_file.mode); cl_assert_equal_s("modified_file", status->head_to_index->new_file.path); cl_assert_equal_oid(&zero_id, &status->head_to_index->new_file.id); cl_assert_equal_i(0, status->head_to_index->new_file.mode); cl_assert_equal_i(0, status->head_to_index->new_file.size); cl_assert_equal_s("modified_file", status->index_to_workdir->old_file.path); cl_assert_equal_oid(&zero_id, &status->index_to_workdir->old_file.id); cl_assert_equal_i(0, status->index_to_workdir->old_file.mode); cl_assert_equal_i(0, status->index_to_workdir->old_file.size); cl_assert_equal_s("modified_file", status->index_to_workdir->new_file.path); cl_assert( !git_oid_equal(&zero_id, &status->index_to_workdir->new_file.id) || !(status->index_to_workdir->new_file.flags & GIT_DIFF_FLAG_VALID_ID)); cl_assert(0 != status->index_to_workdir->new_file.mode); cl_assert(0 != status->index_to_workdir->new_file.size); git_index_free(index); git_status_list_free(statuslist); }
static int try_to_update(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote, enum remote_transport rt) { git_oid base; const git_oid *local_id, *remote_id; if (!git_reference_cmp(local, remote)) return 0; // Dirty modified state in the working tree? We're not going // to update either way if (git_status_foreach(repo, check_clean, NULL)) return report_error("local cached copy is dirty, skipping update"); local_id = git_reference_target(local); remote_id = git_reference_target(remote); if (!local_id || !remote_id) return report_error("Unable to get local or remote SHA1"); if (git_merge_base(&base, repo, local_id, remote_id)) return report_error("Unable to find common commit of local and remote branches"); /* Is the remote strictly newer? Use it */ if (git_oid_equal(&base, local_id)) return reset_to_remote(repo, local, remote_id); /* Is the local repo the more recent one? See if we can update upstream */ if (git_oid_equal(&base, remote_id)) return update_remote(repo, origin, local, remote, rt); /* Merging a bare repository always needs user action */ if (git_repository_is_bare(repo)) return report_error("Local and remote have diverged, merge of bare branch needed"); /* Merging will definitely need the head branch too */ if (git_branch_is_head(local) != 1) return report_error("Local and remote do not match, local branch not HEAD - cannot update"); /* Ok, let's try to merge these */ return try_to_git_merge(repo, local, remote, &base, local_id, remote_id); }
void test_repo_hashfile__simple(void) { git_oid a, b; git_buf full = GIT_BUF_INIT; /* hash with repo relative path */ cl_git_pass(git_odb_hashfile(&a, "status/current_file", GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, "current_file", GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); cl_git_pass(git_buf_joinpath(&full, git_repository_workdir(_repo), "current_file")); /* hash with full path */ cl_git_pass(git_odb_hashfile(&a, full.ptr, GIT_OBJ_BLOB)); cl_git_pass(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJ_BLOB, NULL)); cl_assert(git_oid_equal(&a, &b)); /* hash with invalid type */ cl_git_fail(git_odb_hashfile(&a, full.ptr, GIT_OBJ_ANY)); cl_git_fail(git_repository_hashfile(&b, _repo, full.ptr, GIT_OBJ_OFS_DELTA, NULL)); git_buf_free(&full); }
void test_odb_backend_simple__exists_prefix_succeeds(void) { const fake_object objs[] = { { "1234567890111111111111111111111111111111", "first content" }, { "1234567890222222222222222222222222222222", "second content" }, { NULL, NULL } }; git_oid found; setup_backend(objs); cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 12)); cl_assert(git_oid_equal(&found, &_oid)); }
void test_odb_backend_simple__exists_with_highly_ambiguous_prefix(void) { const fake_object objs[] = { { "1234567890111111111111111111111111111111", "first content" }, { "1234567890111111111111111111111111111112", "second content" }, { NULL, NULL } }; git_oid found; setup_backend(objs); cl_git_pass(git_oid_fromstr(&_oid, objs[0].oid)); cl_git_pass(git_libgit2_opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, 0)); cl_git_fail_with(GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &_oid, 39)); cl_git_pass(git_odb_exists_prefix(&found, _odb, &_oid, 40)); cl_assert(git_oid_equal(&found, &_oid)); }
static bool roundtrip_with_read_index(const char *tree_idstr) { git_oid tree_id, new_tree_id; git_tree *tree; git_index *tree_index; cl_git_pass(git_oid_fromstr(&tree_id, tree_idstr)); cl_git_pass(git_tree_lookup(&tree, _repo, &tree_id)); cl_git_pass(git_index_new(&tree_index)); cl_git_pass(git_index_read_tree(tree_index, tree)); cl_git_pass(git_index_read_index(_index, tree_index)); cl_git_pass(git_index_write_tree(&new_tree_id, _index)); git_tree_free(tree); git_index_free(tree_index); return git_oid_equal(&tree_id, &new_tree_id); }
static int try_to_update(git_repository *repo, git_remote *origin, git_reference *local, git_reference *remote, const char *remote_url, const char *branch, enum remote_transport rt) { git_oid base; const git_oid *local_id, *remote_id; int ret = 0; if (verbose) fprintf(stderr, "git storage: try to update\n"); if (!git_reference_cmp(local, remote)) return 0; // Dirty modified state in the working tree? We're not going // to update either way if (git_status_foreach(repo, check_clean, NULL)) { if (is_subsurface_cloud) goto cloud_data_error; else return report_error("local cached copy is dirty, skipping update"); } local_id = git_reference_target(local); remote_id = git_reference_target(remote); if (!local_id || !remote_id) { if (is_subsurface_cloud) goto cloud_data_error; else return report_error("Unable to get local or remote SHA1"); } if (git_merge_base(&base, repo, local_id, remote_id)) { // TODO: // if they have no merge base, they actually are different repos // so instead merge this as merging a commit into a repo - git_merge() appears to do that // but needs testing and cleanup afterwards // if (is_subsurface_cloud) goto cloud_data_error; else return report_error("Unable to find common commit of local and remote branches"); } /* Is the remote strictly newer? Use it */ if (git_oid_equal(&base, local_id)) { git_storage_update_progress(translate("gettextFromC", "Update local storage to match cloud storage")); return reset_to_remote(repo, local, remote_id); } /* Is the local repo the more recent one? See if we can update upstream */ if (git_oid_equal(&base, remote_id)) { if (verbose) fprintf(stderr, "local is newer than remote, update remote\n"); git_storage_update_progress(translate("gettextFromC", "Push local changes to cloud storage")); return update_remote(repo, origin, local, remote, rt); } /* Merging a bare repository always needs user action */ if (git_repository_is_bare(repo)) { if (is_subsurface_cloud) goto cloud_data_error; else return report_error("Local and remote have diverged, merge of bare branch needed"); } /* Merging will definitely need the head branch too */ if (git_branch_is_head(local) != 1) { if (is_subsurface_cloud) goto cloud_data_error; else return report_error("Local and remote do not match, local branch not HEAD - cannot update"); } /* Ok, let's try to merge these */ git_storage_update_progress(translate("gettextFromC", "Try to merge local changes into cloud storage")); ret = try_to_git_merge(repo, &local, remote, &base, local_id, remote_id); if (ret == 0) return update_remote(repo, origin, local, remote, rt); else return ret; cloud_data_error: // since we are working with Subsurface cloud storage we want to make the user interaction // as painless as possible. So if something went wrong with the local cache, tell the user // about it an move it away return cleanup_local_cache(remote_url, branch); }
static int workdir_reader_read( git_buf *out, git_oid *out_id, git_filemode_t *out_filemode, git_reader *_reader, const char *filename) { workdir_reader *reader = (workdir_reader *)_reader; git_buf path = GIT_BUF_INIT; struct stat st; git_filemode_t filemode; git_filter_list *filters = NULL; const git_index_entry *idx_entry; git_oid id; int error; if ((error = git_buf_joinpath(&path, git_repository_workdir(reader->repo), filename)) < 0) goto done; if ((error = p_lstat(path.ptr, &st)) < 0) { if (error == -1 && errno == ENOENT) error = GIT_ENOTFOUND; giterr_set(GITERR_OS, "could not stat '%s'", path.ptr); goto done; } filemode = git_futils_canonical_mode(st.st_mode); /* * Patch application - for example - uses the filtered version of * the working directory data to match git. So we will run the * workdir -> ODB filter on the contents in this workdir reader. */ if ((error = git_filter_list_load(&filters, reader->repo, NULL, filename, GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT)) < 0) goto done; if ((error = git_filter_list_apply_to_file(out, filters, reader->repo, path.ptr)) < 0) goto done; if (out_id || reader->index) { if ((error = git_odb_hash(&id, out->ptr, out->size, GIT_OBJ_BLOB)) < 0) goto done; } if (reader->index) { if (!(idx_entry = git_index_get_bypath(reader->index, filename, 0)) || filemode != idx_entry->mode || !git_oid_equal(&id, &idx_entry->id)) { error = GIT_READER_MISMATCH; goto done; } } if (out_id) git_oid_cpy(out_id, &id); if (out_filemode) *out_filemode = filemode; done: git_filter_list_free(filters); git_buf_dispose(&path); return error; }
void test_odb_mixed__dup_oid_prefix_0(void) { char hex[10]; git_oid oid, found; git_odb_object *obj; /* ambiguous in the same pack file */ strncpy(hex, "dea509d0", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "dea509d09", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert(git_oid_equal(&found, git_odb_object_id(obj))); git_odb_object_free(obj); strncpy(hex, "dea509d0b", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); /* ambiguous in different pack files */ strncpy(hex, "81b5bff5", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "81b5bff5b", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert(git_oid_equal(&found, git_odb_object_id(obj))); git_odb_object_free(obj); strncpy(hex, "81b5bff5f", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); /* ambiguous in pack file and loose */ strncpy(hex, "0ddeaded", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_assert_equal_i( GIT_EAMBIGUOUS, git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); strncpy(hex, "0ddeaded9", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); cl_git_pass(git_odb_exists_prefix(&found, _odb, &oid, strlen(hex))); cl_assert(git_oid_equal(&found, git_odb_object_id(obj))); git_odb_object_free(obj); strncpy(hex, "0ddeadede", sizeof(hex)); cl_git_pass(git_oid_fromstrn(&oid, hex, strlen(hex))); cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, strlen(hex))); git_odb_object_free(obj); }
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 rebase_commit__create( git_commit **out, git_rebase *rebase, git_index *index, git_commit *parent_commit, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_rebase_operation *operation; git_commit *current_commit = NULL, *commit = NULL; git_tree *parent_tree = NULL, *tree = NULL; git_oid tree_id, commit_id; int error; operation = git_array_get(rebase->operations, rebase->current); if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "conflicts have not been resolved"); error = GIT_EUNMERGED; goto done; } if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_commit_tree(&parent_tree, parent_commit)) < 0 || (error = git_index_write_tree_to(&tree_id, index, rebase->repo)) < 0 || (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) goto done; if (git_oid_equal(&tree_id, git_tree_id(parent_tree))) { giterr_set(GITERR_REBASE, "this patch has already been applied"); error = GIT_EAPPLIED; goto done; } if (!author) author = git_commit_author(current_commit); if (!message) { message_encoding = git_commit_message_encoding(current_commit); message = git_commit_message(current_commit); } if ((error = git_commit_create(&commit_id, rebase->repo, NULL, author, committer, message_encoding, message, tree, 1, (const git_commit **)&parent_commit)) < 0 || (error = git_commit_lookup(&commit, rebase->repo, &commit_id)) < 0) goto done; *out = commit; done: if (error < 0) git_commit_free(commit); git_commit_free(current_commit); git_tree_free(parent_tree); git_tree_free(tree); return error; }