static void *run_index_diffs_with_modifier(void *arg) { int thread = *(int *)arg; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; git_index *idx = NULL; git_repository *repo; cl_git_pass(git_repository_open(&repo, git_repository_path(_repo))); cl_git_pass(git_repository_index(&idx, repo)); /* have first thread altering the index as we go */ if (thread == 0) { int i; for (i = 0; i < 300; ++i) { switch (i & 0x03) { case 0: (void)git_index_add_bypath(idx, "new_file"); break; case 1: (void)git_index_remove_bypath(idx, "modified_file"); break; case 2: (void)git_index_remove_bypath(idx, "new_file"); break; case 3: (void)git_index_add_bypath(idx, "modified_file"); break; } git_thread_yield(); } goto done; } /* only use explicit index in this test to prevent reloading */ switch (thread & 0x03) { case 0: /* diff index to workdir */; cl_git_pass(git_diff_index_to_workdir(&diff, repo, idx, &opts)); break; case 1: /* diff tree 'a' to index */; cl_git_pass(git_diff_tree_to_index(&diff, repo, _a, idx, &opts)); break; case 2: /* diff tree 'b' to index */; cl_git_pass(git_diff_tree_to_index(&diff, repo, _b, idx, &opts)); break; case 3: /* diff index to workdir reversed */; opts.flags |= GIT_DIFF_REVERSE; cl_git_pass(git_diff_index_to_workdir(&diff, repo, idx, &opts)); break; } /* results will be unpredictable with index modifier thread running */ git_diff_free(diff); done: git_index_free(idx); git_repository_free(repo); git_error_clear(); return arg; }
static VALUE rb_git_diff_tree_to_index(VALUE self, VALUE rb_other, VALUE rb_options) { git_index *index; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_repository *repo; git_diff *diff = NULL; VALUE owner; int error; git_tree *other_tree; rugged_parse_diff_options(&opts, rb_options); Data_Get_Struct(self, git_index, index); owner = rugged_owner(self); Data_Get_Struct(owner, git_repository, repo); // Need to flip the reverse option, so that the index is by default // the "old file" side of the diff. opts.flags ^= GIT_DIFF_REVERSE; Data_Get_Struct(rb_other, git_tree, other_tree); error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts); xfree(opts.pathspec.strings); rugged_exception_check(error); return rugged_diff_new(rb_cRuggedDiff, owner, diff); }
void test_diff_index__1(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; diff_expects exp; cl_assert(a); cl_assert(b); opts.context_lines = 1; opts.interhunk_lines = 1; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_assert_equal_i(1, git_diff_foreach( diff, diff_stop_after_2_files, NULL, NULL, NULL, &exp) ); cl_assert_equal_i(2, exp.files); git_diff_free(diff); diff = NULL; git_tree_free(a); git_tree_free(b); }
void test_diff_index__not_in_head_conflicted(void) { const char *a_commit = "26a125ee1bf"; /* the current HEAD */ git_index_entry theirs = {{0}}; git_index *index; git_diff *diff; const git_diff_delta *delta; git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_read_tree(index, a)); theirs.path = "file_not_in_head"; theirs.mode = GIT_FILEMODE_BLOB; git_oid_fromstr(&theirs.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); cl_git_pass(git_index_conflict_add(index, NULL, NULL, &theirs)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, index, NULL)); cl_assert_equal_i(git_diff_num_deltas(diff), 1); delta = git_diff_get_delta(diff, 0); cl_assert_equal_i(delta->status, GIT_DELTA_CONFLICTED); git_diff_free(diff); git_index_free(index); git_tree_free(a); }
Diff diff_to_index(Repository const & repo, Tree & t, git_diff_options const & opts) { git_diff * diff; auto op_res = git_diff_tree_to_index(&diff, repo.ptr(), t.ptr(), nullptr, &opts); assert(op_res == 0); return Diff(diff); }
/* * call-seq: * index.diff([options]) -> diff * index.diff(diffable[, options]) -> diff * * The first form returns a diff between the index and the current working * directory. * * The second form returns a diff between the index and the given diffable object. * +diffable+ can either be a +Rugged::Commit+ or a +Rugged::Tree+. * * The index will be used as the "old file" side of the diff, while the working * directory or the +diffable+ will be used for the "new file" side. * * The following options can be passed in the +options+ Hash: * * :paths :: * An array of paths / fnmatch patterns to constrain the diff to a specific * set of files. Also see +:disable_pathspec_match+. * * :max_size :: * An integer specifying the maximum byte size of a file before a it will * be treated as binary. The default value is 512MB. * * :context_lines :: * The number of unchanged lines that define the boundary of a hunk (and * to display before and after the actual changes). The default is 3. * * :interhunk_lines :: * The maximum number of unchanged lines between hunk boundaries before the hunks * will be merged into a one. The default is 0. * * :reverse :: * If true, the sides of the diff will be reversed. * * :force_text :: * If true, all files will be treated as text, disabling binary attributes & detection. * * :ignore_whitespace :: * If true, all whitespace will be ignored. * * :ignore_whitespace_change :: * If true, changes in amount of whitespace will be ignored. * * :ignore_whitespace_eol :: * If true, whitespace at end of line will be ignored. * * :ignore_submodules :: * if true, submodules will be excluded from the diff completely. * * :patience :: * If true, the "patience diff" algorithm will be used (currenlty unimplemented). * * :include_ignored :: * If true, ignored files will be included in the diff. * * :include_untracked :: * If true, untracked files will be included in the diff. * * :include_unmodified :: * If true, unmodified files will be included in the diff. * * :recurse_untracked_dirs :: * Even if +:include_untracked+ is true, untracked directories will only be * marked with a single entry in the diff. If this flag is set to true, * all files under ignored directories will be included in the diff, too. * * :disable_pathspec_match :: * If true, the given +:paths+ will be applied as exact matches, instead of * as fnmatch patterns. * * :deltas_are_icase :: * If true, filename comparisons will be made with case-insensitivity. * * :include_untracked_content :: * if true, untracked content will be contained in the the diff patch text. * * :skip_binary_check :: * If true, diff deltas will be generated without spending time on binary * detection. This is useful to improve performance in cases where the actual * file content difference is not needed. * * :include_typechange :: * If true, type changes for files will not be interpreted as deletion of * the "old file" and addition of the "new file", but will generate * typechange records. * * :include_typechange_trees :: * Even if +:include_typechange+ is true, blob -> tree changes will still * usually be handled as a deletion of the blob. If this flag is set to true, * blob -> tree changes will be marked as typechanges. * * :ignore_filemode :: * If true, file mode changes will be ignored. * * :recurse_ignored_dirs :: * Even if +:include_ignored+ is true, ignored directories will only be * marked with a single entry in the diff. If this flag is set to true, * all files under ignored directories will be included in the diff, too. */ static VALUE rb_git_index_diff(int argc, VALUE *argv, VALUE self) { git_index *index; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_repository *repo; git_diff *diff = NULL; VALUE owner, rb_other, rb_options; int error; rb_scan_args(argc, argv, "01:", &rb_other, &rb_options); rugged_parse_diff_options(&opts, rb_options); Data_Get_Struct(self, git_index, index); owner = rugged_owner(self); Data_Get_Struct(owner, git_repository, repo); if (NIL_P(rb_other)) { error = git_diff_index_to_workdir(&diff, repo, index, &opts); } else { // Need to flip the reverse option, so that the index is by default // the "old file" side of the diff. opts.flags ^= GIT_DIFF_REVERSE; if (rb_obj_is_kind_of(rb_other, rb_cRuggedCommit)) { git_tree *other_tree; git_commit *commit; Data_Get_Struct(rb_other, git_commit, commit); error = git_commit_tree(&other_tree, commit); if (!error) error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts); } else if (rb_obj_is_kind_of(rb_other, rb_cRuggedTree)) { git_tree *other_tree; Data_Get_Struct(rb_other, git_tree, other_tree); error = git_diff_tree_to_index(&diff, repo, other_tree, index, &opts); } else { xfree(opts.pathspec.strings); rb_raise(rb_eTypeError, "A Rugged::Commit or Rugged::Tree instance is required"); } } xfree(opts.pathspec.strings); rugged_exception_check(error); return rugged_diff_new(rb_cRuggedDiff, owner, diff); }
void test_diff_index__checks_options_version(void) { const char *a_commit = "26a125ee1bf"; git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; const git_error *err; opts.version = 0; cl_git_fail(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); cl_assert_equal_p(diff, NULL); giterr_clear(); opts.version = 1024; cl_git_fail(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); cl_assert_equal_p(diff, NULL); git_tree_free(a); }
PyObject * Tree_diff(Tree *self, PyObject *args, PyObject *kwds) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff; git_tree* tree = NULL; git_index* index; git_repository *repo; int err, empty_tree = 0; char *keywords[] = {"obj", "flags", "empty_tree", NULL}; Diff *py_diff; PyObject *py_obj = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oii", keywords, &py_obj, &opts.flags, &empty_tree)) return NULL; repo = git_tree_owner(self->tree); if (py_obj == NULL) { if (empty_tree > 0) err = git_diff_tree_to_tree(&diff, repo, self->tree, NULL, &opts); else err = git_diff_tree_to_workdir(&diff, repo, self->tree, &opts); } else if (PyObject_TypeCheck(py_obj, &TreeType)) { tree = ((Tree *)py_obj)->tree; err = git_diff_tree_to_tree(&diff, repo, self->tree, tree, &opts); } else if (PyObject_TypeCheck(py_obj, &IndexType)) { index = ((Index *)py_obj)->index; err = git_diff_tree_to_index(&diff, repo, self->tree, index, &opts); } else { PyErr_SetObject(PyExc_TypeError, py_obj); return NULL; } if (err < 0) return Error_set(err); py_diff = PyObject_New(Diff, &DiffType); if (py_diff) { Py_INCREF(self->repo); py_diff->repo = self->repo; py_diff->list = diff; } return (PyObject*)py_diff; }
PyObject * Tree_diff(Tree *self, PyObject *args) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_list *diff; int err; Diff *py_diff; PyObject *py_obj = NULL; if (!PyArg_ParseTuple(args, "|Oi", &py_obj, &opts.flags)) return NULL; if (py_obj == NULL) { err = git_diff_tree_to_workdir( &diff, self->repo->repo, self->tree, &opts); } else if (PyObject_TypeCheck(py_obj, &TreeType)) { err = git_diff_tree_to_tree( &diff, self->repo->repo, self->tree, ((Tree *)py_obj)->tree, &opts); } else if (PyObject_TypeCheck(py_obj, &IndexType)) { err = git_diff_tree_to_index( &diff, self->repo->repo, self->tree, ((Index *)py_obj)->index, &opts); } else { PyErr_SetObject(PyExc_TypeError, py_obj); return NULL; } if (err < 0) return Error_set(err); py_diff = PyObject_New(Diff, &DiffType); if (py_diff) { Py_INCREF(self->repo); py_diff->repo = self->repo; py_diff->list = diff; } return (PyObject*)py_diff; }
PyObject * Tree_diff_to_index(Tree *self, PyObject *args, PyObject *kwds) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff; git_index *index; char *buffer; Py_ssize_t length; Repository *py_repo; PyObject *py_idx, *py_idx_ptr; int err; if (!PyArg_ParseTuple(args, "O|IHH", &py_idx, &opts.flags, &opts.context_lines, &opts.interhunk_lines)) return NULL; /* * This is a hack to check whether we're passed an index, as I * haven't found a good way to grab a type object for * pygit2.index.Index. */ if (!PyObject_GetAttrString(py_idx, "_index")) { PyErr_SetString(PyExc_TypeError, "argument must be an Index"); return NULL; } py_idx_ptr = PyObject_GetAttrString(py_idx, "_pointer"); if (!py_idx_ptr) return NULL; /* Here we need to do the opposite conversion from the _pointer getters */ if (PyBytes_AsStringAndSize(py_idx_ptr, &buffer, &length)) return NULL; if (length != sizeof(git_index *)) { PyErr_SetString(PyExc_TypeError, "passed value is not a pointer"); return NULL; } /* the "buffer" contains the pointer */ index = *((git_index **) buffer); py_repo = self->repo; err = git_diff_tree_to_index(&diff, py_repo->repo, self->tree, index, &opts); if (err < 0) return Error_set(err); return wrap_diff(diff, py_repo); }
static int rebase_ensure_not_dirty( git_repository *repo, bool check_index, bool check_workdir, int fail_with) { git_tree *head = NULL; git_index *index = NULL; git_diff *diff = NULL; int error = 0; if (check_index) { if ((error = git_repository_head_tree(&head, repo)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) > 0) { git_error_set(GIT_ERROR_REBASE, "uncommitted changes exist in index"); error = fail_with; goto done; } git_diff_free(diff); diff = NULL; } if (check_workdir) { git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT; diff_opts.ignore_submodules = GIT_SUBMODULE_IGNORE_UNTRACKED; if ((error = git_diff_index_to_workdir(&diff, repo, index, &diff_opts)) < 0) goto done; if (git_diff_num_deltas(diff) > 0) { git_error_set(GIT_ERROR_REBASE, "unstaged changes exist in workdir"); error = fail_with; goto done; } } done: git_diff_free(diff); git_index_free(index); git_tree_free(head); return error; }
static int build_workdir_tree( git_tree **tree_out, git_index *index, git_commit *b_commit) { git_repository *repo = git_index_owner(index); git_tree *b_tree = NULL; git_diff_list *diff = NULL, *diff2 = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; struct cb_data data = {0}; int error; if ((error = git_commit_tree(&b_tree, b_commit)) < 0) goto cleanup; if ((error = git_diff_tree_to_index(&diff, repo, b_tree, NULL, &opts)) < 0) goto cleanup; if ((error = git_diff_index_to_workdir(&diff2, repo, NULL, &opts)) < 0) goto cleanup; if ((error = git_diff_merge(diff, diff2)) < 0) goto cleanup; data.index = index; data.include_changed = true; if ((error = git_diff_foreach( diff, update_index_cb, NULL, NULL, &data)) < 0) { if (error == GIT_EUSER) error = data.error; goto cleanup; } if ((error = build_tree_from_index(tree_out, index)) < 0) goto cleanup; cleanup: git_diff_list_free(diff); git_diff_list_free(diff2); git_tree_free(b_tree); return error; }
static int rebase_ensure_not_dirty( git_repository *repo, bool check_index, bool check_workdir, int fail_with) { git_tree *head = NULL; git_index *index = NULL; git_diff *diff = NULL; int error = 0; if (check_index) { if ((error = git_repository_head_tree(&head, repo)) < 0 || (error = git_repository_index(&index, repo)) < 0 || (error = git_diff_tree_to_index(&diff, repo, head, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) > 0) { giterr_set(GITERR_REBASE, "Uncommitted changes exist in index"); error = fail_with; goto done; } git_diff_free(diff); diff = NULL; } if (check_workdir) { if ((error = git_diff_index_to_workdir(&diff, repo, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) > 0) { giterr_set(GITERR_REBASE, "Unstaged changes exist in workdir"); error = fail_with; goto done; } } done: git_diff_free(diff); git_index_free(index); git_tree_free(head); return error; }
StagingDirDiff::StagingDirDiff(Tree *headCommitTree) { // get the diff const git_diff_options options = GIT_DIFF_OPTIONS_INIT; Repository *repo = headCommitTree->getRepository(); try { gitTest(git_diff_tree_to_index(&differences, repo->getInternalRepo(), headCommitTree->internalTree() , nullptr, &options)); } catch(GitException e) { stagingTreeDiffException(e); } processDifferences(); }
int luagi_diff_tree_to_index( lua_State *L ) { git_repository **repo = checkrepo( L, 1 ); git_tree **tree = checktree_at( L, 2 ); git_index **index = checkindex_at( L, 3 ); git_diff_options opts; luagi_diff_init_options( L, 4, &opts ); git_diff **diff = (git_diff **) lua_newuserdata( L, sizeof( git_diff *) ); if( git_diff_tree_to_index( diff, *repo, *tree, *index, &opts ) ) { const git_error *err = giterr_last(); lua_pushnil( L ); lua_pushstring( L, err->message ); return 2; } ltk_setmetatable( L, LUAGI_DIFF_FUNCS ); return 1; }
PyObject * Index_diff_to_tree(Index *self, PyObject *args) { Repository *py_repo; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff; int err; Tree *py_tree = NULL; if (!PyArg_ParseTuple(args, "O!|IHH", &TreeType, &py_tree, &opts.flags, &opts.context_lines, &opts.interhunk_lines)) return NULL; py_repo = py_tree->repo; err = git_diff_tree_to_index(&diff, py_repo->repo, py_tree->tree, self->index, &opts); if (err < 0) return Error_set(err); return wrap_diff(diff, py_repo); }
PyObject * Tree_diff_to_index(Tree *self, PyObject *args, PyObject *kwds) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff; Repository *py_repo; int err; Index *py_idx = NULL; if (!PyArg_ParseTuple(args, "O!|IHH", &IndexType, &py_idx, &opts.flags, &opts.context_lines, &opts.interhunk_lines)) return NULL; py_repo = self->repo; err = git_diff_tree_to_index(&diff, py_repo->repo, self->tree, py_idx->index, &opts); if (err < 0) return Error_set(err); return wrap_diff(diff, py_repo); }
void test_diff_submodules__submod2_head_to_index(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_tree *head; git_diff_list *diff = NULL; static const char *expected[] = { "<SKIP>", /* .gitmodules */ "diff --git a/sm_added_and_uncommited b/sm_added_and_uncommited\nnew file mode 160000\nindex 0000000..4800958\n--- /dev/null\n+++ b/sm_added_and_uncommited\n@@ -0,0 +1 @@\n+Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n", /* sm_added_and_uncommited */ "<END>" }; setup_submodules2(); cl_git_pass(git_repository_head_tree(&head, g_repo)); opts.flags = GIT_DIFF_INCLUDE_UNTRACKED; cl_git_pass(git_diff_tree_to_index(&diff, g_repo, head, NULL, &opts)); check_diff_patches(diff, expected); git_diff_list_free(diff); git_tree_free(head); }
static void do_conflicted_diff(diff_expects *exp, unsigned long flags) { const char *a_commit = "26a125ee1bf"; /* the current HEAD */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_index_entry ancestor = {{0}}, ours = {{0}}, theirs = {{0}}; git_diff *diff = NULL; git_index *index; cl_assert(a); opts.context_lines = 1; opts.interhunk_lines = 1; opts.flags |= flags; memset(exp, 0, sizeof(diff_expects)); cl_git_pass(git_repository_index(&index, g_repo)); ancestor.path = ours.path = theirs.path = "staged_changes"; ancestor.mode = ours.mode = theirs.mode = GIT_FILEMODE_BLOB; git_oid_fromstr(&ancestor.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); git_oid_fromstr(&ours.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); git_oid_fromstr(&theirs.id, "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); cl_git_pass(git_index_conflict_add(index, &ancestor, &ours, &theirs)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, index, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, exp)); git_diff_free(diff); git_tree_free(a); git_index_free(index); }
void QGit::commitDiffContent(QString first, QString second, QList<QString> files) { git_commit *first_commit = nullptr, *second_commit = nullptr; git_object *first_obj = nullptr, *second_obj = nullptr; git_tree *first_tree = nullptr, *second_tree = nullptr; const git_diff_delta *delta = nullptr; git_repository *repo = nullptr; git_patch *patch = nullptr; QList<QGitDiffFile> items; git_diff *diff = nullptr; QGitError error; int res = 0; try { res = git_repository_open(&repo, m_path.absolutePath().toUtf8().constData()); if (res) { throw QGitError("git_repository_open", res); } if (!first.isEmpty()) { res = git_revparse_single(&first_obj, repo, first.toLatin1()); if (res) { throw QGitError("git_revparse_single(first)", res); } res = git_commit_lookup(&first_commit, repo, git_object_id(first_obj)); if (res) { throw QGitError("git_commit_lookup(first)", res); } res = git_commit_tree(&first_tree, first_commit); if (res) { throw QGitError("git_commit_tree(first)", res); } } if (second == "staged") { git_diff_options options; res = git_revparse_single(&first_obj, repo, "HEAD^{tree}"); if (res) { throw QGitError("git_revparse_single(staged)", res); } res = git_tree_lookup(&first_tree, repo, git_object_id(first_obj)); if (res) { throw QGitError("git_tree_lookup(staged)", res); } memset(&options, 0, sizeof(options)); options.version = GIT_DIFF_OPTIONS_VERSION; options.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT; options.context_lines = 3; res = git_diff_tree_to_index(&diff, repo, first_tree, nullptr, &options); if (res) { throw QGitError("git_diff_tree_to_index(staged)", res); } } else if (second == "unstaged") { git_diff_options options; memset(&options, 0, sizeof(options)); options.version = GIT_DIFF_OPTIONS_VERSION; options.flags = GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT; options.context_lines = 3; res = git_diff_index_to_workdir(&diff, repo, nullptr, &options); if (res) { throw QGitError("git_diff_index_to_workdir", res); } } else { res = git_revparse_single(&second_obj, repo, second.toLatin1()); if (res) { throw QGitError("git_revparse_single(second)", res); } res = git_commit_lookup(&second_commit, repo, git_object_id(second_obj)); if (res) { throw QGitError("git_commit_lookup(second)", res); } res = git_commit_tree(&second_tree, second_commit); if (res) { throw QGitError("git_commit_tree(second)", res); } res = git_diff_tree_to_tree(&diff, repo, first_tree, second_tree, nullptr); if (res) { throw QGitError("git_diff_tree_to_tree", res); } } size_t _count = git_diff_num_deltas(diff); for(size_t c = 0; c < _count; c++) { delta = git_diff_get_delta(diff, c); QGitDiffFile item(delta); if (files.contains(item.new_file().path())) { res = git_patch_from_diff(&patch, diff, c); if (res) { throw QGitError("git_patch_from_diff", res); } size_t hunks = git_patch_num_hunks(patch); for(size_t hunk_cnt = 0; hunk_cnt < hunks; hunk_cnt++) { const git_diff_hunk *hunk = nullptr; res = git_patch_get_hunk(&hunk, nullptr, patch, hunk_cnt); if (res) { throw QGitError("git_patch_get_hunk", res); } QGitDiffHunk hunkObj(hunk); const git_diff_line *line = nullptr; int lines = git_patch_num_lines_in_hunk(patch, hunk_cnt); if (lines > 0) { for(int line_cnt = 0; line_cnt < lines; line_cnt++) { res = git_patch_get_line_in_hunk(&line, patch, hunk_cnt, static_cast<size_t>(line_cnt)); if (res) { throw QGitError("git_patch_get_line_in_hunk", res); } hunkObj.addLine(line); } } item.addHunk(hunkObj); } items.append(item); } } } catch(const QGitError &ex) { error = ex; } emit commitDiffContentReply(first, second, items, 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 void *run_index_diffs(void *arg) { int thread = *(int *)arg; git_repository *repo; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; size_t i; int exp[4] = { 0, 0, 0, 0 }; cl_git_pass(git_repository_open(&repo, git_repository_path(_repo))); switch (thread & 0x03) { case 0: /* diff index to workdir */; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); break; case 1: /* diff tree 'a' to index */; cl_git_pass(git_diff_tree_to_index(&diff, repo, _a, NULL, &opts)); break; case 2: /* diff tree 'b' to index */; cl_git_pass(git_diff_tree_to_index(&diff, repo, _b, NULL, &opts)); break; case 3: /* diff index to workdir (explicit index) */; { git_index *idx; cl_git_pass(git_repository_index(&idx, repo)); cl_git_pass(git_diff_index_to_workdir(&diff, repo, idx, &opts)); git_index_free(idx); break; } } /* keep some diff stats to make sure results are as expected */ i = git_diff_num_deltas(diff); git_atomic_add(&_counts[0], (int32_t)i); exp[0] = (int)i; while (i > 0) { switch (git_diff_get_delta(diff, --i)->status) { case GIT_DELTA_MODIFIED: exp[1]++; git_atomic_inc(&_counts[1]); break; case GIT_DELTA_ADDED: exp[2]++; git_atomic_inc(&_counts[2]); break; case GIT_DELTA_DELETED: exp[3]++; git_atomic_inc(&_counts[3]); break; default: break; } } switch (thread & 0x03) { case 0: case 3: cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(4, exp[1]); cl_assert_equal_i(0, exp[2]); cl_assert_equal_i(4, exp[3]); break; case 1: cl_assert_equal_i(12, exp[0]); cl_assert_equal_i(3, exp[1]); cl_assert_equal_i(7, exp[2]); cl_assert_equal_i(2, exp[3]); break; case 2: cl_assert_equal_i(8, exp[0]); cl_assert_equal_i(3, exp[1]); cl_assert_equal_i(3, exp[2]); cl_assert_equal_i(2, exp[3]); break; } git_diff_free(diff); git_repository_free(repo); git_error_clear(); return arg; }
void test_diff_index__0(void) { /* grabbed a couple of commit oids from the history of the attr repo */ const char *a_commit = "26a125ee1bf"; /* the current HEAD */ const char *b_commit = "0017bd4ab1ec3"; /* the start */ git_tree *a = resolve_commit_oid_to_tree(g_repo, a_commit); git_tree *b = resolve_commit_oid_to_tree(g_repo, b_commit); git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff *diff = NULL; diff_expects exp; cl_assert(a); cl_assert(b); opts.context_lines = 1; opts.interhunk_lines = 1; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); /* to generate these values: * - cd to tests/resources/status, * - mv .gitted .git * - git diff --name-status --cached 26a125ee1bf * - git diff -U1 --cached 26a125ee1bf * - mv .git .gitted */ cl_assert_equal_i(8, exp.files); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(8, exp.hunks); cl_assert_equal_i(11, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(6, exp.line_adds); cl_assert_equal_i(2, exp.line_dels); git_diff_free(diff); diff = NULL; memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &exp)); /* to generate these values: * - cd to tests/resources/status, * - mv .gitted .git * - git diff --name-status --cached 0017bd4ab1ec3 * - git diff -U1 --cached 0017bd4ab1ec3 * - mv .git .gitted */ cl_assert_equal_i(12, exp.files); cl_assert_equal_i(7, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); cl_assert_equal_i(12, exp.hunks); cl_assert_equal_i(16, exp.lines); cl_assert_equal_i(3, exp.line_ctxt); cl_assert_equal_i(11, exp.line_adds); cl_assert_equal_i(2, exp.line_dels); git_diff_free(diff); diff = NULL; git_tree_free(a); git_tree_free(b); }
static void test_with_many(int expected_new) { git_index *index; git_tree *tree, *new_tree; git_diff *diff = NULL; diff_expects exp; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; git_diff_find_options opts = GIT_DIFF_FIND_OPTIONS_INIT; cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass( git_revparse_single((git_object **)&tree, g_repo, "HEAD^{tree}")); cl_git_pass(p_rename("renames/ikeepsix.txt", "renames/ikeepsix2.txt")); cl_git_pass(git_index_remove_bypath(index, "ikeepsix.txt")); cl_git_pass(git_index_add_bypath(index, "ikeepsix2.txt")); cl_git_pass(git_index_write(index)); cl_git_pass(git_diff_tree_to_index(&diff, g_repo, tree, index, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(expected_new + 1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(expected_new + 2, exp.files); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(expected_new, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(expected_new + 1, exp.files); git_diff_free(diff); cl_repo_commit_from_index(NULL, g_repo, NULL, 1372350000, "yoyoyo"); cl_git_pass(git_revparse_single( (git_object **)&new_tree, g_repo, "HEAD^{tree}")); cl_git_pass(git_diff_tree_to_tree( &diff, g_repo, tree, new_tree, &diffopts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); cl_assert_equal_i(expected_new + 1, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(expected_new + 2, exp.files); opts.flags = GIT_DIFF_FIND_ALL; cl_git_pass(git_diff_find_similar(diff, &opts)); memset(&exp, 0, sizeof(exp)); cl_git_pass(git_diff_foreach( diff, diff_file_cb, NULL, NULL, NULL, &exp)); cl_assert_equal_i(1, exp.file_status[GIT_DELTA_RENAMED]); cl_assert_equal_i(expected_new, exp.file_status[GIT_DELTA_ADDED]); cl_assert_equal_i(expected_new + 1, exp.files); git_diff_free(diff); git_tree_free(new_tree); git_tree_free(tree); git_index_free(index); }
int lg2_diff(git_repository *repo, int argc, char *argv[]) { git_tree *t1 = NULL, *t2 = NULL; git_diff *diff; struct opts o = { GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT, -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "." }; parse_opts(&o, argc, argv); /** * Possible argument patterns: * * * <sha1> <sha2> * * <sha1> --cached * * <sha1> * * --cached * * --nocache (don't use index data in diff at all) * * nothing * * Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2> * are not supported in this example */ if (o.treeish1) treeish_to_tree(&t1, repo, o.treeish1); if (o.treeish2) treeish_to_tree(&t2, repo, o.treeish2); if (t1 && t2) check_lg2( git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts), "diff trees", NULL); else if (o.cache != CACHE_NORMAL) { if (!t1) treeish_to_tree(&t1, repo, "HEAD"); if (o.cache == CACHE_NONE) check_lg2( git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts), "diff tree to working directory", NULL); else check_lg2( git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), "diff tree to index", NULL); } else if (t1) check_lg2( git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts), "diff tree to working directory", NULL); else check_lg2( git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts), "diff index to working directory", NULL); /** Apply rename and copy detection if requested. */ if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0) check_lg2( git_diff_find_similar(diff, &o.findopts), "finding renames and copies", NULL); /** Generate simple output using libgit2 display helper. */ if (!o.output) o.output = OUTPUT_DIFF; if (o.output != OUTPUT_DIFF) diff_print_stats(diff, &o); if ((o.output & OUTPUT_DIFF) != 0) { if (o.color >= 0) fputs(colors[0], stdout); check_lg2( git_diff_print(diff, o.format, color_printer, &o.color), "displaying diff", NULL); if (o.color >= 0) fputs(colors[0], stdout); } /** Cleanup before exiting. */ git_diff_free(diff); git_tree_free(t1); git_tree_free(t2); return 0; }
/* * call-seq: * Tree.diff(repo, tree, diffable[, options]) -> diff * * Returns a diff between the `tree` and the diffable object that was given. * +diffable+ can either be a +Rugged::Commit+, a +Rugged::Tree+, a +Rugged::Index+, * or +nil+. * * The +tree+ object will be used as the "old file" side of the diff, while the * parent tree or the +diffable+ object will be used for the "new file" side. * * If +tree+ or +diffable+ are nil, they will be treated as an empty tree. Passing * both as `nil` will raise an exception. * * The following options can be passed in the +options+ Hash: * * :paths :: * An array of paths / fnmatch patterns to constrain the diff to a specific * set of files. Also see +:disable_pathspec_match+. * * :max_size :: * An integer specifying the maximum byte size of a file before a it will * be treated as binary. The default value is 512MB. * * :context_lines :: * The number of unchanged lines that define the boundary of a hunk (and * to display before and after the actual changes). The default is 3. * * :interhunk_lines :: * The maximum number of unchanged lines between hunk boundaries before the hunks * will be merged into a one. The default is 0. * * :old_prefix :: * The virtual "directory" to prefix to old filenames in hunk headers. * The default is "a". * * :new_prefix :: * The virtual "directory" to prefix to new filenames in hunk headers. * The default is "b". * * :reverse :: * If true, the sides of the diff will be reversed. * * :force_text :: * If true, all files will be treated as text, disabling binary attributes & detection. * * :ignore_whitespace :: * If true, all whitespace will be ignored. * * :ignore_whitespace_change :: * If true, changes in amount of whitespace will be ignored. * * :ignore_whitespace_eol :: * If true, whitespace at end of line will be ignored. * * :ignore_submodules :: * if true, submodules will be excluded from the diff completely. * * :patience :: * If true, the "patience diff" algorithm will be used (currenlty unimplemented). * * :include_ignored :: * If true, ignored files will be included in the diff. * * :include_untracked :: * If true, untracked files will be included in the diff. * * :include_unmodified :: * If true, unmodified files will be included in the diff. * * :recurse_untracked_dirs :: * Even if +:include_untracked+ is true, untracked directories will only be * marked with a single entry in the diff. If this flag is set to true, * all files under ignored directories will be included in the diff, too. * * :disable_pathspec_match :: * If true, the given +:paths+ will be applied as exact matches, instead of * as fnmatch patterns. * * :deltas_are_icase :: * If true, filename comparisons will be made with case-insensitivity. * * :include_untracked_content :: * if true, untracked content will be contained in the the diff patch text. * * :skip_binary_check :: * If true, diff deltas will be generated without spending time on binary * detection. This is useful to improve performance in cases where the actual * file content difference is not needed. * * :include_typechange :: * If true, type changes for files will not be interpreted as deletion of * the "old file" and addition of the "new file", but will generate * typechange records. * * :include_typechange_trees :: * Even if +:include_typechange+ is true, blob -> tree changes will still * usually be handled as a deletion of the blob. If this flag is set to true, * blob -> tree changes will be marked as typechanges. * * :ignore_filemode :: * If true, file mode changes will be ignored. * * :recurse_ignored_dirs :: * Even if +:include_ignored+ is true, ignored directories will only be * marked with a single entry in the diff. If this flag is set to true, * all files under ignored directories will be included in the diff, too. * * Examples: * * # Emulating `git diff <treeish>` * tree = Rugged::Tree.lookup(repo, "d70d245ed97ed2aa596dd1af6536e4bfdb047b69") * diff = tree.diff(repo.index) * diff.merge!(tree.diff) * * # Tree-to-Tree Diff * tree = Rugged::Tree.lookup(repo, "d70d245ed97ed2aa596dd1af6536e4bfdb047b69") * other_tree = Rugged::Tree.lookup(repo, "7a9e0b02e63179929fed24f0a3e0f19168114d10") * diff = tree.diff(other_tree) */ static VALUE rb_git_tree_diff_(int argc, VALUE *argv, VALUE self) { git_tree *tree = NULL; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_repository *repo = NULL; git_diff *diff = NULL; VALUE rb_self, rb_repo, rb_other, rb_options; int error; rb_scan_args(argc, argv, "22", &rb_repo, &rb_self, &rb_other, &rb_options); rugged_parse_diff_options(&opts, rb_options); Data_Get_Struct(rb_repo, git_repository, repo); if (!NIL_P(rb_self)) { if (!rb_obj_is_kind_of(rb_self, rb_cRuggedTree)) rb_raise(rb_eTypeError, "At least a Rugged::Tree object is required for diffing"); Data_Get_Struct(rb_self, git_tree, tree); } if (NIL_P(rb_other)) { if (tree == NULL) { xfree(opts.pathspec.strings); rb_raise(rb_eTypeError, "Need 'old' or 'new' for diffing"); } error = git_diff_tree_to_tree(&diff, repo, tree, NULL, &opts); } else { if (TYPE(rb_other) == T_STRING) rb_other = rugged_object_rev_parse(rb_repo, rb_other, 1); if (rb_obj_is_kind_of(rb_other, rb_cRuggedCommit)) { git_tree *other_tree; git_commit *commit; Data_Get_Struct(rb_other, git_commit, commit); error = git_commit_tree(&other_tree, commit); if (!error) { error = git_diff_tree_to_tree(&diff, repo, tree, other_tree, &opts); git_tree_free(other_tree); } } else if (rb_obj_is_kind_of(rb_other, rb_cRuggedTree)) { git_tree *other_tree; Data_Get_Struct(rb_other, git_tree, other_tree); error = git_diff_tree_to_tree(&diff, repo, tree, other_tree, &opts); } else if (rb_obj_is_kind_of(rb_other, rb_cRuggedIndex)) { git_index *index; Data_Get_Struct(rb_other, git_index, index); error = git_diff_tree_to_index(&diff, repo, tree, index, &opts); } else { xfree(opts.pathspec.strings); rb_raise(rb_eTypeError, "A Rugged::Commit, Rugged::Tree or Rugged::Index instance is required"); } } xfree(opts.pathspec.strings); rugged_exception_check(error); return rugged_diff_new(rb_cRuggedDiff, rb_repo, diff); }
void QGit::commit(QString message) { git_repository *repo = nullptr; git_signature *me = nullptr; git_commit *parent = nullptr; git_index *index = nullptr; git_tree *tree = nullptr; git_oid new_commit_id = { {0} }; git_oid parent_id = { {0} }; git_oid tree_id = { {0} }; git_object *git_obj = nullptr; git_diff *diff = nullptr; size_t _count = 0; int unborn = 0; int res = 0; QGitError error; try { res = git_repository_open(&repo, m_path.absolutePath().toUtf8().constData()); if (res) { throw QGitError("git_repository_open", res); } /// Check if somthing is staged res = git_revparse_single(&git_obj, repo, "HEAD^{tree}"); if (res) { throw QGitError("git_revparse_single(staged)", res); } res = git_tree_lookup(&tree, repo, git_object_id(git_obj)); if (res) { throw QGitError("git_tree_lookup(staged)", res); } res = git_diff_tree_to_index(&diff, repo, tree, nullptr, nullptr); if (res) { throw QGitError("git_diff_tree_to_index(staged)", res); } _count = git_diff_num_deltas(diff); if (_count == 0) { throw QGitError("Nothing staged.", res); } if (tree) { git_tree_free(tree); tree = nullptr; } /// Check end res = git_signature_default(&me, repo); if (res) { throw QGitError("git_signature_default", res); } res = git_repository_index(&index, repo); if (res) { throw QGitError("git_repository_index", res); } res = git_index_write_tree(&tree_id, index); if (res) { throw QGitError("git_index_write_tree", res); } res = git_tree_lookup(&tree, repo, &tree_id); if (res) { throw QGitError("git_tree_lookup", res); } unborn = git_repository_head_unborn(repo); if (unborn) { res = git_commit_create_v( &new_commit_id, repo, "HEAD", /* name of ref to update */ me, /* author */ me, /* committer */ nullptr, /* nullptr = UTF-8 message encoding */ message.toUtf8().constData(), /* message */ tree, /* root tree */ 0); /* parent count */ if (res) { throw QGitError("git_commit_create_v", res); } } else { res = git_reference_name_to_id(&parent_id, repo, "HEAD"); if (res) { throw QGitError("git_reference_name_to_id", res); } res = git_commit_lookup(&parent, repo, &parent_id); if (res) { throw QGitError("git_commit_lookup", res); } res = git_commit_create_v( &new_commit_id, repo, "HEAD", /* name of ref to update */ me, /* author */ me, /* committer */ nullptr, /* nullptr = UTF-8 message encoding */ message.toUtf8().constData(), /* message */ tree, /* root tree */ 1, /* parent count */ parent); /* parent */ if (res) { throw QGitError("git_commit_create_v", res); } } } catch(const QGitError &ex) { error = ex; } emit commitReply(QString::fromUtf8(reinterpret_cast<const char *>(new_commit_id.id)), error); if (parent) { git_commit_free(parent); parent = nullptr; } if (index) { git_index_free(index); index = nullptr; } if (tree) { git_tree_free(tree); tree = nullptr; } if (me) { git_signature_free(me); me = nullptr; } if (diff) { git_diff_free(diff); diff = nullptr; } if (git_obj) { git_object_free(git_obj); git_obj = nullptr; } if (repo) { git_repository_free(repo); repo = nullptr; } }
static int rebase_commit_merge( git_oid *commit_id, git_rebase *rebase, const git_signature *author, const git_signature *committer, const char *message_encoding, const char *message) { git_index *index = NULL; git_reference *head = NULL; git_commit *current_commit = NULL, *head_commit = NULL, *commit = NULL; git_rebase_operation *operation; git_tree *head_tree = NULL, *tree = NULL; git_diff *diff = NULL; git_oid tree_id; git_buf reflog_msg = GIT_BUF_INIT; char old_idstr[GIT_OID_HEXSZ], new_idstr[GIT_OID_HEXSZ]; int error; operation = git_array_get(rebase->operations, rebase->current); assert(operation); if ((error = git_repository_index(&index, rebase->repo)) < 0) goto done; if (git_index_has_conflicts(index)) { giterr_set(GITERR_REBASE, "Conflicts have not been resolved"); error = GIT_EMERGECONFLICT; goto done; } if ((error = git_commit_lookup(¤t_commit, rebase->repo, &operation->id)) < 0 || (error = git_repository_head(&head, rebase->repo)) < 0 || (error = git_reference_peel((git_object **)&head_commit, head, GIT_OBJ_COMMIT)) < 0 || (error = git_commit_tree(&head_tree, head_commit)) < 0 || (error = git_diff_tree_to_index(&diff, rebase->repo, head_tree, index, NULL)) < 0) goto done; if (git_diff_num_deltas(diff) == 0) { giterr_set(GITERR_REBASE, "This patch has already been applied"); error = GIT_EAPPLIED; goto done; } if ((error = git_index_write_tree(&tree_id, index)) < 0 || (error = git_tree_lookup(&tree, rebase->repo, &tree_id)) < 0) 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 **)&head_commit)) < 0 || (error = git_commit_lookup(&commit, rebase->repo, commit_id)) < 0 || (error = git_reference__update_for_commit( rebase->repo, NULL, "HEAD", commit_id, "rebase")) < 0) goto done; git_oid_fmt(old_idstr, git_commit_id(current_commit)); git_oid_fmt(new_idstr, commit_id); error = rebase_setupfile(rebase, REWRITTEN_FILE, O_CREAT|O_WRONLY|O_APPEND, "%.*s %.*s\n", GIT_OID_HEXSZ, old_idstr, GIT_OID_HEXSZ, new_idstr); done: git_buf_free(&reflog_msg); git_commit_free(commit); git_diff_free(diff); git_tree_free(tree); git_tree_free(head_tree); git_commit_free(head_commit); git_commit_free(current_commit); git_reference_free(head); git_index_free(index); return error; }