Skip to content

Commit 5bd1abc

Browse files
committedMay 30, 2012
Add a has_ancestor_sha1 method on Object::Commit.
This will hopefully make finding common parents of 2 given refs/tags/branches easier as well as finding if one is the parent of the other, which will be very very useful if anyone ever plans on adding a rebase function to Git::PurePerl Add tests for has_ancestor
1 parent e245c15 commit 5bd1abc

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed
 

‎lib/Git/PurePerl/Object/Commit.pm

+48
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,53 @@ sub parents {
9191
return map { $self->git->get_object( $_ ) } @{$self->parent_sha1s};
9292
}
9393

94+
=head2 has_ancestor_sha1
95+
96+
Traverses up the parentage of the object graph to find out if the given C<sha1> appears as an ancestor.
97+
98+
if ( $commit_object->has_ancestor_sha1( 'deadbeef' x 5 ) ) {
99+
...
100+
}
101+
102+
=cut
103+
104+
sub has_ancestor_sha1 {
105+
my ( $self, $sha1 ) = @_;
106+
107+
# This may seem redundant, but its not entirely.
108+
# However, its a penalty paid for the branch shortening optimization.
109+
#
110+
# x^, y^ , z^ , y[ y^ , y... ] , z[ z^ , z... ]
111+
#
112+
# Will still be faster than
113+
#
114+
# x^, y[ y^ , y... ] , z[ z^ , z... ]
115+
#
116+
# In the event y is very long.
117+
118+
return 1 if $self->sha1 eq $sha1;
119+
120+
# This is a slight optimization of sorts,
121+
# as it means
122+
# x->{ y->{ y' } , z->{ z' } }
123+
# has a check order of:
124+
# x^, y^ , z^ , y[ y^ , ... ], z[ z^, ... ]
125+
# instead of
126+
# x^, y[ y^, y... ], z[ z^, z... ]
127+
# Which will probably make things a bit faster if y is incredibly large
128+
# and you just want to check if a given commit x has a direct ancestor i.
129+
for my $parent ( @{ $self->parent_sha1s } ) {
130+
return 1 if $parent eq $sha1;
131+
}
132+
133+
# Depth First.
134+
# TODO perhaps make it breadth first? could be very useful on very long repos
135+
# where the given ancestor might not be in the "first-parent" ancestry line.
136+
# But if somebody wants this feature, they'll have to provide the benchmarks, the code, or both.
137+
for my $parent ( $self->parents ) {
138+
return 1 if $parent->has_ancestor_sha1( $sha1, );
139+
}
140+
return;
141+
}
94142
__PACKAGE__->meta->make_immutable;
95143

‎t/08_has_ancestor.t

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use strict;
2+
use warnings;
3+
4+
use Test::More;
5+
6+
# FILENAME: 08_has_ancestor.t
7+
# CREATED: 31/05/12 07:48:42 by Kent Fredric (kentnl) <kentfredric@gmail.com>
8+
# ABSTRACT: Tests for has_ancestor
9+
use strict;
10+
use warnings;
11+
use Test::More;
12+
use Git::PurePerl;
13+
use Path::Class;
14+
15+
sub shatrim {
16+
return substr( shift, 0, 8 );
17+
}
18+
19+
sub repo_ancestor_check {
20+
my ( $repo, $commit, @ancestors ) = @_;
21+
my $git = Git::PurePerl->new( directory => $repo );
22+
my $commit_obj = $git->get_object($commit);
23+
for my $ancestor (@ancestors) {
24+
my ( $tcommit, $tancestor ) = map { shatrim($_) } $commit, $ancestor;
25+
ok(
26+
$commit_obj->has_ancestor_sha1($ancestor),
27+
"$repo @ $tcommit has ancestor $tancestor"
28+
);
29+
}
30+
}
31+
32+
sub repo_ancestor_not_check {
33+
my ( $repo, $commit, @ancestors ) = @_;
34+
my $git = Git::PurePerl->new( directory => $repo );
35+
my $commit_obj = $git->get_object($commit);
36+
for my $ancestor (@ancestors) {
37+
my ( $tcommit, $tancestor ) = map { shatrim($_) } $commit, $ancestor;
38+
ok(
39+
!$commit_obj->has_ancestor_sha1($ancestor),
40+
"$repo @ $tcommit has no ancestor $tancestor"
41+
);
42+
}
43+
}
44+
45+
repo_ancestor_check(
46+
'test-project' => '0c7b3d23c0f821e58cd20e60d5e63f5ed12ef391' => qw(
47+
a47f812b901251922153bac347a348604a24e372
48+
d24a32a404ce934cd4f39fd632fc1d43c413f652
49+
)
50+
);
51+
52+
repo_ancestor_check(
53+
'test-project' => 'a47f812b901251922153bac347a348604a24e372' => qw(
54+
d24a32a404ce934cd4f39fd632fc1d43c413f652
55+
)
56+
);
57+
58+
repo_ancestor_not_check(
59+
'test-project' => '0c7b3d23c0f821e58cd20e60d5e63f5ed12ef391' => qw(
60+
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
61+
)
62+
);
63+
64+
repo_ancestor_not_check(
65+
'test-project' => 'a47f812b901251922153bac347a348604a24e372' => qw(
66+
0c7b3d23c0f821e58cd20e60d5e63f5ed12ef391
67+
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
68+
)
69+
);
70+
repo_ancestor_not_check(
71+
'test-project' => 'd24a32a404ce934cd4f39fd632fc1d43c413f652' => qw(
72+
0c7b3d23c0f821e58cd20e60d5e63f5ed12ef391
73+
deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
74+
a47f812b901251922153bac347a348604a24e372
75+
)
76+
);
77+
78+
done_testing;
79+

0 commit comments

Comments
 (0)