Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit58e2157

Browse files
committed
Added SymbolicReference and HEAD type to better represent these special types of references and allow special handling
Head.reset now is an instance method of HEAD typeConcatenated all reference specific tests into test_refsstarted to fix tests breaking now because of changed interface
1 parentb2a14e4 commit58e2157

File tree

9 files changed

+239
-154
lines changed

9 files changed

+239
-154
lines changed

‎CHANGES‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,12 @@ Index
8787
* A new Index class allows to read and write index files directly, and to perform
8888
simple two and three way merges based on an arbitrary index.
8989

90-
Refs
91-
----
92-
* Will dynmically retrieve their object at the time of query to assure the information
90+
Referernces
91+
------------
92+
* References are object that point to a Commit
93+
* SymbolicReference are a pointer to a Reference Object, which itself points to a specific
94+
Commit
95+
* They will dynmically retrieve their object at the time of query to assure the information
9396
is actual. Recently objects would be cached, hence ref object not be safely kept
9497
persistent.
9598

‎TODO‎

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,12 @@ Index
5858
creating several tree objects, so in the end it might be slower.
5959
Hmm, probably its okay to use the command unless we go c(++)
6060

61-
62-
Head.reset
63-
----------
64-
* Should better be an instance method. Problem was that there is no class specifying
65-
the HEAD - in a way reset would always effect the active branch.
66-
Probably it would be okay to have a special type called SymbolicReference
67-
which represents items like HEAD. These could naturally carry the reset
68-
instance method.
61+
Refs
62+
-----
63+
* If the HEAD is detached as it points to a specific commit, its not technically
64+
a symbolic reference anymore. Currently, we cannot handle this that well
65+
as we do not check for this case. This should be added though as it is
66+
valid to have a detached head in some cases.
6967

7068
Remote
7169
------

‎lib/git/refs.py‎

Lines changed: 137 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77
Module containing all ref based objects
88
"""
9+
importos
910
fromobjects.baseimportObject
1011
fromobjects.utilsimportget_object_type_by_name
1112
fromutilsimportLazyMixin,Iterable
@@ -31,6 +32,9 @@ def __init__(self, repo, path, object = None):
3132
``object``
3233
Object instance, will be retrieved on demand if None
3334
"""
35+
ifnotpath.startswith(self._common_path_default):
36+
raiseValueError("Cannot instantiate %s Reference from path %s"% (self.__class__.__name__,path ))
37+
3438
self.repo=repo
3539
self.path=path
3640
ifobjectisnotNone:
@@ -75,6 +79,17 @@ def object(self):
7579
# have to be dynamic here as we may be a tag which can point to anything
7680
# Our path will be resolved to the hexsha which will be used accordingly
7781
returnObject.new(self.repo,self.path)
82+
83+
@property
84+
defcommit(self):
85+
"""
86+
Returns
87+
Commit object the head points to
88+
"""
89+
commit=self.object
90+
ifcommit.type!="commit":
91+
raiseTypeError("Object of reference %s did not point to a commit"%self)
92+
returncommit
7893

7994
@classmethod
8095
defiter_items(cls,repo,common_path=None,**kwargs):
@@ -112,6 +127,29 @@ def iter_items(cls, repo, common_path = None, **kwargs):
112127

113128
output=repo.git.for_each_ref(common_path,**options)
114129
returncls._iter_from_stream(repo,iter(output.splitlines()))
130+
131+
@classmethod
132+
deffrom_path(cls,repo,path):
133+
"""
134+
Return
135+
Instance of type Reference, Head, Tag, SymbolicReference or HEAD
136+
depending on the given path
137+
"""
138+
ifpath=='HEAD':
139+
returnHEAD(repo,path)
140+
141+
if'/'notinpath:
142+
returnSymbolicReference(repo,path)
143+
144+
forref_typein (Head,RemoteReference,TagReference,Reference):
145+
try:
146+
returnref_type(repo,path)
147+
exceptValueError:
148+
pass
149+
# END exception handling
150+
# END for each type to try
151+
raiseValueError("Could not find reference type suitable to handle path %r"%path)
152+
115153

116154
@classmethod
117155
def_iter_from_stream(cls,repo,stream):
@@ -145,47 +183,91 @@ def _from_string(cls, repo, line):
145183
# return cls(repo, full_path, obj)
146184

147185

