From dec4663129f72321a14efd6de63f14a7419e3ed2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 23 Nov 2010 09:14:17 +0100 Subject: Split ref implementation up into multiple files, to make room for the log implementation --- refs/reference.py | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 refs/reference.py (limited to 'refs/reference.py') diff --git a/refs/reference.py b/refs/reference.py new file mode 100644 index 00000000..1f97b92e --- /dev/null +++ b/refs/reference.py @@ -0,0 +1,111 @@ +from symbolic import SymbolicReference +import os +from git.util import ( + LazyMixin, + Iterable, + ) + +from gitdb.util import ( + isfile, + hex_to_bin + ) + +__all__ = ["Reference"] + + +class Reference(SymbolicReference, LazyMixin, Iterable): + """Represents a named reference to any object. Subclasses may apply restrictions though, + i.e. Heads can only point to commits.""" + __slots__ = tuple() + _common_path_default = "refs" + + def __init__(self, repo, path): + """Initialize this instance + :param repo: Our parent repository + + :param path: + Path relative to the .git/ directory pointing to the ref in question, i.e. + refs/heads/master""" + if not path.startswith(self._common_path_default+'/'): + raise ValueError("Cannot instantiate %r from path %s" % ( self.__class__.__name__, path )) + super(Reference, self).__init__(repo, path) + + + def __str__(self): + return self.name + + def _get_object(self): + """ + :return: + The object our ref currently refers to. Refs can be cached, they will + always point to the actual object as it gets re-created on each query""" + # have to be dynamic here as we may be a tag which can point to anything + # Our path will be resolved to the hexsha which will be used accordingly + return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path))) + + def _set_object(self, ref): + """ + Set our reference to point to the given ref. It will be converted + to a specific hexsha. + If the reference does not exist, it will be created. + + :note: + TypeChecking is done by the git command""" + abs_path = self._abs_path() + existed = True + if not isfile(abs_path): + existed = False + open(abs_path, 'wb').write(Object.NULL_HEX_SHA) + # END quick create + + # do it safely by specifying the old value + try: + self.repo.git.update_ref(self.path, ref, (existed and self._get_object().hexsha) or None) + except: + if not existed: + os.remove(abs_path) + # END remove file on error if it didn't exist before + raise + # END exception handling + + object = property(_get_object, _set_object, doc="Return the object our ref currently refers to") + + @property + def name(self): + """:return: (shortest) Name of this reference - it may contain path components""" + # first two path tokens are can be removed as they are + # refs/heads or refs/tags or refs/remotes + tokens = self.path.split('/') + if len(tokens) < 3: + return self.path # could be refs/HEAD + return '/'.join(tokens[2:]) + + + @classmethod + def create(cls, repo, path, commit='HEAD', force=False ): + """Create a new reference. + + :param repo: Repository to create the reference in + :param path: + The relative path of the reference, i.e. 'new_branch' or + feature/feature1. The path prefix 'refs/' is implied if not + given explicitly + + :param commit: + Commit to which the new reference should point, defaults to the + current HEAD + + :param force: + if True, force creation even if a reference with that name already exists. + Raise OSError otherwise + + :return: Newly created Reference + + :note: This does not alter the current HEAD, index or Working Tree""" + return cls._create(repo, path, True, commit, force) + + @classmethod + def iter_items(cls, repo, common_path = None): + """Equivalent to SymbolicReference.iter_items, but will return non-detached + references as well.""" + return cls._iter_items(repo, common_path) -- cgit v1.2.1