1
# Copyright (C) 2006 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# Author: Aaron Bentley <aaron.bentley@utoronto.ca>
19
"""Black-box tests for bzr merge.
24
from bzrlib.branch import Branch
25
from bzrlib.bzrdir import BzrDir
26
from bzrlib.osutils import abspath
27
from bzrlib.tests.blackbox import ExternalBase
28
from bzrlib.workingtree import WorkingTree
31
class TestMerge(ExternalBase):
33
def example_branch(test):
35
file('hello', 'wt').write('foo')
36
test.runbzr('add hello')
37
test.runbzr('commit -m setup hello')
38
file('goodbye', 'wt').write('baz')
39
test.runbzr('add goodbye')
40
test.runbzr('commit -m setup goodbye')
42
def test_merge_reprocess(self):
43
d = BzrDir.create_standalone_workingtree('.')
45
self.run_bzr('merge', '.', '--reprocess', '--merge-type', 'weave')
48
from bzrlib.branch import Branch
54
self.runbzr('branch a b')
56
file('goodbye', 'wt').write('quux')
57
self.runbzr(['commit', '-m', "more u's are always good"])
60
file('hello', 'wt').write('quuux')
61
# We can't merge when there are in-tree changes
62
self.runbzr('merge ../b', retcode=3)
63
self.runbzr(['commit', '-m', "Like an epidemic of u's"])
64
self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
66
self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
67
self.runbzr('revert --no-backup')
68
self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
69
self.runbzr('revert --no-backup')
70
self.runbzr('merge ../b -r last:1..last:1 --reprocess')
71
self.runbzr('revert --no-backup')
72
self.runbzr('merge ../b -r last:1')
73
self.check_file_contents('goodbye', 'quux')
74
# Merging a branch pulls its revision into the tree
75
a = WorkingTree.open('.')
76
b = Branch.open('../b')
77
a.branch.repository.get_revision_xml(b.last_revision())
78
self.log('pending merges: %s', a.pending_merges())
79
self.assertEquals(a.pending_merges(),
81
self.runbzr('commit -m merged')
82
self.runbzr('merge ../b -r last:1')
83
self.assertEqual(a.pending_merges(), [])
85
def test_merge_with_missing_file(self):
86
"""Merge handles missing file conflicts"""
90
print >> file('sub/a.txt', 'wb'), "hello"
91
print >> file('b.txt', 'wb'), "hello"
92
print >> file('sub/c.txt', 'wb'), "hello"
95
self.runbzr(('commit', '-m', 'added a'))
96
self.runbzr('branch . ../b')
97
print >> file('sub/a.txt', 'ab'), "there"
98
print >> file('b.txt', 'ab'), "there"
99
print >> file('sub/c.txt', 'ab'), "there"
100
self.runbzr(('commit', '-m', 'Added there'))
101
os.unlink('sub/a.txt')
102
os.unlink('sub/c.txt')
105
self.runbzr(('commit', '-m', 'Removed a.txt'))
107
print >> file('sub/a.txt', 'ab'), "something"
108
print >> file('b.txt', 'ab'), "something"
109
print >> file('sub/c.txt', 'ab'), "something"
110
self.runbzr(('commit', '-m', 'Modified a.txt'))
111
self.runbzr('merge ../a/', retcode=1)
112
self.assert_(os.path.exists('sub/a.txt.THIS'))
113
self.assert_(os.path.exists('sub/a.txt.BASE'))
115
self.runbzr('merge ../b/', retcode=1)
116
self.assert_(os.path.exists('sub/a.txt.OTHER'))
117
self.assert_(os.path.exists('sub/a.txt.BASE'))
119
def test_merge_remember(self):
120
"""Merge changes from one branch to another and test parent location."""
121
tree_a = self.make_branch_and_tree('branch_a')
122
branch_a = tree_a.branch
123
self.build_tree(['branch_a/a'])
125
tree_a.commit('commit a')
126
branch_b = branch_a.bzrdir.sprout('branch_b').open_branch()
127
tree_b = branch_b.bzrdir.open_workingtree()
128
branch_c = branch_a.bzrdir.sprout('branch_c').open_branch()
129
tree_c = branch_c.bzrdir.open_workingtree()
130
self.build_tree(['branch_a/b'])
132
tree_a.commit('commit b')
133
self.build_tree(['branch_c/c'])
135
tree_c.commit('commit c')
137
parent = branch_b.get_parent()
138
branch_b.set_parent(None)
139
self.assertEqual(None, branch_b.get_parent())
140
# test merge for failure without parent set
142
out = self.runbzr('merge', retcode=3)
143
self.assertEquals(out,
144
('','bzr: ERROR: No merge branch known or specified.\n'))
145
# test implicit --remember when no parent set, this merge conflicts
146
self.build_tree(['d'])
148
out = self.runbzr('merge ../branch_a', retcode=3)
149
self.assertEquals(out,
150
('','bzr: ERROR: Working tree has uncommitted changes.\n'))
151
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
152
# test implicit --remember after resolving conflict
153
tree_b.commit('commit d')
154
out, err = self.runbzr('merge')
155
self.assertEquals(out, 'Using saved branch: ../branch_a\n')
156
self.assertEquals(err, 'All changes applied successfully.\n')
157
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
158
# re-open tree as external runbzr modified it
159
tree_b = branch_b.bzrdir.open_workingtree()
160
tree_b.commit('merge branch_a')
161
# test explicit --remember
162
out, err = self.runbzr('merge ../branch_c --remember')
163
self.assertEquals(out, '')
164
self.assertEquals(err, 'All changes applied successfully.\n')
165
self.assertEquals(abspath(branch_b.get_parent()),
166
abspath(branch_c.bzrdir.root_transport.base))
167
# re-open tree as external runbzr modified it
168
tree_b = branch_b.bzrdir.open_workingtree()
169
tree_b.commit('merge branch_c')
171
def test_merge_bundle(self):
172
from bzrlib.testament import Testament
173
tree_a = self.make_branch_and_tree('branch_a')
174
f = file('branch_a/a', 'wb')
178
tree_a.commit('message')
180
tree_b = tree_a.bzrdir.sprout('branch_b').open_workingtree()
181
f = file('branch_a/a', 'wb')
184
tree_a.commit('message')
186
f = file('branch_b/a', 'wb')
189
tree_b.commit('message')
191
file('../bundle', 'wb').write(self.runbzr('bundle ../branch_a')[0])
192
os.chdir('../branch_a')
193
self.runbzr('merge ../bundle', retcode=1)
194
testament_a = Testament.from_revision(tree_a.branch.repository,
195
tree_b.last_revision())
196
testament_b = Testament.from_revision(tree_b.branch.repository,
197
tree_b.last_revision())
198
self.assertEqualDiff(testament_a.as_text(),
199
testament_b.as_text())