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); }
/* * call-seq: * commit.to_mbox(options = {}) -> str * * Returns +commit+'s contents formatted to resemble UNIX mailbox format. * * Does not (yet) support merge commits. * * The following options can be passed in the +options+ Hash: * * :patch_no :: * Number for this patch in the series. Defaults to +1+. * * :total_patches :: * Total number of patches in the series. Defaults to +1+. * * :exclude_subject_patch_marker :: * If set to true, no "[PATCH]" marker will be * added to the beginning of the subject line. * * Additionally, you can also pass the same options as for Rugged::Tree#diff. */ static VALUE rb_git_commit_to_mbox(int argc, VALUE *argv, VALUE self) { git_buf email_patch = { NULL }; git_repository *repo; git_commit *commit; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_format_email_flags_t flags = GIT_DIFF_FORMAT_EMAIL_NONE; VALUE rb_repo = rugged_owner(self), rb_email_patch = Qnil, rb_val, rb_options; int error; size_t patch_no = 1, total_patches = 1; rb_scan_args(argc, argv, ":", &rb_options); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Data_Get_Struct(self, git_commit, commit); if (!NIL_P(rb_options)) { Check_Type(rb_options, T_HASH); rb_val = rb_hash_aref(rb_options, CSTR2SYM("patch_no")); if (!NIL_P(rb_val)) patch_no = NUM2INT(rb_val); rb_val = rb_hash_aref(rb_options, CSTR2SYM("total_patches")); if (!NIL_P(rb_val)) total_patches = NUM2INT(rb_val); if (RTEST(rb_hash_aref(rb_options, CSTR2SYM("exclude_subject_patch_marker")))) flags |= GIT_DIFF_FORMAT_EMAIL_EXCLUDE_SUBJECT_PATCH_MARKER; rugged_parse_diff_options(&opts, rb_options); } error = git_diff_commit_as_email( &email_patch, repo, commit, patch_no, total_patches, flags, &opts); if (error) goto cleanup; rb_email_patch = rb_enc_str_new(email_patch.ptr, email_patch.size, rb_utf8_encoding()); cleanup: xfree(opts.pathspec.strings); git_buf_free(&email_patch); rugged_exception_check(error); return rb_email_patch; }
/* * call-seq: * blob.diff(other, options = {}) -> patch * * Directly generate a Rugged::Patch from the difference between +blob+ and +other+. * * +other+ can either be another Rugged::Blob instance, a string, * or nil (treated as an empty blob). * * The following options can be passed in the +options+ Hash: * * :max_size :: * An integer specifying the maximum byte size of a blob 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. * * :patience :: * If true, the "patience diff" algorithm will be used (currently unimplemented). * * :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. * * :old_path :: * An optional string to treat +blob+ as if it had this filename. * * :new_path :: * An optional string to treat +other+ as if it had this filename. */ static VALUE rb_git_blob_diff(int argc, VALUE *argv, VALUE self) { git_blob *blob; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_diff_patch *patch; const char *old_path = NULL, *new_path = NULL; VALUE rb_other, rb_options; int error; rb_scan_args(argc, argv, "10:", &rb_other, &rb_options); if (!NIL_P(rb_options)) { VALUE rb_value; rb_value = rb_hash_aref(rb_options, CSTR2SYM("old_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); old_path = StringValueCStr(rb_value); } rb_value = rb_hash_aref(rb_options, CSTR2SYM("new_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); new_path = StringValueCStr(rb_value); } rugged_parse_diff_options(&opts, rb_options); } Data_Get_Struct(self, git_blob, blob); if (NIL_P(rb_other)) { error = git_diff_patch_from_blobs(&patch, blob, old_path, NULL, new_path, &opts); } else if (rb_obj_is_kind_of(rb_other, rb_cRuggedBlob)) { git_blob *other_blob; Data_Get_Struct(rb_other, git_blob, other_blob); error = git_diff_patch_from_blobs(&patch, blob, old_path, other_blob, new_path, &opts); } else if (TYPE(rb_other) == T_STRING) { const char * buffer = StringValueCStr(rb_other); error = git_diff_patch_from_blob_and_buffer(&patch, blob, old_path, buffer, RSTRING_LEN(rb_other), new_path, &opts); } else { rb_raise(rb_eTypeError, "wrong argument type %s (expected Rugged::Blob, String, or nil)", rb_obj_classname(rb_other)); } rugged_exception_check(error); return rugged_diff_patch_new(self, patch); }
/* * 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); }
static VALUE rb_git_diff_index_to_workdir(VALUE self, 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; 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); error = git_diff_index_to_workdir(&diff, repo, index, &opts); xfree(opts.pathspec.strings); rugged_exception_check(error); return rugged_diff_new(rb_cRuggedDiff, owner, diff); }
/* * call-seq: * Patch.from_strings(old_content = nil, new_content = nil, options = {}) -> patch * * Directly generate a Rugged::Patch from the difference between the content of * the two strings `old_content` and `new_content`. * * The following options can be passed in the +options+ Hash: * * :old_path :: * An optional string to treat +blob+ as if it had this filename. * * :new_path :: * An optional string to treat +other+ as if it had this filename. * * Additionally, `options` can also contain all other valid diff options * (see Rugged::Tree#diff for a complete list). */ VALUE rb_git_patch_from_strings(int argc, VALUE *argv, VALUE self) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_patch *patch; char * old_path = NULL, * new_path = NULL; VALUE rb_old_buffer, rb_new_buffer, rb_options; rb_scan_args(argc, argv, "02:", &rb_old_buffer, &rb_new_buffer, &rb_options); if (!NIL_P(rb_options)) { VALUE rb_value; rb_value = rb_hash_aref(rb_options, CSTR2SYM("old_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); old_path = StringValueCStr(rb_value); } rb_value = rb_hash_aref(rb_options, CSTR2SYM("new_path")); if (!NIL_P(rb_value)) { Check_Type(rb_value, T_STRING); new_path = StringValueCStr(rb_value); } rugged_parse_diff_options(&opts, rb_options); } rugged_exception_check(git_patch_from_buffers(&patch, NIL_P(rb_old_buffer) ? NULL : StringValuePtr(rb_old_buffer), NIL_P(rb_old_buffer) ? 0 : RSTRING_LEN(rb_old_buffer), old_path, NIL_P(rb_new_buffer) ? NULL : StringValuePtr(rb_new_buffer), NIL_P(rb_new_buffer) ? 0 : RSTRING_LEN(rb_new_buffer), new_path, &opts )); return rugged_patch_new(self, patch); }
/* * call-seq: * tree.diff_workdir([options]) -> diff * * Returns a diff between a tree and the current workdir. * * The +tree+ object will be used as the "old file" side of the diff, while the * content of the current workdir will be used for the "new file" side. * * See Rugged::Tree#diff for a list of options that can be passed. */ static VALUE rb_git_tree_diff_workdir(int argc, VALUE *argv, VALUE self) { git_tree *tree; git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_repository *repo; git_diff *diff; VALUE owner, rb_options; int error; rb_scan_args(argc, argv, "00:", &rb_options); rugged_parse_diff_options(&opts, rb_options); Data_Get_Struct(self, git_tree, tree); owner = rugged_owner(self); Data_Get_Struct(owner, git_repository, repo); error = git_diff_tree_to_workdir(&diff, repo, tree, &opts); xfree(opts.pathspec.strings); rugged_exception_check(error); return rugged_diff_new(rb_cRuggedDiff, owner, diff); }
/* * 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); }