summaryrefslogtreecommitdiff
path: root/lib/git/refs.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-10-26 10:57:11 +0100
committerSebastian Thiel <byronimo@gmail.com>2009-10-26 10:57:11 +0100
commit9dfd6bcca5499e1cd472c092bc58426e9b72cccc (patch)
tree12f2418d0843460d1d51c346dd35325fabc12a09 /lib/git/refs.py
parentf9cec00938d9059882bb8eabdaf2f775943e00e5 (diff)
parent44a601a068f4f543f73fd9c49e264c931b1e1652 (diff)
downloadgitpython-9dfd6bcca5499e1cd472c092bc58426e9b72cccc.tar.gz
Merge branch 'refs' into index
* refs: Added notes about git-update-ref Refs can now set the reference they are pointing to in a controlled fashion by writing their ref file directly Added TagRefernce creation and deletion including tests Implemented head methods: create, delete, rename, including tests refs: added create, delete and rename methods where appropriate. Tests are marked, implementation is needed for most of them
Diffstat (limited to 'lib/git/refs.py')
-rw-r--r--lib/git/refs.py196
1 files changed, 183 insertions, 13 deletions
diff --git a/lib/git/refs.py b/lib/git/refs.py
index c8857e97..47c37af6 100644
--- a/lib/git/refs.py
+++ b/lib/git/refs.py
@@ -19,7 +19,7 @@ class Reference(LazyMixin, Iterable):
_common_path_default = "refs"
_id_attribute_ = "name"
- def __init__(self, repo, path, object = None):
+ def __init__(self, repo, path):
"""
Initialize this instance
``repo``
@@ -29,16 +29,12 @@ class Reference(LazyMixin, Iterable):
Path relative to the .git/ directory pointing to the ref in question, i.e.
refs/heads/master
- ``object``
- Object instance, will be retrieved on demand if None
"""
if not path.startswith(self._common_path_default):
raise ValueError("Cannot instantiate %s Reference from path %s" % ( self.__class__.__name__, path ))
self.repo = repo
self.path = path
- if object is not None:
- self.object = object
def __str__(self):
return self.name
@@ -69,8 +65,7 @@ class Reference(LazyMixin, Iterable):
return '/'.join(tokens[2:])
- @property
- def object(self):
+ def _get_object(self):
"""
Returns
The object our ref currently refers to. Refs can be cached, they will
@@ -80,17 +75,54 @@ class Reference(LazyMixin, Iterable):
# Our path will be resolved to the hexsha which will be used accordingly
return Object.new(self.repo, self.path)
- @property
- def commit(self):
+ def _set_object(self, ref, type=None):
+ """
+ Set our reference to point to the given ref. It will be converted
+ to a specific hexsha.
+
+ ``type``
+ If not None, string type of that the object must have, other we raise
+ a type error. Only used internally
+
+ Returns
+ Object we have set. This is used internally only to reduce the amount
+ of calls to the git command
+ """
+ obj = Object.new(self.repo, ref)
+ if type is not None and obj.type != type:
+ raise TypeError("Reference %r cannot point to object of type %r" % (self,obj.type))
+
+ full_ref_path = os.path.join(self.repo.path, self.path)
+ fp = open(full_ref_path, "w")
+ try:
+ fp.write(str(obj))
+ finally:
+ fp.close()
+ return obj
+
+ object = property(_get_object, _set_object, doc="Return the object our ref currently refers to")
+
+ def _set_commit(self, commit):
+ """
+ Set ourselves to point to the given commit.
+
+ Raise
+ ValueError if commit does not actually point to a commit
+ """
+ self._set_object(commit, type="commit")
+
+ def _get_commit(self):
"""
Returns
- Commit object the head points to
+ Commit object the reference points to
"""
commit = self.object
if commit.type != "commit":
raise TypeError("Object of reference %s did not point to a commit" % self)
return commit
+ commit = property(_get_commit, _set_commit, doc="Return Commit object the reference points to")
+
@classmethod
def iter_items(cls, repo, common_path = None, **kwargs):
"""
@@ -182,6 +214,7 @@ class Reference(LazyMixin, Iterable):
# obj.size = object_size
# return cls(repo, full_path, obj)
+
class SymbolicReference(object):
"""
@@ -247,7 +280,7 @@ class SymbolicReference(object):
try:
tokens = fp.readline().rstrip().split(' ')
if tokens[0] != 'ref:':
- raise TypeError("%s is a detached symbolic reference as it points to %r" % tokens[0])
+ raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, tokens[0]))
return Reference.from_path(self.repo, tokens[1])
finally:
fp.close()
@@ -384,12 +417,92 @@ class Head(Reference):
"""
_common_path_default = "refs/heads"
+ @classmethod
+ def create(cls, repo, path, commit='HEAD', force=False, **kwargs ):
+ """
+ Create a new head.
+ ``repo``
+ Repository to create the head in
+
+ ``path``
+ The name or path of the head, i.e. 'new_branch' or
+ feature/feature1. The prefix refs/heads is implied.
+
+ ``commit``
+ Commit to which the new head should point, defaults to the
+ current HEAD
+
+ ``force``
+ if True, force creation even if branch with that name already exists.
+
+ ``**kwargs``
+ Additional keyword arguments to be passed to git-branch, i.e.
+ track, no-track, l
+
+ Returns
+ Newly created Head
+
+ Note
+ This does not alter the current HEAD, index or Working Tree
+ """
+ if cls is not Head:
+ raise TypeError("Only Heads can be created explicitly, not objects of type %s" % cls.__name__)
+
+ args = ( path, commit )
+ if force:
+ kwargs['f'] = True
+
+ repo.git.branch(*args, **kwargs)
+ return cls(repo, "%s/%s" % ( cls._common_path_default, path))
+
+
+ @classmethod
+ def delete(cls, repo, *heads, **kwargs):
+ """
+ Delete the given heads
+
+ ``force``
+ If True, the heads will be deleted even if they are not yet merged into
+ the main development stream.
+ Default False
+ """
+ force = kwargs.get("force", False)
+ flag = "-d"
+ if force:
+ flag = "-D"
+ repo.git.branch(flag, *heads)
+
+
+ def rename(self, new_path, force=False):
+ """
+ Rename self to a new path
+
+ ``new_path``
+ Either a simple name or a path, i.e. new_name or features/new_name.
+ The prefix refs/heads is implied
+
+ ``force``
+ If True, the rename will succeed even if a head with the target name
+ already exists.
+
+ Returns
+ self
+ """
+ flag = "-m"
+ if force:
+ flag = "-M"
+
+ self.repo.git.branch(flag, self, new_path)
+ self.path = "%s/%s" % (self._common_path_default, new_path)
+ return self
+
+
class TagReference(Reference):
"""
Class representing a lightweight tag reference which either points to a commit
- or to a tag object. In the latter case additional information, like the signature
- or the tag-creator, is available.
+ ,a tag object or any other object. In the latter case additional information,
+ like the signature or the tag-creator, is available.
This tag object will always point to a commit object, but may carray additional
information in a tag object::
@@ -427,6 +540,52 @@ class TagReference(Reference):
if self.object.type == "tag":
return self.object
return None
+
+ @classmethod
+ def create(cls, repo, path, ref='HEAD', message=None, force=False, **kwargs):
+ """
+ Create a new tag object.
+
+ ``path``
+ The name of the tag, i.e. 1.0 or releases/1.0.
+ The prefix refs/tags is implied
+
+ ``ref``
+ A reference to the object you want to tag. It can be a commit, tree or
+ blob.
+
+ ``message``
+ If not None, the message will be used in your tag object. This will also
+ create an additional tag object that allows to obtain that information, i.e.::
+ tagref.tag.message
+
+ ``force``
+ If True, to force creation of a tag even though that tag already exists.
+
+ ``**kwargs``
+ Additional keyword arguments to be passed to git-tag
+
+ Returns
+ A new TagReference
+ """
+ args = ( path, ref )
+ if message:
+ kwargs['m'] = message
+ if force:
+ kwargs['f'] = True
+
+ repo.git.tag(*args, **kwargs)
+ return TagReference(repo, "%s/%s" % (cls._common_path_default, path))
+
+ @classmethod
+ def delete(cls, repo, *tags):
+ """
+ Delete the given existing tag or tags
+ """
+ repo.git.tag("-d", *tags)
+
+
+
# provide an alias
@@ -460,3 +619,14 @@ class RemoteReference(Head):
"""
tokens = self.path.split('/')
return '/'.join(tokens[3:])
+
+ @classmethod
+ def delete(cls, repo, *remotes, **kwargs):
+ """
+ Delete the given remote references.
+
+ Note
+ kwargs are given for compatability with the base class method as we
+ should not narrow the signature.
+ """
+ repo.git.branch("-d", "-r", *remotes)