148-
classHead(Reference):
186+
classSymbolicReference(object):
149187
"""
150-
A Head is a named reference to a Commit. Every Head instance contains a name
151-
and a Commit object.
152-
153-
Examples::
154-
155-
>>> repo = Repo("/path/to/repo")
156-
>>> head = repo.heads[0]
157-
158-
>>> head.name
159-
'master'
160-
161-
>>> head.commit
162-
<git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
163-
164-
>>> head.commit.id
165-
'1c09f116cbc2cb4100fb6935bb162daa4723f455'
188+
Represents a special case of a reference such that this reference is symbolic.
189+
It does not point to a specific commit, but to another Head, which itself
190+
specifies a commit.
191+
192+
A typical example for a symbolic reference is HEAD.
166193
"""
167-
_common_path_default="refs/heads"
194+
__slots__=("repo","name")
168195

196+
def__init__(self,repo,name):
197+
if'/'inname:
198+
raiseValueError("SymbolicReferences are not located within a directory, got %s"%name)
199+
self.repo=repo
200+
self.name=name
201+
202+
def__str__(self):
203+
returnself.name
204+
205+
def__repr__(self):
206+
return'<git.%s "%s">'% (self.__class__.__name__,self.name)
207+
208+
def__eq__(self,other):
209+
returnself.name==other.name
210+
211+
def__ne__(self,other):
212+
returnnot (self==other )
213+
214+
def__hash__(self):
215+
returnhash(self.name)
216+
169217
@property
170-
defcommit(self):
218+
defreference(self):
171219
"""
172220
Returns
173-
Commit object the head points to
221+
Reference Object we point to
174222
"""
175-
returnself.object
223+
fp=open(os.path.join(self.repo.path,self.name),'r')
224+
try:
225+
tokens=fp.readline().split(' ')
226+
iftokens[0]!='ref:':
227+
raiseTypeError("%s is a detached symbolic reference as it points to %r"%tokens[0])
228+
returnReference.from_path(self.repo,tokens[1])
229+
finally:
230+
fp.close()
176231

