Skip to content

Commit

Permalink
Add References.compress
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
cjwatson committed Nov 29, 2019
1 parent d2b0ced commit 1df85d3
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Example::
# Delete a reference
>>> repo.references.delete('refs/tags/version1')

# Pack loose references
>>> repo.references.compress()


Functions
===================================
Expand Down
3 changes: 3 additions & 0 deletions pygit2/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
26 changes: 26 additions & 0 deletions src/repository.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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),
Expand Down
15 changes: 15 additions & 0 deletions test/test_refs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

"""Tests for reference objects."""

import os

import pytest

from pygit2 import GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 1df85d3

Please sign in to comment.