int git_branch_tracking( git_reference **tracking_out, git_reference *branch) { const char *remote_name, *merge_name; git_buf buf = GIT_BUF_INIT; int error = -1; git_remote *remote = NULL; const git_refspec *refspec; assert(tracking_out && branch); if (!git_reference_is_branch(branch)) return not_a_local_branch(branch); if ((error = retrieve_tracking_configuration(&remote_name, branch, "branch.%s.remote")) < 0) goto cleanup; if ((error = retrieve_tracking_configuration(&merge_name, branch, "branch.%s.merge")) < 0) goto cleanup; if (strcmp(".", remote_name) != 0) { if ((error = git_remote_load(&remote, git_reference_owner(branch), remote_name)) < 0) goto cleanup; refspec = git_remote_fetchspec(remote); if (refspec == NULL || refspec->src == NULL || refspec->dst == NULL) { error = GIT_ENOTFOUND; goto cleanup; } if (git_refspec_transform_r(&buf, refspec, merge_name) < 0) goto cleanup; } else if (git_buf_sets(&buf, merge_name) < 0) goto cleanup; error = git_reference_lookup( tracking_out, git_reference_owner(branch), git_buf_cstr(&buf)); cleanup: git_remote_free(remote); git_buf_free(&buf); return error; }
/* * call-seq: * reference.log -> [reflog_entry, ...] * * Return an array with the log of all modifications to this reference * * Each +reflog_entry+ is a hash with the following keys: * * - +:id_old+: previous OID before the change * - +:id_new+: OID after the change * - +:committer+: author of the change * - +:message+: message for the change * * Example: * * reference.log #=> [ * # { * # :id_old => nil, * # :id_new => '9d09060c850defbc7711d08b57def0d14e742f4e', * # :committer => {:name => 'Vicent Marti', :email => {'*****@*****.**'}}, * # :message => 'created reference' * # }, ... ] */ static VALUE rb_git_reflog(VALUE self) { git_reflog *reflog; git_reference *ref; int error; VALUE rb_log; size_t i, ref_count; Data_Get_Struct(self, git_reference, ref); error = git_reflog_read(&reflog, git_reference_owner(ref), git_reference_name(ref)); rugged_exception_check(error); ref_count = git_reflog_entrycount(reflog); rb_log = rb_ary_new2(ref_count); for (i = 0; i < ref_count; ++i) { const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, ref_count - i - 1); rb_ary_push(rb_log, reflog_entry_new(entry)); } git_reflog_free(reflog); return rb_log; }
/** * ggit_ref_get_log: * @ref: a #GgitRef. * @error: a #GError for error reporting, or %NULL. * * Gets the #GgitReflog for @ref. The reflog will be created if it doesn't exist * yet. * * Returns: (transfer full): the reflog. */ GgitReflog * ggit_ref_get_log (GgitRef *ref, GError **error) { git_reflog *reflog; git_reference *nref; gint ret; g_return_val_if_fail (GGIT_IS_REF (ref), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); nref = _ggit_native_get (ref); ret = git_reflog_read (&reflog, git_reference_owner (nref), git_reference_name (nref)); if (ret != GIT_OK) { _ggit_error_set (error, ret); return NULL; } return _ggit_reflog_wrap (ref, reflog); }
int Reference_oid__set__(Reference *self, PyObject *py_hex) { git_oid oid; int err; git_reference *new_ref; CHECK_REFERENCE_INT(self); /* Get the oid */ err = py_str_to_git_oid_expand(git_reference_owner(self->reference), py_hex, &oid); if (err < 0) { Error_set(err); return -1; } /* Set the oid */ err = git_reference_set_target(&new_ref, self->reference, &oid); if (err < 0) { Error_set(err); return -1; } git_reference_free(self->reference); self->reference = new_ref; return 0; }
int git_branch_is_head( git_reference *branch) { git_reference *head; bool is_same = false; int error; assert(branch); if (!git_reference_is_branch(branch)) return false; error = git_repository_head(&head, git_reference_owner(branch)); if (error == GIT_EORPHANEDHEAD) return false; if (error < 0) return -1; is_same = strcmp( git_reference_name(branch), git_reference_name(head)) == 0; git_reference_free(head); return is_same; }
static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, const git_signature *signature, const char *message) { git_refname_t normalized; bool should_head_be_updated = false; int error = 0; assert(ref && new_name && signature); if ((error = reference_normalize_for_repo( normalized, git_reference_owner(ref), new_name)) < 0) return error; /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) return error; should_head_be_updated = (error > 0); if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0) return error; /* Update HEAD it was pointing to the reference being renamed */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, normalized)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); return error; } return 0; }
/** * ggit_reflog_rename: * @reflog: a #GgitReflog. * @new_name: the new name of the reference. * @error: a #GError for error reporting, or %NULL. * * Renames the reflog for to @new_name, on error @error is set. */ gboolean ggit_reflog_rename (GgitReflog *reflog, const gchar *new_name, GError **error) { git_reference *nref; gint ret; g_return_val_if_fail (reflog != NULL, FALSE); g_return_val_if_fail (new_name != NULL && *new_name != '\0', FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); nref = _ggit_native_get (reflog->ref); ret = git_reflog_rename (git_reference_owner (nref), git_reference_name (nref), new_name); if (ret != GIT_OK) { _ggit_error_set (error, ret); return FALSE; } return TRUE; }
int git_branch_is_head( const git_reference *branch) { git_reference *head; bool is_same = false; int error; assert(branch); if (!git_reference_is_branch(branch)) return false; error = git_repository_head(&head, git_reference_owner(branch)); if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND) return false; if (error < 0) return -1; is_same = strcmp( git_reference_name(branch), git_reference_name(head)) == 0; git_reference_free(head); return is_same; }
/** * ggit_ref_get_owner: * @ref: a #GgitRef. * * Gets the repository where @ref resides. * * Returns: (transfer full): the repository where a reference resides. */ GgitRepository * ggit_ref_get_owner (GgitRef *ref) { g_return_val_if_fail (ref != NULL, NULL); return _ggit_repository_wrap (git_reference_owner (_ggit_native_get (ref)), FALSE); }
int git_reference_peel( git_object **peeled, git_reference *ref, git_otype target_type) { git_reference *resolved = NULL; git_object *target = NULL; int error; assert(ref); if (ref->type == GIT_REF_OID) { resolved = ref; } else { if ((error = git_reference_resolve(&resolved, ref)) < 0) return peel_error(error, ref, "Cannot resolve reference"); } if (!git_oid_iszero(&resolved->peel)) { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->peel, GIT_OBJ_ANY); } else { error = git_object_lookup(&target, git_reference_owner(ref), &resolved->target.oid, GIT_OBJ_ANY); } if (error < 0) { peel_error(error, ref, "Cannot retrieve reference target"); goto cleanup; } if (target_type == GIT_OBJ_ANY && git_object_type(target) != GIT_OBJ_TAG) error = git_object_dup(peeled, target); else error = git_object_peel(peeled, target, target_type); cleanup: git_object_free(target); if (resolved != ref) git_reference_free(resolved); return error; }
int git_branch_upstream( git_reference **tracking_out, const git_reference *branch) { int error; git_buf tracking_name = GIT_BUF_INIT; if ((error = git_branch_upstream_name(&tracking_name, git_reference_owner(branch), git_reference_name(branch))) < 0) return error; error = git_reference_lookup( tracking_out, git_reference_owner(branch), git_buf_cstr(&tracking_name)); git_buf_free(&tracking_name); return error; }
/* * call-seq: * reference.log? -> true or false * * Return +true+ if the reference has a reflog, +false+ otherwise. */ static VALUE rb_git_has_reflog(VALUE self) { git_reference *ref; git_repository *repo; Data_Get_Struct(self, git_reference, ref); repo = git_reference_owner(ref); return git_reference_has_log(repo, git_reference_name(ref)) ? Qtrue : Qfalse; }
/** * ggit_ref_has_log: * @ref: a #GgitRef. * * Get whether @ref has an existing log. * * Returns: %TRUE if @ref has a log, %FALSE otherwise. * **/ gboolean ggit_ref_has_log (GgitRef *ref) { git_reference *nref; g_return_val_if_fail (GGIT_IS_REF (ref), FALSE); nref = _ggit_native_get (ref); return git_reference_has_log (git_reference_owner (nref), git_reference_name (nref)) == 1; }
static int retrieve_oid_from_reflog(git_oid *oid, git_reference *ref, size_t identifier) { git_reflog *reflog; int error = -1; size_t numentries; const git_reflog_entry *entry; bool search_by_pos = (identifier <= 100000000); if (git_reflog_read(&reflog, git_reference_owner(ref), git_reference_name(ref)) < 0) return -1; numentries = git_reflog_entrycount(reflog); if (search_by_pos) { if (numentries < identifier + 1) { giterr_set( GITERR_REFERENCE, "Reflog for '%s' has only %"PRIuZ" entries, asked for %"PRIuZ, git_reference_name(ref), numentries, identifier); error = GIT_ENOTFOUND; goto cleanup; } entry = git_reflog_entry_byindex(reflog, identifier); git_oid_cpy(oid, git_reflog_entry_id_new(entry)); error = 0; goto cleanup; } else { size_t i; git_time commit_time; for (i = 0; i < numentries; i++) { entry = git_reflog_entry_byindex(reflog, i); commit_time = git_reflog_entry_committer(entry)->when; if (commit_time.time > (git_time_t)identifier) continue; git_oid_cpy(oid, git_reflog_entry_id_new(entry)); error = 0; goto cleanup; } error = GIT_ENOTFOUND; } cleanup: git_reflog_free(reflog); return error; }
/* * 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); } }
int git_branch_move( git_reference **out, git_reference *branch, const char *new_branch_name, int force) { git_buf new_reference_name = GIT_BUF_INIT, old_config_section = GIT_BUF_INIT, new_config_section = GIT_BUF_INIT, log_message = GIT_BUF_INIT; int error; assert(branch && new_branch_name); if (!git_reference_is_branch(branch)) return not_a_local_branch(git_reference_name(branch)); if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) goto done; if ((error = git_buf_printf(&log_message, "branch: renamed %s to %s", git_reference_name(branch), git_buf_cstr(&new_reference_name))) < 0) goto done; /* first update ref then config so failure won't trash config */ error = git_reference_rename( out, branch, git_buf_cstr(&new_reference_name), force, git_buf_cstr(&log_message)); if (error < 0) goto done; git_buf_join(&old_config_section, '.', "branch", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)); git_buf_join(&new_config_section, '.', "branch", new_branch_name); error = git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&old_config_section), git_buf_cstr(&new_config_section)); done: git_buf_free(&new_reference_name); git_buf_free(&old_config_section); git_buf_free(&new_config_section); git_buf_free(&log_message); return error; }
int git_reference_rename( git_reference **out, git_reference *ref, const char *new_name, int force) { unsigned int normalization_flags; char normalized[GIT_REFNAME_MAX]; bool should_head_be_updated = false; int error = 0; int reference_has_log; normalization_flags = ref->type == GIT_REF_SYMBOLIC ? GIT_REF_FORMAT_ALLOW_ONELEVEL : GIT_REF_FORMAT_NORMAL; if ((error = git_reference_normalize_name( normalized, sizeof(normalized), new_name, normalization_flags)) < 0) return error; /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) return error; should_head_be_updated = (error > 0); if ((error = git_refdb_rename(out, ref->db, ref->name, new_name, force)) < 0) return error; /* Update HEAD it was poiting to the reference being renamed. */ if (should_head_be_updated && (error = git_repository_set_head(ref->db->repo, new_name)) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); return error; } /* Rename the reflog file, if it exists. */ reference_has_log = git_reference_has_log(ref); if (reference_has_log < 0) return reference_has_log; if (reference_has_log && (error = git_reflog_rename(git_reference_owner(ref), git_reference_name(ref), new_name)) < 0) return error; return 0; }
static int retrieve_tracking_configuration( const char **out, git_reference *branch, const char *format) { git_config *config; git_buf buf = GIT_BUF_INIT; int error; if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; if (git_buf_printf(&buf, format, git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) return -1; error = git_config_get_string(out, config, git_buf_cstr(&buf)); git_buf_free(&buf); return error; }
int reference_is_packed(git_reference *ref) { git_buf ref_path = GIT_BUF_INIT; int packed; assert(ref); if (git_buf_joinpath(&ref_path, git_repository_path(git_reference_owner(ref)), git_reference_name(ref)) < 0) return -1; packed = !git_path_isfile(ref_path.ptr); git_buf_free(&ref_path); return packed; }
int git_branch_move( git_reference *branch, const char *new_branch_name, int force) { git_buf new_reference_name = GIT_BUF_INIT, old_config_section = GIT_BUF_INIT, new_config_section = GIT_BUF_INIT; int error; assert(branch && new_branch_name); if (!git_reference_is_branch(branch)) return not_a_local_branch(branch); if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0) goto cleanup; if (git_buf_printf( &old_config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto cleanup; if ((error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force)) < 0) goto cleanup; if (git_buf_printf(&new_config_section, "branch.%s", new_branch_name) < 0) goto cleanup; if ((error = git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&old_config_section), git_buf_cstr(&new_config_section))) < 0) goto cleanup; cleanup: git_buf_free(&new_reference_name); git_buf_free(&old_config_section); git_buf_free(&new_config_section); return error; }
/** * ggit_ref_delete_log: * @ref: a #GgitRef. * @error: a #GError for error reporting, or %NULL. * * Deletes the log for @ref, on error @error is set. */ void ggit_ref_delete_log (GgitRef *ref, GError **error) { git_reference *nref; gint ret; g_return_if_fail (GGIT_IS_REF (ref)); g_return_if_fail (error == NULL || *error == NULL); nref = _ggit_native_get (ref); ret = git_reflog_delete (git_reference_owner (nref), git_reference_name (nref)); if (ret != GIT_OK) { _ggit_error_set (error, ret); } }
int git_branch_delete(git_reference *branch) { int is_head; git_buf config_section = GIT_BUF_INIT; int error = -1; assert(branch); if (!git_reference_is_branch(branch) && !git_reference_is_remote(branch)) { giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch)); return -1; } if ((is_head = git_branch_is_head(branch)) < 0) return is_head; if (is_head) { giterr_set(GITERR_REFERENCE, "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch)); return -1; } if (git_buf_printf(&config_section, "branch.%s", git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0) goto on_error; if (git_config_rename_section( git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0) goto on_error; if (git_reference_delete(branch) < 0) goto on_error; error = 0; on_error: git_buf_free(&config_section); return error; }
PyObject * Reference_log(Reference *self) { int err; RefLogIter *iter; git_repository *repo; CHECK_REFERENCE(self); repo = git_reference_owner(self->reference); iter = PyObject_New(RefLogIter, &RefLogIterType); if (iter != NULL) { err = git_reflog_read(&iter->reflog, repo, git_reference_name(self->reference)); if (err < 0) return Error_set(err); iter->size = git_reflog_entrycount(iter->reflog); iter->i = 0; } return (PyObject*)iter; }
static int reference__rename(git_reference **out, git_reference *ref, const char *new_name, int force, const git_signature *signature, const char *message) { git_repository *repo; git_refname_t normalized; bool should_head_be_updated = false; int error = 0; assert(ref && new_name && signature); repo = git_reference_owner(ref); if ((error = reference_normalize_for_repo( normalized, repo, new_name, true)) < 0) return error; /* Check if we have to update HEAD. */ if ((error = git_branch_is_head(ref)) < 0) return error; should_head_be_updated = (error > 0); if ((error = git_refdb_rename(out, ref->db, ref->name, normalized, force, signature, message)) < 0) return error; /* Update HEAD if it was pointing to the reference being renamed */ if (should_head_be_updated) { error = git_repository_set_head(ref->db->repo, normalized); } else { rename_cb_data payload; payload.old_name = ref->name; memcpy(&payload.new_name, &normalized, sizeof(normalized)); error = git_repository_foreach_head(repo, update_wt_heads, &payload); } return error; }
/** * ggit_ref_lookup: * @ref: a #GgitRef. * @error: a #GError for error reporting, or %NULL. * * Convenient method to resolve a reference to an object. * * Returns: (transfer full): a #GgitObject. * **/ GgitObject * ggit_ref_lookup (GgitRef *ref, GError **error) { git_object *obj; git_reference *r; gint ret; GgitRef *lref; g_return_val_if_fail (GGIT_IS_REF (ref), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); lref = ggit_ref_resolve (ref, error); if (lref == NULL) { return NULL; } r = _ggit_native_get (lref); ret = git_object_lookup (&obj, git_reference_owner (r), git_reference_target (r), GIT_OBJ_ANY); g_object_unref (lref); if (ret != GIT_OK) { _ggit_error_set (error, ret); return NULL; } return ggit_utils_create_real_object (obj, TRUE); }
int git_branch_set_upstream(git_reference *branch, const char *upstream_name) { git_buf key = GIT_BUF_INIT, value = GIT_BUF_INIT; git_reference *upstream; git_repository *repo; git_remote *remote = NULL; git_config *config; const char *name, *shortname; int local, error; const git_refspec *fetchspec; name = git_reference_name(branch); if (!git_reference__is_branch(name)) return not_a_local_branch(name); if (git_repository_config__weakptr(&config, git_reference_owner(branch)) < 0) return -1; shortname = name + strlen(GIT_REFS_HEADS_DIR); if (upstream_name == NULL) return unset_upstream(config, shortname); repo = git_reference_owner(branch); /* First we need to figure out whether it's a branch or remote-tracking */ if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_LOCAL) == 0) local = 1; else if (git_branch_lookup(&upstream, repo, upstream_name, GIT_BRANCH_REMOTE) == 0) local = 0; else { giterr_set(GITERR_REFERENCE, "Cannot set upstream for branch '%s'", shortname); return GIT_ENOTFOUND; } /* * If it's local, the remote is "." and the branch name is * simply the refname. Otherwise we need to figure out what * the remote-tracking branch's name on the remote is and use * that. */ if (local) error = git_buf_puts(&value, "."); else error = git_branch_remote_name(&value, repo, git_reference_name(upstream)); if (error < 0) goto on_error; if (git_buf_printf(&key, "branch.%s.remote", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; if (local) { git_buf_clear(&value); if (git_buf_puts(&value, git_reference_name(upstream)) < 0) goto on_error; } else { /* Get the remoe-tracking branch's refname in its repo */ if (git_remote_lookup(&remote, repo, git_buf_cstr(&value)) < 0) goto on_error; fetchspec = git_remote__matching_dst_refspec(remote, git_reference_name(upstream)); git_buf_clear(&value); if (!fetchspec || git_refspec_rtransform(&value, fetchspec, git_reference_name(upstream)) < 0) goto on_error; git_remote_free(remote); remote = NULL; } git_buf_clear(&key); if (git_buf_printf(&key, "branch.%s.merge", shortname) < 0) goto on_error; if (git_config_set_string(config, git_buf_cstr(&key), git_buf_cstr(&value)) < 0) goto on_error; git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); return 0; on_error: git_reference_free(upstream); git_buf_free(&key); git_buf_free(&value); git_remote_free(remote); return -1; }
Repository Reference::owner() const { return Repository(git_reference_owner(d.data())); }