Skip to content

Commit 73959f3

Browse files
committed
Implemented main rev-parsing, including long hexshas, tags and refs. Short Shas still to be done
1 parent a32a6bc commit 73959f3

File tree

2 files changed

+46
-14
lines changed

2 files changed

+46
-14
lines changed

lib/git/repo.py

+14-6
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ class Repo(object):
7171
# precompiled regex
7272
re_whitespace = re.compile(r'\s+')
7373
re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
74-
re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{7:40}$')
74+
re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{7,40}$')
75+
re_hexsha_domain = re.compile('^[0-9A-Fa-f]{1,40}$')
7576
re_author_committer_start = re.compile(r'^(author|committer)')
7677
re_tab_full_line = re.compile(r'^\t(.*)$')
7778

@@ -724,7 +725,7 @@ def rev_parse(self, rev):
724725
def name_to_object(name):
725726
hexsha = None
726727

727-
# is it a hexsha ?
728+
# is it a hexsha ? Try the most common ones, which is 7 to 40
728729
if self.re_hexsha_shortened.match(name):
729730
if len(name) != 40:
730731
# find long sha for short sha
@@ -744,6 +745,11 @@ def name_to_object(name):
744745

745746
# tried everything ? fail
746747
if hexsha is None:
748+
# it could also be a very short ( less than 7 ) hexsha, which
749+
# wasnt tested in the first run
750+
if len(name) < 7 and self.re_hexsha_domain.match(name):
751+
raise NotImplementedError()
752+
# END try short name
747753
raise BadObject(name)
748754
# END assert hexsha was found
749755

@@ -806,7 +812,7 @@ def to_commit(obj):
806812
# END exception handling
807813
elif output_type in ('', 'blob'):
808814
if obj.type == 'tag':
809-
obj = deref_tag(tag)
815+
obj = deref_tag(obj)
810816
else:
811817
# cannot do anything for non-tags
812818
pass
@@ -815,8 +821,9 @@ def to_commit(obj):
815821
raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
816822
# END handle output type
817823

818-
if obj.type != output_type:
819-
raise ValueError("Could not accomodate requested object type %s, got %s" % (output_type, obj.type))
824+
# empty output types don't require any specific type, its just about dereferencing tags
825+
if output_type and obj.type != output_type:
826+
raise ValueError("Could not accomodate requested object type %r, got %s" % (output_type, obj.type))
820827
# END verify ouput type
821828

822829
start = end+1 # skip brace
@@ -849,12 +856,13 @@ def to_commit(obj):
849856
parsed_to = start
850857
# handle hiererarchy walk
851858
try:
852-
obj = to_commit(obj)
853859
if token == "~":
860+
obj = to_commit(obj)
854861
for item in xrange(num):
855862
obj = obj.parents[0]
856863
# END for each history item to walk
857864
elif token == "^":
865+
obj = to_commit(obj)
858866
# must be n'th parent
859867
if num:
860868
obj = obj.parents[num-1]

test/git/test_repo.py

+32-8
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ def mktiny():
381381
def _assert_rev_parse_types(self, name, rev_obj):
382382
rev_parse = self.rorepo.rev_parse
383383

384+
if rev_obj.type == 'tag':
385+
rev_obj = rev_obj.object
386+
384387
# tree and blob type
385388
obj = rev_parse(name + '^{tree}')
386389
assert obj == rev_obj.tree
@@ -439,9 +442,6 @@ def _assert_rev_parse(self, name):
439442
def test_rev_parse(self):
440443
rev_parse = self.rorepo.rev_parse
441444

442-
# it works with tags !
443-
self._assert_rev_parse('0.1.4')
444-
445445
# start from reference
446446
num_resolved = 0
447447
for ref in Reference.iter_items(self.rorepo):
@@ -461,29 +461,53 @@ def test_rev_parse(self):
461461
# END for each reference
462462
assert num_resolved
463463

464+
# it works with tags !
465+
tag = self._assert_rev_parse('0.1.4')
466+
assert tag.type == 'tag'
467+
464468
# try full sha directly ( including type conversion )
469+
assert tag.object == rev_parse(tag.object.hexsha)
470+
self._assert_rev_parse_types(tag.object.hexsha, tag.object)
465471

466472

467473
# multiple tree types result in the same tree: HEAD^{tree}^{tree}:CHANGES
474+
rev = '0.1.4^{tree}^{tree}'
475+
assert rev_parse(rev) == tag.object.tree
476+
assert rev_parse(rev+':CHANGES') == tag.object.tree['CHANGES']
477+
468478

469479
# try to get parents from first revision - it should fail as no such revision
470480
# exists
481+
first_rev = "33ebe7acec14b25c5f84f35a664803fcab2f7781"
482+
commit = rev_parse(first_rev)
483+
assert len(commit.parents) == 0
484+
assert commit.hexsha == first_rev
485+
self.failUnlessRaises(BadObject, rev_parse, first_rev+"~")
486+
self.failUnlessRaises(BadObject, rev_parse, first_rev+"^")
487+
488+
# short SHA1
489+
commit2 = rev_parse(first_rev[:20])
490+
assert commit2 == commit
491+
commit2 = rev_parse(first_rev[:5])
492+
assert commit2 == commit
493+
471494

472495
# todo: dereference tag into a blob 0.1.7^{blob} - quite a special one
496+
# needs a tag which points to a blob
473497

474-
# dereference tag using ^{} notation
475498

476-
# ref^0 returns commit being pointed to, same with ref~0
499+
# ref^0 returns commit being pointed to, same with ref~0, and ^{}
477500
tag = rev_parse('0.1.4')
478-
for token in ('~^'):
479-
assert tag.object == rev_parse('0.1.4%s0' % token)
501+
for token in (('~0', '^0', '^{}')):
502+
assert tag.object == rev_parse('0.1.4%s' % token)
480503
# END handle multiple tokens
481504

482505
# missing closing brace commit^{tree
506+
self.failUnlessRaises(ValueError, rev_parse, '0.1.4^{tree')
483507

484508
# missing starting brace
509+
self.failUnlessRaises(ValueError, rev_parse, '0.1.4^tree}')
485510

486-
# not enough parents ^10
487511

488512
# cannot handle rev-log for now
489513
self.failUnlessRaises(ValueError, rev_parse, "hi@there")

0 commit comments

Comments
 (0)