14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
20
from bzrlib.selftest import TestCaseInTempDir
21
from bzrlib.branch import Branch
22
from bzrlib.commit import commit
21
from bzrlib.branch import Branch
22
from bzrlib.commit import commit
23
from bzrlib.fetch import fetch
24
from bzrlib.revision import (find_present_ancestors, combined_graph,
25
is_ancestor, MultipleRevisionSources)
26
from bzrlib.trace import mutter
27
from bzrlib.errors import NoSuchRevision
29
# XXX: Make this a method of a merge base case
30
def make_branches(self):
31
"""Create two branches
33
branch 1 has 6 commits, branch 2 has 3 commits
34
commit 10 was a psuedo merge from branch 1
35
but has been disabled until ghost support is
48
so A is missing b6 at the start
49
and B is missing a3, a4, a5
24
51
os.mkdir("branch1")
25
br1 = Branch("branch1", init=True)
52
br1 = Branch.initialize("branch1")
27
54
commit(br1, "Commit one", rev_id="a@u-0-0")
28
55
commit(br1, "Commit two", rev_id="a@u-0-1")
29
56
commit(br1, "Commit three", rev_id="a@u-0-2")
31
58
os.mkdir("branch2")
32
br2 = Branch("branch2", init=True)
59
br2 = Branch.initialize("branch2")
33
60
br2.update_revisions(br1)
34
61
commit(br2, "Commit four", rev_id="b@u-0-3")
35
62
commit(br2, "Commit five", rev_id="b@u-0-4")
36
63
revisions_2 = br2.revision_history()
65
fetch(from_branch=br2, to_branch=br1)
37
66
br1.add_pending_merge(revisions_2[4])
67
self.assertEquals(revisions_2[4], 'b@u-0-4')
38
68
commit(br1, "Commit six", rev_id="a@u-0-3")
39
69
commit(br1, "Commit seven", rev_id="a@u-0-4")
40
70
commit(br2, "Commit eight", rev_id="b@u-0-5")
72
fetch(from_branch=br2, to_branch=br1)
41
73
br1.add_pending_merge(br2.revision_history()[5])
42
74
commit(br1, "Commit nine", rev_id="a@u-0-5")
75
# DO NOT FETCH HERE - we WANT a GHOST.
76
#fetch(from_branch=br1, to_branch=br2)
43
77
br2.add_pending_merge(br1.revision_history()[4])
44
commit(br2, "Commit ten", rev_id="b@u-0-6")
78
commit(br2, "Commit ten - ghost merge", rev_id="b@u-0-6")
48
83
class TestIsAncestor(TestCaseInTempDir):
84
def test_recorded_ancestry(self):
85
"""Test that commit records all ancestors"""
86
br1, br2 = make_branches(self)
87
d = [('a@u-0-0', ['a@u-0-0']),
88
('a@u-0-1', ['a@u-0-0', 'a@u-0-1']),
89
('a@u-0-2', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2']),
90
('b@u-0-3', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3']),
91
('b@u-0-4', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3',
93
('a@u-0-3', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
95
('a@u-0-4', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
96
'a@u-0-3', 'a@u-0-4']),
97
('b@u-0-5', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
99
('a@u-0-5', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
100
'b@u-0-3', 'b@u-0-4',
101
'b@u-0-5', 'a@u-0-5']),
102
('b@u-0-6', ['a@u-0-0', 'a@u-0-1', 'a@u-0-2',
103
'b@u-0-3', 'b@u-0-4',
104
'b@u-0-5', 'b@u-0-6']),
106
br1_only = ('a@u-0-3', 'a@u-0-4', 'a@u-0-5')
107
br2_only = ('b@u-0-6',)
108
for branch in br1, br2:
109
for rev_id, anc in d:
110
if rev_id in br1_only and not branch is br1:
112
if rev_id in br2_only and not branch is br2:
114
mutter('ancestry of {%s}: %r',
115
rev_id, branch.get_ancestry(rev_id))
116
self.assertEquals(sorted(branch.get_ancestry(rev_id)),
117
[None] + sorted(anc))
49
120
def test_is_ancestor(self):
50
121
"""Test checking whether a revision is an ancestor of another revision"""
51
from bzrlib.revision import is_ancestor, MultipleRevisionSources
52
from bzrlib.errors import NoSuchRevision
53
br1, br2 = make_branches()
122
br1, br2 = make_branches(self)
54
123
revisions = br1.revision_history()
55
124
revisions_2 = br2.revision_history()
56
sources = MultipleRevisionSources(br1, br2)
58
assert is_ancestor(revisions[0], revisions[0], sources)
59
assert is_ancestor(revisions[1], revisions[0], sources)
60
assert not is_ancestor(revisions[0], revisions[1], sources)
61
assert is_ancestor(revisions_2[3], revisions[0], sources)
62
self.assertRaises(NoSuchRevision, is_ancestor, revisions_2[3],
64
assert is_ancestor(revisions[3], revisions_2[4], sources)
65
assert is_ancestor(revisions[3], revisions_2[4], br1)
66
assert is_ancestor(revisions[3], revisions_2[3], sources)
67
assert not is_ancestor(revisions[3], revisions_2[3], br1)
127
self.assert_(is_ancestor(revisions[0], revisions[0], br1))
128
self.assert_(is_ancestor(revisions[1], revisions[0], sources))
129
self.assert_(not is_ancestor(revisions[0], revisions[1], sources))
130
self.assert_(is_ancestor(revisions_2[3], revisions[0], sources))
131
# disabled mbp 20050914, doesn't seem to happen anymore
132
## self.assertRaises(NoSuchRevision, is_ancestor, revisions_2[3],
133
## revisions[0], br1)
134
self.assert_(is_ancestor(revisions[3], revisions_2[4], sources))
135
self.assert_(is_ancestor(revisions[3], revisions_2[4], br1))
136
self.assert_(is_ancestor(revisions[3], revisions_2[3], sources))
137
## self.assert_(not is_ancestor(revisions[3], revisions_2[3], br1))
140
class TestIntermediateRevisions(TestCaseInTempDir):
143
from bzrlib.commit import commit
144
TestCaseInTempDir.setUp(self)
145
self.br1, self.br2 = make_branches(self)
147
self.br2.commit("Commit eleven", rev_id="b@u-0-7")
148
self.br2.commit("Commit twelve", rev_id="b@u-0-8")
149
self.br2.commit("Commit thirtteen", rev_id="b@u-0-9")
151
fetch(from_branch=self.br2, to_branch=self.br1)
152
self.br1.add_pending_merge(self.br2.revision_history()[6])
153
self.br1.commit("Commit fourtten", rev_id="a@u-0-6")
155
fetch(from_branch=self.br1, to_branch=self.br2)
156
self.br2.add_pending_merge(self.br1.revision_history()[6])
157
self.br2.commit("Commit fifteen", rev_id="b@u-0-10")
159
from bzrlib.revision import MultipleRevisionSources
160
self.sources = MultipleRevisionSources(self.br1, self.br2)
162
def intervene(self, ancestor, revision, revision_history=None):
163
from bzrlib.revision import get_intervening_revisions
164
return get_intervening_revisions(ancestor,revision, self.sources,
167
def test_intervene(self):
168
"""Find intermediate revisions, without requiring history"""
169
from bzrlib.errors import NotAncestor, NoSuchRevision
170
self.assertEquals(len(self.intervene('a@u-0-0', 'a@u-0-0')), 0)
171
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-1'), ['a@u-0-1'])
172
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-2'),
173
['a@u-0-1', 'a@u-0-2'])
174
self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-3'),
175
['a@u-0-1', 'a@u-0-2', 'b@u-0-3'])
176
self.assertEqual(self.intervene('b@u-0-3', 'a@u-0-3'),
177
['b@u-0-4', 'a@u-0-3'])
178
self.assertEqual(self.intervene('a@u-0-2', 'a@u-0-3',
179
self.br1.revision_history()),
181
self.assertEqual(self.intervene('a@u-0-0', 'a@u-0-5',
182
self.br1.revision_history()),
183
['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
185
self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-6',
186
self.br1.revision_history()),
187
['a@u-0-1', 'a@u-0-2', 'a@u-0-3', 'a@u-0-4',
189
self.assertEqual(self.intervene('a@u-0-0', 'b@u-0-5'),
190
['a@u-0-1', 'a@u-0-2', 'b@u-0-3', 'b@u-0-4',
192
self.assertEqual(self.intervene('b@u-0-3', 'b@u-0-6',
193
self.br2.revision_history()),
194
['b@u-0-4', 'b@u-0-5', 'b@u-0-6'])
195
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10'),
196
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
197
self.assertEqual(self.intervene('b@u-0-6', 'b@u-0-10',
198
self.br2.revision_history()),
199
['b@u-0-7', 'b@u-0-8', 'b@u-0-9', 'b@u-0-10'])
200
self.assertRaises(NotAncestor, self.intervene, 'b@u-0-10', 'b@u-0-6',
201
self.br2.revision_history())
202
self.assertRaises(NoSuchRevision, self.intervene, 'c@u-0-10',
203
'b@u-0-6', self.br2.revision_history())
204
self.assertRaises(NoSuchRevision, self.intervene, 'b@u-0-10',
205
'c@u-0-6', self.br2.revision_history())
70
208
class TestCommonAncestor(TestCaseInTempDir):
71
209
"""Test checking whether a revision is an ancestor of another revision"""
211
def test_old_common_ancestor(self):
212
"""Pick a resonable merge base using the old functionality"""
213
from bzrlib.revision import old_common_ancestor as common_ancestor
214
br1, br2 = make_branches(self)
215
revisions = br1.revision_history()
216
revisions_2 = br2.revision_history()
219
expected_ancestors_list = {revisions[3]:(0, 0),
221
revisions_2[4]:(2, 1),
223
revisions_2[3]:(4, 2),
224
revisions[0]:(5, 3) }
225
ancestors_list = find_present_ancestors(revisions[3], sources)
226
self.assertEquals(len(expected_ancestors_list), len(ancestors_list))
227
for key, value in expected_ancestors_list.iteritems():
228
self.assertEqual(ancestors_list[key], value,
229
"key %r, %r != %r" % (key, ancestors_list[key],
232
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
234
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
236
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
238
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
240
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
242
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
244
fetch(from_branch=br2, to_branch=br1)
245
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
246
revisions[4]) # revisions_2[5] is equally valid
247
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
73
250
def test_common_ancestor(self):
74
from bzrlib.revision import find_present_ancestors, common_ancestor
75
from bzrlib.revision import MultipleRevisionSources
76
br1, br2 = make_branches()
251
"""Pick a reasonable merge base"""
252
from bzrlib.revision import common_ancestor
253
br1, br2 = make_branches(self)
77
254
revisions = br1.revision_history()
78
255
revisions_2 = br2.revision_history()
79
256
sources = MultipleRevisionSources(br1, br2)
81
257
expected_ancestors_list = {revisions[3]:(0, 0),
82
258
revisions[2]:(1, 1),
83
259
revisions_2[4]:(2, 1),