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
from bzrlib.selftest import InTempDir
21
from bzrlib.branch import Branch
22
from bzrlib.commit import commit
20
from bzrlib.tests import TestCaseInTempDir
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)
26
commit(br1, "Commit one")
27
commit(br1, "Commit two")
28
commit(br1, "Commit three")
52
br1 = Branch.initialize("branch1")
54
commit(br1, "Commit one", rev_id="a@u-0-0")
55
commit(br1, "Commit two", rev_id="a@u-0-1")
56
commit(br1, "Commit three", rev_id="a@u-0-2")
30
58
os.mkdir("branch2")
31
br2 = Branch("branch2", init=True)
59
br2 = Branch.initialize("branch2")
32
60
br2.update_revisions(br1)
33
commit(br2, "Commit four")
34
commit(br2, "Commit five")
61
commit(br2, "Commit four", rev_id="b@u-0-3")
62
commit(br2, "Commit five", rev_id="b@u-0-4")
35
63
revisions_2 = br2.revision_history()
36
br1.add_pending_merge(revisions_2[4])
37
commit(br1, "Commit six")
65
fetch(from_branch=br2, to_branch=br1)
66
br1.working_tree().add_pending_merge(revisions_2[4])
67
self.assertEquals(revisions_2[4], 'b@u-0-4')
68
commit(br1, "Commit six", rev_id="a@u-0-3")
69
commit(br1, "Commit seven", rev_id="a@u-0-4")
70
commit(br2, "Commit eight", rev_id="b@u-0-5")
72
fetch(from_branch=br2, to_branch=br1)
73
br1.working_tree().add_pending_merge(br2.revision_history()[5])
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)
77
br2.working_tree().add_pending_merge(br1.revision_history()[4])
78
commit(br2, "Commit ten - ghost merge", rev_id="b@u-0-6")
41
class TestIsAncestor(InTempDir):
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))
120
def test_is_ancestor(self):
121
"""Test checking whether a revision is an ancestor of another revision"""
122
br1, br2 = make_branches(self)
123
revisions = br1.revision_history()
124
revisions_2 = br2.revision_history()
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.working_tree().commit("Commit eleven", rev_id="b@u-0-7")
148
self.br2.working_tree().commit("Commit twelve", rev_id="b@u-0-8")
149
self.br2.working_tree().commit("Commit thirtteen", rev_id="b@u-0-9")
151
fetch(from_branch=self.br2, to_branch=self.br1)
152
self.br1.working_tree().add_pending_merge(self.br2.revision_history()[6])
153
self.br1.working_tree().commit("Commit fourtten", rev_id="a@u-0-6")
155
fetch(from_branch=self.br1, to_branch=self.br2)
156
self.br2.working_tree().add_pending_merge(self.br1.revision_history()[6])
157
self.br2.working_tree().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())
208
class TestCommonAncestor(TestCaseInTempDir):
42
209
"""Test checking whether a revision is an ancestor of another revision"""
44
from bzrlib.revision import is_ancestor, MultipleRevisionSources
45
from bzrlib.errors import NoSuchRevision
46
br1, br2 = make_branches()
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),
250
def test_common_ancestor(self):
251
"""Pick a reasonable merge base"""
252
from bzrlib.revision import common_ancestor
253
br1, br2 = make_branches(self)
47
254
revisions = br1.revision_history()
48
255
revisions_2 = br2.revision_history()
49
256
sources = MultipleRevisionSources(br1, br2)
51
assert is_ancestor(revisions[0], revisions[0], sources)
52
assert is_ancestor(revisions[1], revisions[0], sources)
53
assert not is_ancestor(revisions[0], revisions[1], sources)
54
assert is_ancestor(revisions_2[3], revisions[0], sources)
55
self.assertRaises(NoSuchRevision, is_ancestor, revisions_2[3],
57
assert is_ancestor(revisions[3], revisions_2[4], sources)
58
assert is_ancestor(revisions[3], revisions_2[4], br1)
59
assert is_ancestor(revisions[3], revisions_2[3], sources)
60
assert not is_ancestor(revisions[3], revisions_2[3], br1)
257
expected_ancestors_list = {revisions[3]:(0, 0),
259
revisions_2[4]:(2, 1),
261
revisions_2[3]:(4, 2),
262
revisions[0]:(5, 3) }
263
ancestors_list = find_present_ancestors(revisions[3], sources)
264
self.assertEquals(len(expected_ancestors_list), len(ancestors_list))
265
for key, value in expected_ancestors_list.iteritems():
266
self.assertEqual(ancestors_list[key], value,
267
"key %r, %r != %r" % (key, ancestors_list[key],
269
self.assertEqual(common_ancestor(revisions[0], revisions[0], sources),
271
self.assertEqual(common_ancestor(revisions[1], revisions[2], sources),
273
self.assertEqual(common_ancestor(revisions[1], revisions[1], sources),
275
self.assertEqual(common_ancestor(revisions[2], revisions_2[4], sources),
277
self.assertEqual(common_ancestor(revisions[3], revisions_2[4], sources),
279
self.assertEqual(common_ancestor(revisions[4], revisions_2[5], sources),
281
self.assertEqual(common_ancestor(revisions[5], revisions_2[6], sources),
282
revisions[4]) # revisions_2[5] is equally valid
283
self.assertEqual(common_ancestor(revisions_2[6], revisions[5], sources),
284
revisions[4]) # revisions_2[5] is equally valid
286
def test_combined(self):
288
Ensure it's not order-sensitive
290
br1, br2 = make_branches(self)
291
source = MultipleRevisionSources(br1, br2)
292
combined_1 = combined_graph(br1.last_revision(),
293
br2.last_revision(), source)
294
combined_2 = combined_graph(br2.last_revision(),
295
br1.last_revision(), source)
296
self.assertEquals(combined_1[1], combined_2[1])
297
self.assertEquals(combined_1[2], combined_2[2])
298
self.assertEquals(combined_1[3], combined_2[3])
299
self.assertEquals(combined_1, combined_2)