@@ -51,7 +51,7 @@ def name(self):
5151 """
5252 return self .path
5353
54- def _get_path (self ):
54+ def _abs_path (self ):
5555 return join_path_native (self .repo .git_dir , self .path )
5656
5757 @classmethod
@@ -97,7 +97,7 @@ def _get_ref_info(self):
9797 point to, or None"""
9898 tokens = None
9999 try :
100- fp = open (self ._get_path (), 'r' )
100+ fp = open (self ._abs_path (), 'r' )
101101 value = fp .read ().rstrip ()
102102 fp .close ()
103103 tokens = value .split (" " )
@@ -143,8 +143,15 @@ def _get_commit(self):
143143 def _set_commit (self , commit ):
144144 """
145145 Set our commit, possibly dereference our symbolic reference first.
146+ If the reference does not exist, it will be created
146147 """
147- if self .is_detached :
148+ is_detached = True
149+ try :
150+ is_detached = self .is_detached
151+ except ValueError :
152+ pass
153+ # END handle non-existing ones
154+ if is_detached :
148155 return self ._set_reference (commit )
149156
150157 # set the commit on our reference
@@ -197,7 +204,7 @@ def _set_reference(self, ref):
197204 return
198205 # END non-detached handling
199206
200- path = self ._get_path ()
207+ path = self ._abs_path ()
201208 directory = os .path .dirname (path )
202209 if not os .path .isdir (directory ):
203210 os .makedirs (directory )
@@ -533,12 +540,28 @@ def _set_object(self, ref):
533540 """
534541 Set our reference to point to the given ref. It will be converted
535542 to a specific hexsha.
543+ If the reference does not exist, it will be created.
536544
537545 Note:
538546 TypeChecking is done by the git command
539547 """
548+ # check for existence, touch it if required
549+ abs_path = self ._abs_path ()
550+ existed = True
551+ if not os .path .isfile (abs_path ):
552+ existed = False
553+ open (abs_path , 'wb' ).write (Object .NULL_HEX_SHA )
554+ # END quick create
555+
540556 # do it safely by specifying the old value
541- self .repo .git .update_ref (self .path , ref , self ._get_object ().sha )
557+ try :
558+ self .repo .git .update_ref (self .path , ref , (existed and self ._get_object ().sha ) or None )
559+ except :
560+ if not existed :
561+ os .remove (abs_path )
562+ # END remove file on error if it didn't exist before
563+ raise
564+ # END exception handling
542565
543566 object = property (_get_object , _set_object , doc = "Return the object our ref currently refers to" )
544567
@@ -813,11 +836,12 @@ def commit(self):
813836 Returns
814837 Commit object the tag ref points to
815838 """
816- if self .object .type == "commit" :
817- return self .object
818- elif self .object .type == "tag" :
839+ obj = self .object
840+ if obj .type == "commit" :
841+ return obj
842+ elif obj .type == "tag" :
819843 # it is a tag object which carries the commit as an object - we can point to anything
820- return self . object .object
844+ return obj .object
821845 else :
822846 raise ValueError ( "Tag %s points to a Blob or Tree - have never seen that before" % self )
823847
@@ -828,10 +852,15 @@ def tag(self):
828852 Tag object this tag ref points to or None in case
829853 we are a light weight tag
830854 """
831- if self .object .type == "tag" :
832- return self .object
855+ obj = self .object
856+ if obj .type == "tag" :
857+ return obj
833858 return None
834859
860+ # make object read-only
861+ # It should be reasonably hard to adjust an existing tag
862+ object = property (Reference ._get_object )
863+
835864 @classmethod
836865 def create (cls , repo , path , ref = 'HEAD' , message = None , force = False , ** kwargs ):
837866 """
0 commit comments