Repository: make head read-only and introduce set_head()
Following from the previous commits, make 'head' read-only and provide a method to update head while providing a message. The checkout() codepath which switches branches has been updated to provide a reflog entry which mimics git's.
This commit is contained in:
@@ -30,6 +30,13 @@ typedef struct git_strarray {
|
||||
|
||||
typedef int64_t git_off_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_REF_INVALID = 0,
|
||||
GIT_REF_OID = 1,
|
||||
GIT_REF_SYMBOLIC = 2,
|
||||
GIT_REF_LISTALL = 3,
|
||||
} git_ref_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_OK = 0,
|
||||
GIT_ERROR = -1,
|
||||
@@ -450,6 +457,9 @@ int git_repository_init_ext(
|
||||
const char *repo_path,
|
||||
git_repository_init_options *opts);
|
||||
|
||||
int git_repository_set_head(git_repository *repo, const char *refname, const git_signature *signature, const char *log_message);
|
||||
int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish, const git_signature *signature, const char *log_message);
|
||||
|
||||
/*
|
||||
* git_index
|
||||
*/
|
||||
|
@@ -274,7 +274,57 @@ class Repository(_Repository):
|
||||
oid = reference.resolve().target
|
||||
treeish = self[oid]
|
||||
self.checkout_tree(treeish, **kwargs)
|
||||
self.head = refname
|
||||
head = self.lookup_reference('HEAD')
|
||||
if head.type == C.GIT_REF_SYMBOLIC:
|
||||
from_ = self.head.shorthand
|
||||
else:
|
||||
from_ = head.target.hex
|
||||
|
||||
try:
|
||||
signature = self.default_signature
|
||||
except:
|
||||
signature = None
|
||||
|
||||
reflog_text = "checkout: moving from %s to %s" % (from_, reference)
|
||||
self.set_head(refname, signature, reflog_text)
|
||||
|
||||
#
|
||||
# Setting HEAD
|
||||
#
|
||||
def set_head(self, target, signature=None, message=None):
|
||||
"""Set HEAD to point to the given target
|
||||
|
||||
Arguments:
|
||||
|
||||
target
|
||||
The new target for HEAD. Can be a string or Oid (to detach)
|
||||
|
||||
signature
|
||||
Signature to use for the reflog. If not provided, the repository's
|
||||
default will be used
|
||||
|
||||
message
|
||||
Message to use for the reflog
|
||||
"""
|
||||
|
||||
sig_ptr = ffi.new('git_signature **')
|
||||
if signature:
|
||||
ffi.buffer(sig_ptr)[:] = signature._pointer[:]
|
||||
|
||||
message_ptr = ffi.NULL
|
||||
if message_ptr:
|
||||
message_ptr = to_bytes(message)
|
||||
|
||||
if isinstance(target, Oid):
|
||||
oid = ffi.new('git_oid *')
|
||||
ffi.buffer(oid)[:] = target.raw[:]
|
||||
err = C.git_repository_set_head_detached(self._repo, oid, sig_ptr[0], message_ptr)
|
||||
check_error(err)
|
||||
return
|
||||
|
||||
# if it's a string, then it's a reference name
|
||||
err = C.git_repository_set_head(self._repo, to_bytes(target), sig_ptr[0], message_ptr)
|
||||
check_error(err)
|
||||
|
||||
#
|
||||
# Diff
|
||||
|
@@ -178,38 +178,6 @@ Repository_head__get__(Repository *self)
|
||||
return wrap_reference(head, self);
|
||||
}
|
||||
|
||||
int
|
||||
Repository_head__set__(Repository *self, PyObject *py_val)
|
||||
{
|
||||
int err;
|
||||
if (PyObject_TypeCheck(py_val, &OidType)) {
|
||||
git_oid oid;
|
||||
py_oid_to_git_oid(py_val, &oid);
|
||||
err = git_repository_set_head_detached(self->repo, &oid, NULL, NULL);
|
||||
if (err < 0) {
|
||||
Error_set(err);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const char *refname;
|
||||
PyObject *trefname;
|
||||
|
||||
refname = py_str_borrow_c_str(&trefname, py_val, NULL);
|
||||
if (refname == NULL)
|
||||
return -1;
|
||||
|
||||
err = git_repository_set_head(self->repo, refname, NULL, NULL);
|
||||
Py_DECREF(trefname);
|
||||
if (err < 0) {
|
||||
Error_set_str(err, refname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_head_is_detached__doc__,
|
||||
"A repository's HEAD is detached when it points directly to a commit\n"
|
||||
"instead of a branch.");
|
||||
@@ -1514,7 +1482,7 @@ PyMethodDef Repository_methods[] = {
|
||||
|
||||
PyGetSetDef Repository_getseters[] = {
|
||||
GETTER(Repository, path),
|
||||
GETSET(Repository, head),
|
||||
GETTER(Repository, head),
|
||||
GETTER(Repository, head_is_detached),
|
||||
GETTER(Repository, head_is_unborn),
|
||||
GETTER(Repository, is_empty),
|
||||
|
@@ -76,10 +76,10 @@ class RepositoryTest(utils.BareRepoTestCase):
|
||||
|
||||
def test_set_head(self):
|
||||
# Test setting a detatched HEAD.
|
||||
self.repo.head = Oid(hex=PARENT_SHA)
|
||||
self.repo.set_head(Oid(hex=PARENT_SHA))
|
||||
self.assertEqual(self.repo.head.target.hex, PARENT_SHA)
|
||||
# And test setting a normal HEAD.
|
||||
self.repo.head = "refs/heads/master"
|
||||
self.repo.set_head("refs/heads/master")
|
||||
self.assertEqual(self.repo.head.name, "refs/heads/master")
|
||||
self.assertEqual(self.repo.head.target.hex, HEAD_SHA)
|
||||
|
||||
|
Reference in New Issue
Block a user