Skip to content

Commit 3c94808

Browse files
committed
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 bda8730 commit 3c94808

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
Revision history for Perl module Git::PurePerl:
22

3+
- Add has_ancestor_sha1 method to Object::Commit (Kent Fredric)
34
- Add Git::PurePerl::Util with handy current_git_dir() util (Kent Fredric)
45

56
0.50 Sat Jan 25 14:58:16 CET 2014

lib/Git/PurePerl/Object/Commit.pm

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,55 @@ 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+
130+
for my $parent ( @{ $self->parent_sha1s } ) {
131+
return 1 if $parent eq $sha1;
132+
}
133+
134+
# Depth First.
135+
# TODO perhaps make it breadth first? could be very useful on very long repos
136+
# where the given ancestor might not be in the "first-parent" ancestry line.
137+
# But if somebody wants this feature, they'll have to provide the benchmarks, the code, or both.
138+
139+
for my $parent ( $self->parents ) {
140+
return 1 if $parent->has_ancestor_sha1( $sha1, );
141+
}
142+
return;
143+
}
94144
__PACKAGE__->meta->make_immutable;
95145

t/08_has_ancestor.t

Lines changed: 79 additions & 0 deletions
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) <[email protected]>
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)