From 1df85d356d7849ae278e5f556a57971def67a63a Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Fri, 29 Nov 2019 13:21:02 +0000 Subject: [PATCH] Add References.compress This exports the functionality of `git_refdb_compress`, which is the equivalent of `git pack-refs --all`. This is useful to improve performance in some contexts on repositories with a large number of refs. --- docs/references.rst | 3 +++ pygit2/repository.py | 3 +++ src/repository.c | 26 ++++++++++++++++++++++++++ test/test_refs.py | 15 +++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/docs/references.rst b/docs/references.rst index 9f9fbe82d..0438f56a4 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -29,6 +29,9 @@ Example:: # Delete a reference >>> repo.references.delete('refs/tags/version1') + # Pack loose references + >>> repo.references.compress() + Functions =================================== diff --git a/pygit2/repository.py b/pygit2/repository.py index 06592426b..6c1eb8e4d 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -1269,6 +1269,9 @@ def __contains__(self, name): def objects(self): return self._repository.listall_reference_objects() + def compress(self): + return self._repository.compress_references() + class Repository(BaseRepository): def __init__(self, path, *args, **kwargs): diff --git a/src/repository.c b/src/repository.c index d1680ee14..af3aaa2e9 100755 --- a/src/repository.c +++ b/src/repository.c @@ -1407,6 +1407,31 @@ Repository_create_reference_symbolic(Repository *self, PyObject *args, return wrap_reference(c_reference, self); } +PyDoc_STRVAR(Repository_compress_references__doc__, + "compress_references()\n" + "\n" + "Suggest that the repository compress or optimize its references.\n" + "This mechanism is implementation-specific. For on-disk reference\n" + "databases, for example, this may pack all loose references."); + +PyObject * +Repository_compress_references(Repository *self) +{ + git_refdb *refdb; + int err; + + err = git_repository_refdb(&refdb, self->repo); + if (err < 0) + return Error_set(err); + + err = git_refdb_compress(refdb); + + git_refdb_free(refdb); + if (err < 0) + return Error_set(err); + Py_RETURN_NONE; +} + PyDoc_STRVAR(Repository_status__doc__, "status() -> {str: int}\n" "\n" @@ -1874,6 +1899,7 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, apply, METH_O), METHOD(Repository, create_reference_direct, METH_VARARGS), METHOD(Repository, create_reference_symbolic, METH_VARARGS), + METHOD(Repository, compress_references, METH_NOARGS), METHOD(Repository, listall_references, METH_NOARGS), METHOD(Repository, listall_reference_objects, METH_NOARGS), METHOD(Repository, listall_submodules, METH_NOARGS), diff --git a/test/test_refs.py b/test/test_refs.py index 958827f01..2349f6ce4 100644 --- a/test/test_refs.py +++ b/test/test_refs.py @@ -25,6 +25,8 @@ """Tests for reference objects.""" +import os + import pytest from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC, Signature @@ -238,6 +240,19 @@ def test_equality(self): assert ref1 != ref3 assert not ref1 == ref3 + def test_compress(self): + repo = self.repo + packed_refs_file = os.path.join(self.repo_path, '.git', 'packed-refs') + assert not os.path.exists(packed_refs_file) + old_refs = [(ref.name, ref.target.hex) + for ref in repo.references.objects] + + repo.references.compress() + assert os.path.exists(packed_refs_file) + new_refs = [(ref.name, ref.target.hex) + for ref in repo.references.objects] + assert old_refs == new_refs + class ReferencesTest(utils.RepoTestCase): def test_list_all_reference_objects(self): repo = self.repo