177-
@classmethod
178-
defreset(cls,repo,commit='HEAD',index=True,working_tree=False,
232+
# alias
233+
ref=reference
234+
235+
@property
236+
defis_detached(self):
237+
"""
238+
Returns
239+
True if we are a detached reference, hence we point to a specific commit
240+
instead to another reference
241+
"""
242+
try:
243+
self.reference
244+
returnFalse
245+
exceptTypeError:
246+
returnTrue
247+
248+
249+
classHEAD(SymbolicReference):
250+
"""
251+
Special case of a Symbolic Reference as it represents the repository's
252+
HEAD reference.
253+
"""
254+
__slots__=tuple()
255+
256+
def__init__(self,repo,name):
257+
ifname!='HEAD':
258+
raiseValueError("HEAD instance must point to 'HEAD', got %s"%name)
259+
super(HEAD,self).__init__(repo,name)
260+
261+
262+
defreset(self,commit='HEAD',index=True,working_tree=False,
179263
paths=None,**kwargs):
180264
"""
181-
Resetthe current head to the given commit optionally synchronizing
265+
Resetour HEAD to the given commit optionally synchronizing
182266
the index and working tree.
183267
184-
``repo``
185-
Repository containing commit
186-
187268
``commit``
188-
Commit object, Reference Object or string identifying a revision
269+
Commit object, Reference Object or string identifying a revision we
270+
should reset HEAD to.
189271
190272
``index``
191273
If True, the index will be set to match the given commit. Otherwise
@@ -204,7 +286,7 @@ def reset(cls, repo, commit='HEAD', index=True, working_tree = False,
204286
Additional arguments passed to git-reset.
205287
206288
Returns
207-
Head pointing to the specified commit
289+
self
208290
"""
209291
mode="--soft"
210292
ifindex:
@@ -219,9 +301,32 @@ def reset(cls, repo, commit='HEAD', index=True, working_tree = False,
219301
repo.git.reset(mode,commit,paths,**kwargs)
220302

221303
# we always point to the active branch as it is the one changing
222-
returnrepo.active_branch
304+
self
305+
306+
307+
classHead(Reference):
308+
"""
309+
A Head is a named reference to a Commit. Every Head instance contains a name
310+
and a Commit object.
311+
312+
Examples::
313+
314+
>>> repo = Repo("/path/to/repo")
315+
>>> head = repo.heads[0]
316+
317+
>>> head.name
318+
'master'
319+
320+
>>> head.commit
321+
<git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
322+
323+
>>> head.commit.id
324+
'1c09f116cbc2cb4100fb6935bb162daa4723f455'
325+
"""
326+
_common_path_default="refs/heads"
327+
223328

224-
classTagReference(Head):
329+
classTagReference(Reference):
225330
"""
226331
Class representing a lightweight tag reference which either points to a commit
227332
or to a tag object. In the latter case additional information, like the signature
@@ -230,7 +335,7 @@ class TagReference(Head):
230335
This tag object will always point to a commit object, but may carray additional
231336
information in a tag object::
232337
233-
tagref =TagRef.list_items(repo)[0]
338+
tagref =TagReference.list_items(repo)[0]
234339
print tagref.commit.message
235340
if tagref.tag is not None:
236341
print tagref.tag.message

‎lib/git/repo.py‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,12 @@ def heads(self):
147147
branches=heads
148148

149149
@property
150-
defhead(self,path="HEAD"):
150+
defhead(self):
151151
"""
152152
Return
153-
Head Object, reference pointing to commit
154-
155-
``path``
156-
path to the head or its name, i.e. master or heads/master
153+
HEAD Object pointing to the current head reference
157154
"""
158-
returnHead(self,path)
155+
returnHEAD(self,'HEAD')
159156

160157
@property
161158
defremotes(self):
@@ -486,8 +483,7 @@ def active_branch(self):
486483
Returns
487484
Head to the active branch
488485
"""
489-
returnHead(self,self.git.symbolic_ref('HEAD').strip() )
490-
486+
returnself.head.reference
491487

492488
defblame(self,rev,file):
493489
"""

‎test/git/test_base.py‎

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -66,50 +66,6 @@ def test_base_object(self):
6666
assertlen(s|s)==num_objs
6767
assertnum_index_objs==2
6868

69-
70-
deftest_tags(self):
71-
# tag refs can point to tag objects or to commits
72-
s=set()
73-
ref_count=0
74-
forrefinchain(self.rorepo.tags,self.rorepo.heads):
75-
ref_count+=1
76-
assertisinstance(ref,refs.Reference)
77-
assertstr(ref)==ref.name
78-
assertrepr(ref)
79-
assertref==ref
80-
assertnotref!=ref
81-
s.add(ref)
82-
# END for each ref
83-
assertlen(s)==ref_count
84-
assertlen(s|s)==ref_count
85-
86-
deftest_heads(self):
87-
# see how it dynmically updates its object
88-
forheadinself.rorepo.heads:
89-
head.name
90-
head.path
91-
prev_object=head.object
92-
cur_object=head.object
93-
assertprev_object==cur_object# represent the same git object
94-
assertprev_objectisnotcur_object# but are different instances
95-
# END for each head
96-
97-
@with_rw_repo('0.1.6')
98-
deftest_head_reset(self,rw_repo):
99-
cur_head=rw_repo.head
100-
new_head_commit=cur_head.commit.parents[0]
101-
reset_head=Head.reset(rw_repo,new_head_commit,index=True)# index only
102-
assertreset_head.commit==new_head_commit
103-
104-
self.failUnlessRaises(ValueError,Head.reset,rw_repo,new_head_commit,index=False,working_tree=True)
105-
new_head_commit=new_head_commit.parents[0]
106-
reset_head=Head.reset(rw_repo,new_head_commit,index=True,working_tree=True)# index + wt
107-
assertreset_head.commit==new_head_commit
108-
109-
# paths
110-
Head.reset(rw_repo,new_head_commit,paths="lib")
111-
112-
11369
deftest_get_object_type_by_name(self):
11470
fortnameinbase.Object.TYPES:
11571
assertbase.Objectinget_object_type_by_name(tname).mro()
@@ -119,7 +75,7 @@ def test_get_object_type_by_name(self):
11975

12076
deftest_object_resolution(self):
12177
# objects must be resolved to shas so they compare equal
122-
assertself.rorepo.head.object==self.rorepo.active_branch.object
78+
assertself.rorepo.head.reference.object==self.rorepo.active_branch.object
12379

12480
@with_bare_rw_repo
12581
deftest_with_bare_rw_repo(self,bare_rw_repo):

‎test/git/test_commit.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def test_rev_list_bisect_all(self, git):
6464
assert_equal(sha1,commit.id)
6565

6666
deftest_count(self):
67-
assertself.rorepo.tag('0.1.5').commit.count( )==141
67+
assertself.rorepo.tag('refs/tags/0.1.5').commit.count( )==141
6868

6969
deftest_list(self):
7070
assertisinstance(Commit.list_items(self.rorepo,'0.1.5',max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'],Commit)

‎test/git/test_head.py‎

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2026 Movatter.jp