/* * call-seq: * branch.move(old_name, new_name, options = {}) -> new_branch * branch.move(branch, new_name, options = {}) -> new_branch * branch.rename(old_name, new_name, options = {}) -> new_branch * branch.rename(branch, new_name, options = {}) -> new_branch * * Rename a branch to +new_name+. * * +new_name+ needs to be a branch name, not an absolute reference path * (e.g. +development+ instead of +refs/heads/development+). * * The following options can be passed in the +options+ Hash: * * :force :: * Overwrites the branch with the given +name+, if it already exists, * instead of raising an exception. * * If a branch with the given +new_name+ already exists and +:force+ is not +true+, * an exception will be raised. * * A new Rugged::Branch object for the renamed branch will be returned. * */ static VALUE rb_git_branch_collection_move(int argc, VALUE *argv, VALUE self) { VALUE rb_repo = rugged_owner(self), rb_name_or_branch, rb_new_branch_name, rb_options; git_reference *old_branch = NULL, *new_branch = NULL; git_repository *repo; int error, force = 0; rb_scan_args(argc, argv, "20:", &rb_name_or_branch, &rb_new_branch_name, &rb_options); Check_Type(rb_new_branch_name, T_STRING); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = rugged_branch_lookup(&old_branch, repo, rb_name_or_branch); rugged_exception_check(error); if (!NIL_P(rb_options)) { force = RTEST(rb_hash_aref(rb_options, CSTR2SYM("force"))); } error = git_branch_move(&new_branch, old_branch, StringValueCStr(rb_new_branch_name), force); git_reference_free(old_branch); rugged_exception_check(error); return rugged_branch_new(rugged_owner(self), new_branch); }
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: * walker.each { |commit| block } * walker.each -> Iterator * * Perform the walk through the repository, yielding each * one of the commits found as a <tt>Rugged::Commit</tt> instance * to +block+. * * If no +block+ is given, an +Iterator+ will be returned. * * The walker must have been previously set-up before a walk can be performed * (i.e. at least one commit must have been pushed). * * walker.push("92b22bbcb37caf4f6f53d30292169e84f5e4283b") * walker.each { |commit| puts commit.oid } * * generates: * * 92b22bbcb37caf4f6f53d30292169e84f5e4283b * 6b750d5800439b502de669465b385e5f469c78b6 * ef9207141549f4ffcd3c4597e270d32e10d0a6bc * cb75e05f0f8ac3407fb3bd0ebd5ff07573b16c9f * ... */ static VALUE rb_git_walker_each(VALUE self) { git_revwalk *walk; git_commit *commit; git_repository *repo; git_oid commit_oid; int error; Data_Get_Struct(self, git_revwalk, walk); repo = git_revwalk_repository(walk); if (!rb_block_given_p()) return rb_funcall(self, rb_intern("to_enum"), 0); while ((error = git_revwalk_next(&commit_oid, walk)) == 0) { error = git_commit_lookup(&commit, repo, &commit_oid); rugged_exception_check(error); rb_yield(rugged_object_new(rugged_owner(self), (git_object *)commit)); } if (error != GIT_ITEROVER) rugged_exception_check(error); return Qnil; }
/* * call-seq: * tags[name] -> tag * * Lookup a tag in +repo+, with the given +name+. * * +name+ can be a short or canonical tag name * (e.g. +v0.1.0+ or +refs/tags/v0.1.0+). * * Returns the looked up tag, or +nil+ if the tag doesn't exist. */ static VALUE rb_git_tag_collection_aref(VALUE self, VALUE rb_name) { git_reference *tag; git_repository *repo; int error; VALUE rb_repo = rugged_owner(self); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); error = git_reference_lookup(&tag, repo, StringValueCStr(rb_name)); if (error == GIT_ENOTFOUND || error == GIT_EINVALIDSPEC) { char *canonical_ref = xmalloc((RSTRING_LEN(rb_name) + strlen("refs/tags/") + 1) * sizeof(char)); strcpy(canonical_ref, "refs/tags/"); strcat(canonical_ref, StringValueCStr(rb_name)); error = git_reference_lookup(&tag, repo, canonical_ref); xfree(canonical_ref); if (error == GIT_ENOTFOUND) return Qnil; } rugged_exception_check(error); return rugged_ref_new(rb_cRuggedTag, rb_repo, tag); }
/* * call-seq: * patch.delta -> delta * * Returns the delta object associated with the patch. */ static VALUE rb_git_diff_patch_delta(VALUE self) { git_patch *patch; Data_Get_Struct(self, git_patch, patch); return rugged_diff_delta_new(rugged_owner(self), git_patch_get_delta(patch)); }
/* * call-seq: * hunk.each_line { |line| } -> self * hunk.each_line -> Enumerator * * If given a block, yields each line that is part of the current hunk. * * If no block is given, an enumerator is returned instead. */ static VALUE rb_git_diff_hunk_each_line(VALUE self) { git_patch *patch; int error = 0, l, lines_count, hunk_idx; if (!rb_block_given_p()) { return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_line"), self); } Data_Get_Struct(rugged_owner(self), git_patch, patch); lines_count = FIX2INT(rb_iv_get(self, "@line_count")); hunk_idx = FIX2INT(rb_iv_get(self, "@hunk_index")); for (l = 0; l < lines_count; ++l) { const git_diff_line *line; error = git_patch_get_line_in_hunk(&line, patch, hunk_idx, l); if (error) break; rb_yield(rugged_diff_line_new(line)); } rugged_exception_check(error); return self; }
/* * call-seq: * tag.target -> git_object */ static VALUE rb_git_tag_target(VALUE self) { git_reference *ref, *resolved_ref; git_repository *repo; git_object *target; int error; VALUE rb_repo = rugged_owner(self); rugged_check_repo(rb_repo); Data_Get_Struct(self, git_reference, ref); Data_Get_Struct(rb_repo, git_repository, repo); error = git_reference_resolve(&resolved_ref, ref); rugged_exception_check(error); error = git_object_lookup(&target, repo, git_reference_target(resolved_ref), GIT_OBJ_ANY); git_reference_free(resolved_ref); rugged_exception_check(error); if (git_object_type(target) == GIT_OBJ_TAG) { git_object *annotation_target; error = git_tag_target(&annotation_target, (git_tag *)target); git_object_free(target); rugged_exception_check(error); return rugged_object_new(rb_repo, annotation_target); } else { return rugged_object_new(rb_repo, target); } }
/* * call-seq: * submodules.setup_add(url, path[, options]) -> submodule * * Setup a new +submodule+ for checkout in +repository+. * * This does <tt>"git submodule add"</tt> up to the fetch and checkout of the * submodule contents. It prepares a new submodule, creates an entry in * +.gitmodules+ and creates an empty initialized repository either at the * given +path+ in the working directory or in +.git/modules+ with a gitlink * from the working directory to the new repository. * * To fully emulate <tt>"git submodule add"</tt> call this function, then open * the submodule repository and perform the clone step as needed. * Lastly, call Submodule#finalize_add to wrap up adding the new submodule and * +.gitmodules+ to the index to be ready to commit. * * - +url+: URL for the submodule's remote * - +path+: path at which the submodule should be created * * The following options can be passed in the +options+ Hash: * :gitlink :: * (defaults to +true+) should workdir contain a * gitlink to the repository in +.git/modules+ vs. repository * directly in workdir. * * Returns the newly created +submodule+ */ static VALUE rb_git_submodule_setup_add(int argc, VALUE *argv, VALUE self) { git_submodule *submodule; git_repository *repo; int error; int use_gitlink = 1; VALUE rb_repo, rb_url, rb_path, rb_options; rb_scan_args(argc, argv, "20:", &rb_url, &rb_path, &rb_options); Check_Type(rb_url, T_STRING); Check_Type(rb_path, T_STRING); rb_repo = rugged_owner(self); Data_Get_Struct(rb_repo, git_repository, repo); if (!NIL_P(rb_options)) { VALUE rb_val; rb_val = rb_hash_aref(rb_options, CSTR2SYM("gitlink")); use_gitlink = (rb_val != Qfalse); } error = git_submodule_add_setup( &submodule, repo, StringValueCStr(rb_url), StringValueCStr(rb_path), use_gitlink ); rugged_exception_check(error); return rugged_submodule_new(rb_repo, submodule); }
/* * call-seq: * branches.create(name, target, options = {}) -> branch * * Create a new branch with the given +name+, pointing to the +target+. * * +name+ needs to be a branch name, not an absolute reference path * (e.g. +development+ instead of +refs/heads/development+). * * +target+ needs to be an existing commit in the given repository. * * The following options can be passed in the +options+ Hash: * * :force :: * Overwrites the branch with the given +name+, if it already exists, * instead of raising an exception. * * If a branch with the given +name+ already exists and +:force+ is not +true+, * an exception will be raised. * * Returns a Rugged::Branch for the newly created branch. */ static VALUE rb_git_branch_collection_create(int argc, VALUE *argv, VALUE self) { VALUE rb_repo = rugged_owner(self), rb_name, rb_target, rb_options; git_repository *repo; git_reference *branch; git_commit *target; int error, force = 0; rb_scan_args(argc, argv, "20:", &rb_name, &rb_target, &rb_options); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); Check_Type(rb_target, T_STRING); if (!NIL_P(rb_options)) { force = RTEST(rb_hash_aref(rb_options, CSTR2SYM("force"))); } target = (git_commit *)rugged_object_get(repo, rb_target, GIT_OBJ_COMMIT); error = git_branch_create(&branch, repo, StringValueCStr(rb_name), target, force); git_commit_free(target); rugged_exception_check(error); return rugged_branch_new(rb_repo, branch); }
/* * 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: * remote.fetch(refspecs = nil, options = {}) -> hash * * Downloads new data from the remote for the given +refspecs+ and updates tips. * * You can optionally pass in a single or multiple alternative +refspecs+ to use instead of the fetch * refspecs already configured for +remote+. * * Returns a hash containing statistics for the fetch operation. * * The following options can be passed in the +options+ Hash: * * :credentials :: * The credentials to use for the fetch operation. Can be either an instance of one * of the Rugged::Credentials types, or a proc returning one of the former. * The proc will be called with the +url+, the +username+ from the url (if applicable) and * a list of applicable credential types. * * :progress :: * A callback that will be executed with the textual progress received from the remote. * This is the text send over the progress side-band (ie. the "counting objects" output). * * :transfer_progress :: * A callback that will be executed to report clone progress information. It will be passed * the amount of +total_objects+, +indexed_objects+, +received_objects+, +local_objects+, * +total_deltas+, +indexed_deltas+ and +received_bytes+. * * :update_tips :: * A callback that will be executed each time a reference is updated locally. It will be * passed the +refname+, +old_oid+ and +new_oid+. * * :message :: * The message to insert into the reflogs. Defaults to "fetch". * * Example: * * remote = Rugged::Remote.lookup(@repo, 'origin') * remote.fetch({ * transfer_progress: lambda { |total_objects, indexed_objects, received_objects, local_objects, total_deltas, indexed_deltas, received_bytes| * # ... * } * }) */ static VALUE rb_git_remote_fetch(int argc, VALUE *argv, VALUE self) { git_remote *remote; git_repository *repo; git_strarray refspecs; git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, 0 }; char *log_message = NULL; int error; VALUE rb_options, rb_refspecs, rb_result = Qnil, rb_repo = rugged_owner(self); rb_scan_args(argc, argv, "01:", &rb_refspecs, &rb_options); rugged_rb_ary_to_strarray(rb_refspecs, &refspecs); Data_Get_Struct(self, git_remote, remote); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload); if (!NIL_P(rb_options)) { VALUE rb_val = rb_hash_aref(rb_options, CSTR2SYM("message")); if (!NIL_P(rb_val)) log_message = StringValueCStr(rb_val); } if ((error = git_remote_set_callbacks(remote, &callbacks))) goto cleanup; if ((error = git_remote_fetch(remote, &refspecs, log_message)) == GIT_OK) { const git_transfer_progress *stats = git_remote_stats(remote); rb_result = rb_hash_new(); rb_hash_aset(rb_result, CSTR2SYM("total_objects"), UINT2NUM(stats->total_objects)); rb_hash_aset(rb_result, CSTR2SYM("indexed_objects"), UINT2NUM(stats->indexed_objects)); rb_hash_aset(rb_result, CSTR2SYM("received_objects"), UINT2NUM(stats->received_objects)); rb_hash_aset(rb_result, CSTR2SYM("local_objects"), UINT2NUM(stats->local_objects)); rb_hash_aset(rb_result, CSTR2SYM("total_deltas"), UINT2NUM(stats->total_deltas)); rb_hash_aset(rb_result, CSTR2SYM("indexed_deltas"), UINT2NUM(stats->indexed_deltas)); rb_hash_aset(rb_result, CSTR2SYM("received_bytes"), INT2FIX(stats->received_bytes)); } cleanup: xfree(refspecs.strings); if (payload.exception) rb_jump_tag(payload.exception); rugged_exception_check(error); return rb_result; }
/* * call-seq: * tags.create(name, target[, force = false][, annotation = nil]) -> oid * * Create a new tag with the specified +name+ on +target+ in +repo+. * * If +annotation+ is not +nil+, it will cause the creation of an annotated tag object. * +annotation+ has to contain the following key value pairs: * * :tagger :: * An optional Hash containing a git signature. Defaults to the signature * from the configuration if only `:message` is given. Will cause the * creation of an annotated tag object if present. * * :message :: * An optional string containing the message for the new tag. * * Returns the OID of the newly created tag. */ static VALUE rb_git_tag_collection_create(int argc, VALUE *argv, VALUE self) { git_oid tag_oid; git_repository *repo = NULL; git_object *target = NULL; int error, force = 0; VALUE rb_repo = rugged_owner(self), rb_name, rb_target, rb_force, rb_annotation; rb_scan_args(argc, argv, "21:", &rb_name, &rb_target, &rb_force, &rb_annotation); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); if (!NIL_P(rb_force)) force = rugged_parse_bool(rb_force); target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY); if (NIL_P(rb_annotation)) { error = git_tag_create_lightweight( &tag_oid, repo, StringValueCStr(rb_name), target, force ); } else { git_signature *tagger = rugged_signature_get( rb_hash_aref(rb_annotation, CSTR2SYM("tagger")), repo ); VALUE rb_message = rb_hash_aref(rb_annotation, CSTR2SYM("message")); Check_Type(rb_message, T_STRING); error = git_tag_create( &tag_oid, repo, StringValueCStr(rb_name), target, tagger, StringValueCStr(rb_message), force ); git_signature_free(tagger); } git_object_free(target); rugged_exception_check(error); return rb_git_tag_collection_aref(self, rb_name); }
/* * call-seq: * obj.remove_note(data = {}) -> boolean * * Removes a +note+ from +object+, with the given +data+ * arguments, passed as a +Hash+: * * - +:committer+ (optional): a hash with the signature for the committer, * defaults to the signature from the configuration * - +:author+ (optional): a hash with the signature for the author, * defaults to the signature from the configuration * - +:ref+: (optional): canonical name of the reference to use, defaults to "refs/notes/commits" * * When the note is successfully removed +true+ will be * returned as a +Boolean+. * * author = {:email=>"*****@*****.**", :time=>Time.now, :name=>"Vicent Mart\303\255"} * * obj.remove_note( * :author => author, * :committer => author, * :ref => 'refs/notes/builds' * ) */ static VALUE rb_git_note_remove(int argc, VALUE *argv, VALUE self) { int error = 0; const char *notes_ref = NULL; git_repository *repo = NULL; git_signature *author, *committer; git_object *target = NULL; VALUE rb_data; VALUE rb_ref = Qnil; VALUE rb_author = Qnil; VALUE rb_committer = Qnil; VALUE owner; Data_Get_Struct(self, git_object, target); owner = rugged_owner(self); Data_Get_Struct(owner, git_repository, repo); rb_scan_args(argc, argv, "01", &rb_data); if (!NIL_P(rb_data)) { Check_Type(rb_data, T_HASH); rb_ref = rb_hash_aref(rb_data, CSTR2SYM("ref")); if (!NIL_P(rb_ref)) { Check_Type(rb_ref, T_STRING); notes_ref = StringValueCStr(rb_ref); } rb_committer = rb_hash_aref(rb_data, CSTR2SYM("committer")); rb_author = rb_hash_aref(rb_data, CSTR2SYM("author")); } committer = rugged_signature_get(rb_committer, repo); author = rugged_signature_get(rb_author, repo); error = git_note_remove( repo, notes_ref, author, committer, git_object_id(target)); git_signature_free(author); git_signature_free(committer); if (error == GIT_ENOTFOUND) return Qfalse; rugged_exception_check(error); return Qtrue; }
/* * call-seq: * reference.resolve -> peeled_ref * * Peel a symbolic reference to its target reference. * * r1.type #=> :symbolic * r1.name #=> 'HEAD' * r1.target #=> 'refs/heads/master' * * r2 = r1.resolve #=> #<Rugged::Reference:0x401b3948> * r2.target #=> '9d09060c850defbc7711d08b57def0d14e742f4e' */ static VALUE rb_git_ref_resolve(VALUE self) { git_reference *ref; git_reference *resolved; int error; Data_Get_Struct(self, git_reference, ref); error = git_reference_resolve(&resolved, ref); rugged_exception_check(error); return rugged_ref_new(rb_cRuggedReference, rugged_owner(self), resolved); }
static VALUE rb_git_merge_file(int argc, VALUE *argv, VALUE self) { VALUE rb_path, rb_options; VALUE rb_result = rb_hash_new(); VALUE rb_repo = rugged_owner(self); git_repository *repo; git_index *index; const git_index_entry *ancestor, *ours, *theirs; git_merge_file_result merge_file_result = {0}; git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT; int error; rb_scan_args(argc, argv, "1:", &rb_path, &rb_options); if (!NIL_P(rb_options)) { Check_Type(rb_options, T_HASH); rugged_parse_merge_file_options(&opts, rb_options); } Check_Type(rb_path, T_STRING); Data_Get_Struct(self, git_index, index); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_index_conflict_get(&ancestor, &ours, &theirs, index, StringValueCStr(rb_path)); if (error == GIT_ENOTFOUND) return Qnil; else rugged_exception_check(error); if (ours == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 2 entry"); else if (theirs == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 3 entry"); error = git_merge_file_from_index(&merge_file_result, repo, ancestor, ours, theirs, &opts); rugged_exception_check(error); rb_hash_aset(rb_result, CSTR2SYM("automergeable"), merge_file_result.automergeable ? Qtrue : Qfalse); rb_hash_aset(rb_result, CSTR2SYM("path"), rb_path); rb_hash_aset(rb_result, CSTR2SYM("filemode"), INT2FIX(merge_file_result.mode)); rb_hash_aset(rb_result, CSTR2SYM("data"), rb_str_new(merge_file_result.ptr, merge_file_result.len)); git_merge_file_result_free(&merge_file_result); return rb_result; }
/* * call-seq: * reference.target_id -> id * reference.target_id -> ref_name * * Return the target of +reference+. * * If +reference+ is a symbolic reference, it returns the target * reference object. * * If +reference+ is a direct reference, it returns the target object. * * ref1.type #=> :symbolic * ref1.target #=> #<Rugged::Reference ...> * * ref2.type #=> :direct * ref2.target #=> #<Rugged::Commit ...> */ static VALUE rb_git_ref_target(VALUE self) { git_reference *ref; Data_Get_Struct(self, git_reference, ref); if (git_reference_type(ref) == GIT_REF_OID) { git_object *target; rugged_exception_check( git_object_lookup(&target, git_reference_owner(ref), git_reference_target(ref), GIT_OBJ_ANY) ); return rugged_object_new(rugged_owner(self), target); } else { git_reference *target; rugged_exception_check( git_reference_lookup(&target, git_reference_owner(ref), git_reference_symbolic_target(ref)) ); return rugged_ref_new(rb_cRuggedReference, rugged_owner(self), target); } }
/* * call-seq: * annotation.target -> object * * Return the +object+ pointed at by this tag annotation, as a <tt>Rugged::Object</tt> * instance. * * annotation.target #=> #<Rugged::Commit:0x108828918> */ static VALUE rb_git_tag_annotation_target(VALUE self) { git_tag *tag; git_object *target; int error; VALUE owner; Data_Get_Struct(self, git_tag, tag); owner = rugged_owner(self); error = git_tag_target(&target, tag); rugged_exception_check(error); return rugged_object_new(owner, target); }
/* * call-seq: * tags.delete(name) -> nil * * Delete the tag reference identified by +name+. */ static VALUE rb_git_tag_collection_delete(VALUE self, VALUE rb_name) { VALUE rb_repo = rugged_owner(self); git_repository *repo; int error; rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); error = git_tag_delete(repo, StringValueCStr(rb_name)); rugged_exception_check(error); return Qnil; }
/* * call-seq: * commit.tree -> tree * * Return the tree pointed at by this +commit+. The tree is * returned as a +Rugged::Tree+ object. * * commit.tree #=> #<Rugged::Tree:0x10882c680> */ static VALUE rb_git_commit_tree_GET(VALUE self) { git_commit *commit; git_tree *tree; VALUE owner; int error; Data_Get_Struct(self, git_commit, commit); owner = rugged_owner(self); error = git_commit_tree(&tree, commit); rugged_exception_check(error); return rugged_object_new(owner, (git_object *)tree); }
static VALUE each_branch(int argc, VALUE *argv, VALUE self, int branch_names_only) { VALUE rb_repo = rugged_owner(self), rb_filter; git_repository *repo; git_branch_iterator *iter; int error, exception = 0; git_branch_t filter = (GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE), branch_type; rb_scan_args(argc, argv, "01", &rb_filter); if (!rb_block_given_p()) { VALUE symbol = branch_names_only ? CSTR2SYM("each_name") : CSTR2SYM("each"); return rb_funcall(self, rb_intern("to_enum"), 2, symbol, rb_filter); } rugged_check_repo(rb_repo); if (!NIL_P(rb_filter)) filter = parse_branch_type(rb_filter); Data_Get_Struct(rb_repo, git_repository, repo); error = git_branch_iterator_new(&iter, repo, filter); rugged_exception_check(error); if (branch_names_only) { git_reference *branch; while (!exception && (error = git_branch_next(&branch, &branch_type, iter)) == GIT_OK) { rb_protect(rb_yield, rb_str_new_utf8(git_reference_shorthand(branch)), &exception); } } else { git_reference *branch; while (!exception && (error = git_branch_next(&branch, &branch_type, iter)) == GIT_OK) { rb_protect(rb_yield, rugged_branch_new(rb_repo, branch), &exception); } } git_branch_iterator_free(iter); if (exception) rb_jump_tag(exception); if (error != GIT_ITEROVER) rugged_exception_check(error); return Qnil; }
static VALUE rb_git_remote_collection__each(VALUE self, int only_names) { git_repository *repo; git_strarray remotes; size_t i; int error = 0; int exception = 0; VALUE rb_repo; if (!rb_block_given_p()) { if (only_names) return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each_name")); else return rb_funcall(self, rb_intern("to_enum"), 1, CSTR2SYM("each")); } rb_repo = rugged_owner(self); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_remote_list(&remotes, repo); rugged_exception_check(error); if (only_names) { for (i = 0; !exception && i < remotes.count; ++i) { rb_protect(rb_yield, rb_str_new_utf8(remotes.strings[i]), &exception); } } else { for (i = 0; !exception && !error && i < remotes.count; ++i) { git_remote *remote; if (!(error = git_remote_lookup(&remote, repo, remotes.strings[i]))) rb_protect(rb_yield, rugged_remote_new(rb_repo, remote), &exception); } } git_strarray_free(&remotes); if (exception) rb_jump_tag(exception); rugged_exception_check(error); return Qnil; }
/* * 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); }
/* * tree.merge(other_tree[, ancestor_tree[, options]]) -> Rugged::Index * tree.merge(other_tree[, options]) -> Rugged::Index * * Merges two trees and returns the a Rugged::Index object that reflects * the result of the merge. * * The following options can be passed in the +options+ Hash: * * :renames :: * If true, looking for renames will be enabled (`--find-renames`). * * :rename_threshold :: * An integer specifying the minimum similarity of a file to be * seen as an eligible rename source (default 50). * * :target_limit :: * An integer specifying the maximum byte size of a file before a it will * be treated as binary. The default value is 512MB. * * :favor :: * Specifies how and if conflicts are auto-resolved by favoring a specific * file output. Can be one of `:normal`, `:ours`, `:theirs` or `:union`. * */ static VALUE rb_git_tree_merge(int argc, VALUE *argv, VALUE self) { VALUE rb_other_tree, rb_ancestor_tree, rb_options; VALUE rb_repo = rugged_owner(self); git_tree *tree, *other_tree, *ancestor_tree; git_repository *repo; git_index *index; git_merge_options opts = GIT_MERGE_OPTIONS_INIT; int error; if (rb_scan_args(argc, argv, "12", &rb_other_tree, &rb_ancestor_tree, &rb_options) == 2) { if (TYPE(rb_ancestor_tree) == T_HASH) { rb_options = rb_ancestor_tree; rb_ancestor_tree = Qnil; } } if (!NIL_P(rb_options)) { Check_Type(rb_options, T_HASH); rugged_parse_merge_options(&opts, rb_options); } if (!rb_obj_is_kind_of(rb_other_tree, rb_cRuggedTree)) rb_raise(rb_eTypeError, "Expecting a Rugged::Tree instance"); else if (!NIL_P(rb_ancestor_tree) && !rb_obj_is_kind_of(rb_ancestor_tree, rb_cRuggedTree)) rb_raise(rb_eTypeError, "Expecting a Rugged::Tree instance"); Data_Get_Struct(self, git_tree, tree); Data_Get_Struct(rb_repo, git_repository, repo); Data_Get_Struct(rb_other_tree, git_tree, other_tree); if (!NIL_P(rb_ancestor_tree)) Data_Get_Struct(rb_ancestor_tree, git_tree, ancestor_tree); else ancestor_tree = NULL; error = git_merge_trees(&index, repo, ancestor_tree, tree, other_tree, &opts); if (error == GIT_EMERGECONFLICT) return Qnil; rugged_exception_check(error); return rugged_index_new(rb_cRuggedIndex, rb_repo, index); }
/* * call-seq: * remote.push_url = url -> url * * Sets the remote's url for pushing without persisting it in the config. * Existing connections will not be updated. * * remote.push_url = '[email protected]/libgit2/rugged.git' #=> "[email protected]/libgit2/rugged.git" */ static VALUE rb_git_remote_set_push_url(VALUE self, VALUE rb_url) { VALUE rb_repo = rugged_owner(self); git_remote *remote; git_repository *repo; rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_url, T_STRING); Data_Get_Struct(self, git_remote, remote); rugged_exception_check( git_remote_set_pushurl(repo, git_remote_name(remote), StringValueCStr(rb_url)) ); return rb_url; }
static VALUE each_tag(int argc, VALUE *argv, VALUE self, int tag_names_only) { git_repository *repo; git_strarray tags; size_t i; int error, exception = 0; VALUE rb_repo = rugged_owner(self), rb_pattern; const char *pattern = NULL; rb_scan_args(argc, argv, "01", &rb_pattern); if (!rb_block_given_p()) { VALUE symbol = tag_names_only ? CSTR2SYM("each_name") : CSTR2SYM("each"); return rb_funcall(self, rb_intern("to_enum"), 2, symbol, rb_pattern); } if (!NIL_P(rb_pattern)) { Check_Type(rb_pattern, T_STRING); pattern = StringValueCStr(rb_pattern); } rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_tag_list_match(&tags, pattern ? pattern : "", repo); rugged_exception_check(error); if (tag_names_only) { for (i = 0; !exception && i < tags.count; ++i) rb_protect(rb_yield, rb_str_new_utf8(tags.strings[i]), &exception); } else { for (i = 0; !exception && i < tags.count; ++i) { rb_protect(rb_yield, rb_git_tag_collection_aref(self, rb_str_new_utf8(tags.strings[i])), &exception); } } git_strarray_free(&tags); if (exception) rb_jump_tag(exception); return Qnil; }
static VALUE rb_git_merge_file(int argc, VALUE *argv, VALUE self) { VALUE rb_path, rb_options, rb_result; VALUE rb_repo = rugged_owner(self); git_repository *repo; git_index *index; const git_index_entry *ancestor, *ours, *theirs; git_merge_file_result merge_file_result = {0}; git_merge_file_options opts = GIT_MERGE_FILE_OPTIONS_INIT; int error; rb_scan_args(argc, argv, "1:", &rb_path, &rb_options); if (!NIL_P(rb_options)) rugged_parse_merge_file_options(&opts, rb_options); Check_Type(rb_path, T_STRING); Data_Get_Struct(self, git_index, index); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_index_conflict_get(&ancestor, &ours, &theirs, index, StringValueCStr(rb_path)); if (error == GIT_ENOTFOUND) return Qnil; else rugged_exception_check(error); if (ours == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 2 entry"); else if (theirs == NULL) rb_raise(rb_eRuntimeError, "The conflict does not have a stage 3 entry"); error = git_merge_file_from_index(&merge_file_result, repo, ancestor, ours, theirs, &opts); rugged_exception_check(error); rb_result = rb_merge_file_result_fromC(&merge_file_result); git_merge_file_result_free(&merge_file_result); return rb_result; }
/* * call-seq: * branch.upstream -> branch * * Returns the remote tracking branch, or +nil+ if the branch is * remote or has no tracking branch. */ static VALUE rb_git_branch_upstream(VALUE self) { git_reference *branch, *upstream_branch; int error; Data_Get_Struct(self, git_reference, branch); if (git_reference_is_remote(branch)) return Qnil; error = git_branch_upstream(&upstream_branch, branch); if (error == GIT_ENOTFOUND) return Qnil; rugged_exception_check(error); return rugged_branch_new(rugged_owner(self), upstream_branch); }
/* * call-seq: * branches[name] -> branch * * Return the branch with the given +name+. * * Branches can be looked up by their relative (+development+) or absolute * (+refs/heads/development+) branch name. * * If a local branch and a remote branch both share the same short name * (e.g. +refs/heads/origin/master+ and +refs/remotes/origin/master+), * passing +origin/master+ as the +name+ will return the local branch. * You can explicitly request the local branch by passing * +heads/origin/master+, or the remote branch through +remotes/origin/master+. * * Returns the looked up branch, or +nil+ if the branch doesn't exist. */ static VALUE rb_git_branch_collection_aref(VALUE self, VALUE rb_name) { git_reference *branch; git_repository *repo; VALUE rb_repo = rugged_owner(self); int error; rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); error = rugged_branch_lookup(&branch, repo, rb_name); if (error == GIT_ENOTFOUND) return Qnil; rugged_exception_check(error); return rugged_branch_new(rb_repo, branch); }
/* * call-seq: * tags.create_annotation(name, target, annotation) -> annotation * * Create a new annotated tag object with the specified +name+ on +target+ in * +repo+. * * Unlike the +create+ method, +create_annotation+ simply creates a tag * object. It does not write a tag ref. * * +annotation+ must have the following keys: * * :tagger :: * An optional Hash containing a git signature. Defaults to the signature * from the configuration if only `:message` is given. Will cause the * creation of an annotated tag object if present. * * :message :: * An optional string containing the message for the new tag. * * Returns an instance of Rugged::Tag::Annotation representing the newly * created annotation. */ static VALUE rb_git_tag_collection_create_annotation(VALUE self, VALUE rb_name, VALUE rb_target, VALUE rb_annotation) { git_oid tag_oid; git_repository *repo = NULL; git_object *target = NULL, *tag = NULL; git_signature *tagger = NULL; VALUE rb_message; int error; VALUE rb_repo = rugged_owner(self); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); Check_Type(rb_name, T_STRING); target = rugged_object_get(repo, rb_target, GIT_OBJ_ANY); rb_message = rb_hash_aref(rb_annotation, CSTR2SYM("message")); Check_Type(rb_message, T_STRING); tagger = rugged_signature_get( rb_hash_aref(rb_annotation, CSTR2SYM("tagger")), repo ); error = git_tag_annotation_create( &tag_oid, repo, StringValueCStr(rb_name), target, tagger, StringValueCStr(rb_message) ); git_object_free(target); git_signature_free(tagger); rugged_exception_check(error); error = git_object_lookup(&tag, repo, &tag_oid, GIT_OBJ_TAG); rugged_exception_check(error); return rugged_object_new(rb_repo, tag); }
/* * call-seq: * remotes.delete(remote) -> nil * remotes.delete(name) -> nil * * Delete the specified remote. * * repo.remotes.delete("origin") * # Remote no longer exists in the configuration. */ static VALUE rb_git_remote_collection_delete(VALUE self, VALUE rb_name_or_remote) { VALUE rb_repo = rugged_owner(self); git_repository *repo; int error; if (rb_obj_is_kind_of(rb_name_or_remote, rb_cRuggedRemote)) rb_name_or_remote = rb_funcall(rb_name_or_remote, rb_intern("name"), 0); if (TYPE(rb_name_or_remote) != T_STRING) rb_raise(rb_eTypeError, "Expecting a String or Rugged::Remote instance"); rugged_check_repo(rb_repo); Data_Get_Struct(rb_repo, git_repository, repo); error = git_remote_delete(repo, StringValueCStr(rb_name_or_remote)); rugged_exception_check(error); return Qnil; }