Re-work the checkout API
New API: Repository.head = refname Repository.checkout_head(strategy) Repository.checkout_index(strategy) Repository.checkout_tree(treeish, strategy) Changed API: # Before Repository.checkout(strategy=GIT_CHECKOUT_SAFE_CREATE, reference=None, head=False) # Now Repository.checkout(refname=None, strategy=GIT_CHECKOUT_SAFE_CREATE)
This commit is contained in:
parent
9c0a82876b
commit
974f16ca69
@ -64,3 +64,9 @@ Checkout
|
|||||||
====================
|
====================
|
||||||
|
|
||||||
.. automethod:: pygit2.Repository.checkout
|
.. automethod:: pygit2.Repository.checkout
|
||||||
|
|
||||||
|
Lower level API:
|
||||||
|
|
||||||
|
.. automethod:: pygit2.Repository.checkout_head
|
||||||
|
.. automethod:: pygit2.Repository.checkout_tree
|
||||||
|
.. automethod:: pygit2.Repository.checkout_index
|
||||||
|
@ -31,6 +31,8 @@ from string import hexdigits
|
|||||||
# Import from pygit2
|
# Import from pygit2
|
||||||
from _pygit2 import Repository as _Repository
|
from _pygit2 import Repository as _Repository
|
||||||
from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
|
from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
|
||||||
|
from _pygit2 import GIT_CHECKOUT_SAFE_CREATE
|
||||||
|
from _pygit2 import Reference
|
||||||
|
|
||||||
|
|
||||||
class Repository(_Repository):
|
class Repository(_Repository):
|
||||||
@ -88,3 +90,41 @@ class Repository(_Repository):
|
|||||||
return self.create_reference_direct(name, target, force)
|
return self.create_reference_direct(name, target, force)
|
||||||
|
|
||||||
return self.create_reference_symbolic(name, target, force)
|
return self.create_reference_symbolic(name, target, force)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Checkout
|
||||||
|
#
|
||||||
|
def checkout(self, refname=None, strategy=GIT_CHECKOUT_SAFE_CREATE):
|
||||||
|
"""
|
||||||
|
Checkout the given reference using the given strategy, and update
|
||||||
|
the HEAD.
|
||||||
|
The reference may be a reference name or a Reference object.
|
||||||
|
The default strategy is GIT_CHECKOUT_SAFE_CREATE.
|
||||||
|
|
||||||
|
To checkout from the HEAD, just pass 'HEAD'::
|
||||||
|
|
||||||
|
>>> checkout('HEAD')
|
||||||
|
|
||||||
|
If no reference is given, checkout from the index.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Case 1: Checkout index
|
||||||
|
if refname is None:
|
||||||
|
return self.checkout_index(strategy)
|
||||||
|
|
||||||
|
# Case 2: Checkout head
|
||||||
|
if refname == 'HEAD':
|
||||||
|
return self.checkout_head(strategy)
|
||||||
|
|
||||||
|
# Case 3: Reference
|
||||||
|
if type(refname) is Reference:
|
||||||
|
reference = refname
|
||||||
|
refname = refname.name
|
||||||
|
else:
|
||||||
|
reference = self.lookup_reference(refname)
|
||||||
|
|
||||||
|
oid = reference.resolve().target
|
||||||
|
treeish = self[oid]
|
||||||
|
self.checkout_tree(treeish, strategy)
|
||||||
|
self.head = refname
|
||||||
|
119
src/repository.c
119
src/repository.c
@ -42,6 +42,7 @@ extern PyObject *GitError;
|
|||||||
extern PyTypeObject IndexType;
|
extern PyTypeObject IndexType;
|
||||||
extern PyTypeObject WalkerType;
|
extern PyTypeObject WalkerType;
|
||||||
extern PyTypeObject SignatureType;
|
extern PyTypeObject SignatureType;
|
||||||
|
extern PyTypeObject ObjectType;
|
||||||
extern PyTypeObject TreeType;
|
extern PyTypeObject TreeType;
|
||||||
extern PyTypeObject TreeBuilderType;
|
extern PyTypeObject TreeBuilderType;
|
||||||
extern PyTypeObject ConfigType;
|
extern PyTypeObject ConfigType;
|
||||||
@ -183,6 +184,25 @@ Repository_head__get__(Repository *self)
|
|||||||
return wrap_reference(head);
|
return wrap_reference(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Repository_head__set__(Repository *self, PyObject *py_refname)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const char *refname;
|
||||||
|
|
||||||
|
refname = py_str_to_c_str(py_refname, NULL);
|
||||||
|
if (refname == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
err = git_repository_set_head(self->repo, refname);
|
||||||
|
if (err < 0) {
|
||||||
|
Error_set_str(err, refname);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_head_is_detached__doc__,
|
PyDoc_STRVAR(Repository_head_is_detached__doc__,
|
||||||
"A repository's HEAD is detached when it points directly to a commit\n"
|
"A repository's HEAD is detached when it points directly to a commit\n"
|
||||||
@ -1101,47 +1121,72 @@ Repository_remotes__get__(Repository *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_checkout__doc__,
|
PyDoc_STRVAR(Repository_checkout_head__doc__,
|
||||||
"checkout([strategy:int, reference:Reference])\n"
|
"checkout_head(strategy)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Checks out a tree by a given reference and modifies the HEAD pointer\n"
|
"Checkout the head using the given strategy.");
|
||||||
"Standard checkout strategy is pygit2.GIT_CHECKOUT_SAFE_CREATE\n"
|
|
||||||
"If no reference is given, checkout will use HEAD instead.");
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
Repository_checkout(Repository *self, PyObject *args, PyObject *kw)
|
Repository_checkout_head(Repository *self, PyObject *args)
|
||||||
{
|
{
|
||||||
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||||
unsigned int strategy = GIT_CHECKOUT_SAFE_CREATE;
|
unsigned int strategy;
|
||||||
Reference* ref = NULL;
|
int err;
|
||||||
git_object* object;
|
|
||||||
const git_oid* id;
|
|
||||||
int err, head = 0;
|
|
||||||
|
|
||||||
static char *kwlist[] = {"strategy", "reference", "head", NULL};
|
if (!PyArg_ParseTuple(args, "I", &strategy))
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "|IO!i", kwlist,
|
|
||||||
&strategy, &ReferenceType, &ref, &head))
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (ref != NULL) { /* checkout from treeish */
|
opts.checkout_strategy = strategy;
|
||||||
id = git_reference_target(ref->reference);
|
err = git_checkout_head(self->repo, &opts);
|
||||||
err = git_object_lookup(&object, self->repo, id, GIT_OBJ_COMMIT);
|
if (err < 0)
|
||||||
if (err == GIT_OK) {
|
return Error_set(err);
|
||||||
opts.checkout_strategy = strategy;
|
|
||||||
err = git_checkout_tree(self->repo, object, &opts);
|
|
||||||
if (err == GIT_OK) {
|
|
||||||
err = git_repository_set_head(self->repo,
|
|
||||||
git_reference_name(ref->reference));
|
|
||||||
}
|
|
||||||
git_object_free(object);
|
|
||||||
}
|
|
||||||
} else { /* checkout from head / index */
|
|
||||||
opts.checkout_strategy = strategy;
|
|
||||||
err = (!head) ? git_checkout_index(self->repo, NULL, &opts) :
|
|
||||||
git_checkout_head(self->repo, &opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Repository_checkout_index__doc__,
|
||||||
|
"checkout_index(strategy)\n"
|
||||||
|
"\n"
|
||||||
|
"Checkout the index using the given strategy.");
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
Repository_checkout_index(Repository *self, PyObject *args)
|
||||||
|
{
|
||||||
|
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||||
|
unsigned int strategy;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "I", &strategy))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
opts.checkout_strategy = strategy;
|
||||||
|
err = git_checkout_index(self->repo, NULL, &opts);
|
||||||
|
if (err < 0)
|
||||||
|
return Error_set(err);
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Repository_checkout_tree__doc__,
|
||||||
|
"checkout_tree(treeish, strategy)\n"
|
||||||
|
"\n"
|
||||||
|
"Checkout the given tree, commit or tag, using the given strategy.");
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
Repository_checkout_tree(Repository *self, PyObject *args)
|
||||||
|
{
|
||||||
|
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
|
||||||
|
unsigned int strategy;
|
||||||
|
Object *py_object;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O!I", &ObjectType, &py_object, &strategy))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
opts.checkout_strategy = strategy;
|
||||||
|
err = git_checkout_tree(self->repo, py_object->obj, &opts);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return Error_set(err);
|
return Error_set(err);
|
||||||
|
|
||||||
@ -1152,7 +1197,7 @@ Repository_checkout(Repository *self, PyObject *args, PyObject *kw)
|
|||||||
PyDoc_STRVAR(Repository_notes__doc__, "");
|
PyDoc_STRVAR(Repository_notes__doc__, "");
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
Repository_notes(Repository *self, PyObject* args)
|
Repository_notes(Repository *self, PyObject *args)
|
||||||
{
|
{
|
||||||
NoteIter *iter = NULL;
|
NoteIter *iter = NULL;
|
||||||
char *ref = "refs/notes/commits";
|
char *ref = "refs/notes/commits";
|
||||||
@ -1255,7 +1300,9 @@ PyMethodDef Repository_methods[] = {
|
|||||||
METHOD(Repository, status, METH_NOARGS),
|
METHOD(Repository, status, METH_NOARGS),
|
||||||
METHOD(Repository, status_file, METH_O),
|
METHOD(Repository, status_file, METH_O),
|
||||||
METHOD(Repository, create_remote, METH_VARARGS),
|
METHOD(Repository, create_remote, METH_VARARGS),
|
||||||
METHOD(Repository, checkout, METH_VARARGS|METH_KEYWORDS),
|
METHOD(Repository, checkout_head, METH_VARARGS),
|
||||||
|
METHOD(Repository, checkout_index, METH_VARARGS),
|
||||||
|
METHOD(Repository, checkout_tree, METH_VARARGS),
|
||||||
METHOD(Repository, notes, METH_VARARGS),
|
METHOD(Repository, notes, METH_VARARGS),
|
||||||
METHOD(Repository, create_note, METH_VARARGS),
|
METHOD(Repository, create_note, METH_VARARGS),
|
||||||
METHOD(Repository, lookup_note, METH_VARARGS),
|
METHOD(Repository, lookup_note, METH_VARARGS),
|
||||||
@ -1266,7 +1313,7 @@ PyMethodDef Repository_methods[] = {
|
|||||||
PyGetSetDef Repository_getseters[] = {
|
PyGetSetDef Repository_getseters[] = {
|
||||||
GETTER(Repository, index),
|
GETTER(Repository, index),
|
||||||
GETTER(Repository, path),
|
GETTER(Repository, path),
|
||||||
GETTER(Repository, head),
|
GETSET(Repository, head),
|
||||||
GETTER(Repository, head_is_detached),
|
GETTER(Repository, head_is_detached),
|
||||||
GETTER(Repository, head_is_orphaned),
|
GETTER(Repository, head_is_orphaned),
|
||||||
GETTER(Repository, is_empty),
|
GETTER(Repository, is_empty),
|
||||||
|
@ -34,7 +34,8 @@ extern PyTypeObject ReferenceType;
|
|||||||
|
|
||||||
/* py_str_to_c_str() returns a newly allocated C string holding
|
/* py_str_to_c_str() returns a newly allocated C string holding
|
||||||
* the string contained in the value argument. */
|
* the string contained in the value argument. */
|
||||||
char * py_str_to_c_str(PyObject *value, const char *encoding)
|
char *
|
||||||
|
py_str_to_c_str(PyObject *value, const char *encoding)
|
||||||
{
|
{
|
||||||
char *c_str = NULL;
|
char *c_str = NULL;
|
||||||
/* Case 1: byte string */
|
/* Case 1: byte string */
|
||||||
@ -43,7 +44,6 @@ char * py_str_to_c_str(PyObject *value, const char *encoding)
|
|||||||
|
|
||||||
/* Case 2: text string */
|
/* Case 2: text string */
|
||||||
if (PyUnicode_Check(value)) {
|
if (PyUnicode_Check(value)) {
|
||||||
|
|
||||||
if (encoding == NULL)
|
if (encoding == NULL)
|
||||||
value = PyUnicode_AsUTF8String(value);
|
value = PyUnicode_AsUTF8String(value);
|
||||||
else
|
else
|
||||||
@ -60,6 +60,3 @@ char * py_str_to_c_str(PyObject *value, const char *encoding)
|
|||||||
Py_TYPE(value)->tp_name);
|
Py_TYPE(value)->tp_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,18 +191,17 @@ class RepositoryTest_II(utils.RepoTestCase):
|
|||||||
|
|
||||||
# checkout i18n with conflicts and default strategy should
|
# checkout i18n with conflicts and default strategy should
|
||||||
# not be possible
|
# not be possible
|
||||||
self.assertRaises(pygit2.GitError,
|
self.assertRaises(pygit2.GitError, self.repo.checkout, ref_i18n)
|
||||||
lambda: self.repo.checkout(reference=ref_i18n))
|
|
||||||
|
|
||||||
# checkout i18n with GIT_CHECKOUT_FORCE
|
# checkout i18n with GIT_CHECKOUT_FORCE
|
||||||
head = self.repo.head
|
head = self.repo.head
|
||||||
head = self.repo[head.target]
|
head = self.repo[head.target]
|
||||||
self.assertTrue('new' not in head.tree)
|
self.assertTrue('new' not in head.tree)
|
||||||
self.repo.checkout(pygit2.GIT_CHECKOUT_FORCE, ref_i18n)
|
self.repo.checkout(ref_i18n, pygit2.GIT_CHECKOUT_FORCE)
|
||||||
|
|
||||||
head = self.repo.head
|
head = self.repo.head
|
||||||
head = self.repo[head.target]
|
head = self.repo[head.target]
|
||||||
self.assertEqual(head.hex, self.repo[ref_i18n.target].hex)
|
self.assertEqual(head.hex, ref_i18n.target.hex)
|
||||||
self.assertTrue('new' in head.tree)
|
self.assertTrue('new' in head.tree)
|
||||||
self.assertTrue('bye.txt' not in self.repo.status())
|
self.assertTrue('bye.txt' not in self.repo.status())
|
||||||
|
|
||||||
@ -213,7 +212,7 @@ class RepositoryTest_II(utils.RepoTestCase):
|
|||||||
|
|
||||||
# checkout index
|
# checkout index
|
||||||
self.assertTrue('hello.txt' in self.repo.status())
|
self.assertTrue('hello.txt' in self.repo.status())
|
||||||
self.repo.checkout(pygit2.GIT_CHECKOUT_FORCE)
|
self.repo.checkout(strategy=pygit2.GIT_CHECKOUT_FORCE)
|
||||||
self.assertTrue('hello.txt' not in self.repo.status())
|
self.assertTrue('hello.txt' not in self.repo.status())
|
||||||
|
|
||||||
def test_checkout_head(self):
|
def test_checkout_head(self):
|
||||||
@ -224,16 +223,19 @@ class RepositoryTest_II(utils.RepoTestCase):
|
|||||||
|
|
||||||
# checkout from index should not change anything
|
# checkout from index should not change anything
|
||||||
self.assertTrue('bye.txt' in self.repo.status())
|
self.assertTrue('bye.txt' in self.repo.status())
|
||||||
self.repo.checkout(pygit2.GIT_CHECKOUT_FORCE)
|
self.repo.checkout(strategy=pygit2.GIT_CHECKOUT_FORCE)
|
||||||
self.assertTrue('bye.txt' in self.repo.status())
|
self.assertTrue('bye.txt' in self.repo.status())
|
||||||
|
|
||||||
# checkout from head will reset index as well
|
# checkout from head will reset index as well
|
||||||
self.repo.checkout(pygit2.GIT_CHECKOUT_FORCE, head=True)
|
self.repo.checkout('HEAD', pygit2.GIT_CHECKOUT_FORCE)
|
||||||
self.assertTrue('bye.txt' not in self.repo.status())
|
self.assertTrue('bye.txt' not in self.repo.status())
|
||||||
|
|
||||||
def test_merge_base(self):
|
def test_merge_base(self):
|
||||||
commit = self.repo.merge_base('5ebeeebb320790caf276b9fc8b24546d63316533', '4ec4389a8068641da2d6578db0419484972284c8')
|
commit = self.repo.merge_base(
|
||||||
self.assertEqual(commit.hex, 'acecd5ea2924a4b900e7e149496e1f4b57976e51')
|
'5ebeeebb320790caf276b9fc8b24546d63316533',
|
||||||
|
'4ec4389a8068641da2d6578db0419484972284c8')
|
||||||
|
self.assertEqual(commit.hex,
|
||||||
|
'acecd5ea2924a4b900e7e149496e1f4b57976e51')
|
||||||
|
|
||||||
|
|
||||||
class NewRepositoryTest(utils.NoRepoTestCase):
|
class NewRepositoryTest(utils.NoRepoTestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user