static void assert_patch_matches_blobs( git_patch *p, git_blob *a, git_blob *b, int hunks, int l0, int l1, int ctxt, int adds, int dels) { const git_diff_delta *delta; size_t tc, ta, td; cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert_equal_oid(git_blob_id(a), &delta->old_file.id); cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); cl_assert_equal_oid(git_blob_id(b), &delta->new_file.id); cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size); cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p)); if (hunks > 0) cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0)); if (hunks > 1) cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1)); cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(ctxt, (int)tc); cl_assert_equal_i(adds, (int)ta); cl_assert_equal_i(dels, (int)td); }
/** * ggit_patch_get_num_lines_in_hunk: * @patch: a #GgitPatch. * @hunk: the hunk index. * * Get the number of lines in @hunk. * * Returns: the number of lines. * **/ gint ggit_patch_get_num_lines_in_hunk (GgitPatch *patch, gsize hunk) { g_return_val_if_fail (patch != NULL, FALSE); return git_patch_num_lines_in_hunk (patch->patch, hunk); }
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); }
/* * call-seq: * patch.lines(options = {}) -> int * * The following options can be passed in the +options+ Hash: * * :exclude_context :: * Boolean value specifying that context line counts should be excluded from * the returned total. * * :exclude_additions :: * Boolean value specifying that addition line counts should be excluded from * the returned total. * * :exclude_deletions :: * Boolean value specifying that deletion line counts should be excluded from * the returned total. * * :exclude_eofnl :: * Boolean value specifying that end-of-file newline change lines should * be excluded from the returned total. * * Returns the total number of lines in the patch, depending on the options * specified. */ static VALUE rb_git_diff_patch_lines(int argc, VALUE *argv, VALUE self) { git_patch *patch; size_t lines = 0; VALUE rb_options; Data_Get_Struct(self, git_patch, patch); int options = 0; rb_scan_args(argc, argv, "0:", &rb_options); if (!NIL_P(rb_options)) { if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_context")))) { options |= EXCLUDE_CONTEXT; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_additions")))) { options |= EXCLUDE_ADDITIONS; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_deletions")))) { options |= EXCLUDE_DELETIONS; } if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_eofnl")))) { options |= EXCLUDE_EOFNL; } } if (options == 0) { size_t i = 0, hunks_count = git_patch_num_hunks(patch); for (i = 0; i < hunks_count; ++i) { lines += git_patch_num_lines_in_hunk(patch, i); } } else { size_t i = 0, hunks_count = git_patch_num_hunks(patch); for (i = 0; i < hunks_count; ++i) { size_t lines_in_hunk = git_patch_num_lines_in_hunk(patch, i), l = 0; for (l = 0; l < lines_in_hunk; ++l) { const git_diff_line *line; rugged_exception_check( git_patch_get_line_in_hunk(&line, patch, i, l) ); switch (line->origin) { case GIT_DIFF_LINE_CONTEXT: if (options & EXCLUDE_CONTEXT) continue; break; case GIT_DIFF_LINE_ADDITION: if (options & EXCLUDE_ADDITIONS) continue; break; case GIT_DIFF_LINE_DELETION: if (options & EXCLUDE_DELETIONS) continue; break; case GIT_DIFF_LINE_ADD_EOFNL: case GIT_DIFF_LINE_DEL_EOFNL: if (options & EXCLUDE_EOFNL) continue; break; } lines += 1; } } } return INT2FIX(lines); }
void test_diff_blob__can_compare_blob_to_buffer_with_patch(void) { git_patch *p; git_blob *a; git_oid a_oid; const char *a_content = "Hello from the root\n"; const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n"; size_t tc, ta, td; /* tests/resources/attr/root_test1 */ cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8)); cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8)); /* diff from blob a to content of b */ cl_git_pass(git_patch_from_blob_and_buffer( &p, a, NULL, b_content, strlen(b_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, git_patch_get_delta(p)->status); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0)); cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(1, (int)tc); cl_assert_equal_i(5, (int)ta); cl_assert_equal_i(0, (int)td); git_patch_free(p); /* diff from blob a to content of a */ opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED; cl_git_pass(git_patch_from_blob_and_buffer( &p, a, NULL, a_content, strlen(a_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); /* diff from NULL blob to content of a */ cl_git_pass(git_patch_from_blob_and_buffer( &p, NULL, NULL, a_content, strlen(a_content), NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0)); git_patch_free(p); /* diff from blob a to NULL buffer */ cl_git_pass(git_patch_from_blob_and_buffer( &p, a, NULL, NULL, 0, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, git_patch_get_delta(p)->status); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0)); git_patch_free(p); /* diff with reverse */ opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blob_and_buffer( &p, a, NULL, NULL, 0, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0)); git_patch_free(p); git_blob_free(a); }
void test_diff_blob__can_compare_against_null_blobs_with_patch(void) { git_blob *e = NULL; git_patch *p; const git_diff_delta *delta; const git_diff_line *line; int l, max_l; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size); cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin); } git_patch_free(p); opts.flags |= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->old_file.size); cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin); } git_patch_free(p); opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); }