24
24
from bzrlib.branch import Branch
25
25
from bzrlib.bzrdir import BzrDir
26
from bzrlib.conflicts import ConflictList, ContentsConflict
27
from bzrlib.osutils import abspath, file_kind
26
from bzrlib.conflicts import ConflictList
27
from bzrlib.osutils import abspath
28
28
from bzrlib.tests.blackbox import ExternalBase
29
29
import bzrlib.urlutils as urlutils
30
30
from bzrlib.workingtree import WorkingTree
33
33
class TestMerge(ExternalBase):
35
35
def example_branch(test):
37
37
file('hello', 'wt').write('foo')
38
test.run_bzr('add hello')
39
test.run_bzr('commit -m setup hello')
38
test.runbzr('add hello')
39
test.runbzr('commit -m setup hello')
40
40
file('goodbye', 'wt').write('baz')
41
test.run_bzr('add goodbye')
42
test.run_bzr('commit -m setup goodbye')
41
test.runbzr('add goodbye')
42
test.runbzr('commit -m setup goodbye')
44
44
def test_merge_reprocess(self):
45
45
d = BzrDir.create_standalone_workingtree('.')
47
self.run_bzr('merge . --reprocess --merge-type weave')
47
self.run_bzr('merge', '.', '--reprocess', '--merge-type', 'weave')
49
49
def test_merge(self):
50
50
from bzrlib.branch import Branch
54
54
self.example_branch()
55
55
ancestor = Branch.open('.').revno()
57
self.run_bzr('branch a b')
57
self.runbzr('branch a b')
59
59
file('goodbye', 'wt').write('quux')
60
self.run_bzr(['commit', '-m', "more u's are always good"])
60
self.runbzr(['commit', '-m', "more u's are always good"])
63
63
file('hello', 'wt').write('quuux')
64
64
# We can't merge when there are in-tree changes
65
self.run_bzr('merge ../b', retcode=3)
65
self.runbzr('merge ../b', retcode=3)
66
66
a = WorkingTree.open('.')
67
67
a_tip = a.commit("Like an epidemic of u's")
68
self.run_bzr('merge ../b -r last:1..last:1 --merge-type blooof',
68
self.runbzr('merge ../b -r last:1..last:1 --merge-type blooof',
70
self.run_bzr('merge ../b -r last:1..last:1 --merge-type merge3')
71
self.run_bzr('revert --no-backup')
72
self.run_bzr('merge ../b -r last:1..last:1 --merge-type weave')
73
self.run_bzr('revert --no-backup')
74
self.run_bzr('merge ../b -r last:1..last:1 --reprocess')
75
self.run_bzr('revert --no-backup')
76
self.run_bzr('merge ../b -r last:1')
70
self.runbzr('merge ../b -r last:1..last:1 --merge-type merge3')
71
self.runbzr('revert --no-backup')
72
self.runbzr('merge ../b -r last:1..last:1 --merge-type weave')
73
self.runbzr('revert --no-backup')
74
self.runbzr('merge ../b -r last:1..last:1 --reprocess')
75
self.runbzr('revert --no-backup')
76
self.runbzr('merge ../b -r last:1')
77
77
self.check_file_contents('goodbye', 'quux')
78
78
# Merging a branch pulls its revision into the tree
79
79
b = Branch.open('../b')
80
80
b_tip = b.last_revision()
81
81
self.failUnless(a.branch.repository.has_revision(b_tip))
82
82
self.assertEqual([a_tip, b_tip], a.get_parent_ids())
83
self.run_bzr('revert --no-backup')
84
out, err = self.run_bzr('merge -r revno:1:./hello', retcode=3)
83
self.runbzr('revert --no-backup')
84
out, err = self.runbzr('merge -r revno:1:./hello', retcode=3)
85
85
self.assertTrue("Not a branch" in err)
86
self.run_bzr('merge -r revno:%d:./..revno:%d:../b'
86
self.runbzr('merge -r revno:%d:./..revno:%d:../b'
87
87
%(ancestor,b.revno()))
88
88
self.assertEquals(a.get_parent_ids(),
89
89
[a.branch.last_revision(), b.last_revision()])
90
90
self.check_file_contents('goodbye', 'quux')
91
self.run_bzr('revert --no-backup')
92
self.run_bzr('merge -r revno:%d:../b'%b.revno())
91
self.runbzr('revert --no-backup')
92
self.runbzr('merge -r revno:%d:../b'%b.revno())
93
93
self.assertEquals(a.get_parent_ids(),
94
94
[a.branch.last_revision(), b.last_revision()])
95
95
a_tip = a.commit('merged')
96
self.run_bzr('merge ../b -r last:1')
96
self.runbzr('merge ../b -r last:1')
97
97
self.assertEqual([a_tip], a.get_parent_ids())
99
99
def test_merge_with_missing_file(self):
104
104
print >> file('sub/a.txt', 'wb'), "hello"
105
105
print >> file('b.txt', 'wb'), "hello"
106
106
print >> file('sub/c.txt', 'wb'), "hello"
109
self.run_bzr(['commit', '-m', 'added a'])
110
self.run_bzr('branch . ../b')
109
self.runbzr(('commit', '-m', 'added a'))
110
self.runbzr('branch . ../b')
111
111
print >> file('sub/a.txt', 'ab'), "there"
112
112
print >> file('b.txt', 'ab'), "there"
113
113
print >> file('sub/c.txt', 'ab'), "there"
114
self.run_bzr(['commit', '-m', 'Added there'])
114
self.runbzr(('commit', '-m', 'Added there'))
115
115
os.unlink('sub/a.txt')
116
116
os.unlink('sub/c.txt')
118
118
os.unlink('b.txt')
119
self.run_bzr(['commit', '-m', 'Removed a.txt'])
119
self.runbzr(('commit', '-m', 'Removed a.txt'))
121
121
print >> file('sub/a.txt', 'ab'), "something"
122
122
print >> file('b.txt', 'ab'), "something"
123
123
print >> file('sub/c.txt', 'ab'), "something"
124
self.run_bzr(['commit', '-m', 'Modified a.txt'])
125
self.run_bzr('merge ../a/', retcode=1)
124
self.runbzr(('commit', '-m', 'Modified a.txt'))
125
self.runbzr('merge ../a/', retcode=1)
126
126
self.assert_(os.path.exists('sub/a.txt.THIS'))
127
127
self.assert_(os.path.exists('sub/a.txt.BASE'))
129
self.run_bzr('merge ../b/', retcode=1)
129
self.runbzr('merge ../b/', retcode=1)
130
130
self.assert_(os.path.exists('sub/a.txt.OTHER'))
131
131
self.assert_(os.path.exists('sub/a.txt.BASE'))
153
153
self.assertEqual(None, branch_b.get_parent())
154
154
# test merge for failure without parent set
155
155
os.chdir('branch_b')
156
out = self.run_bzr('merge', retcode=3)
156
out = self.runbzr('merge', retcode=3)
157
157
self.assertEquals(out,
158
158
('','bzr: ERROR: No location specified or remembered\n'))
159
159
# test implicit --remember when no parent set, this merge conflicts
160
160
self.build_tree(['d'])
162
out = self.run_bzr('merge ../branch_a', retcode=3)
162
out = self.runbzr('merge ../branch_a', retcode=3)
163
163
self.assertEquals(out,
164
164
('','bzr: ERROR: Working tree has uncommitted changes.\n'))
165
165
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
166
166
# test implicit --remember after resolving conflict
167
167
tree_b.commit('commit d')
168
out, err = self.run_bzr('merge')
168
out, err = self.runbzr('merge')
170
170
base = urlutils.local_path_from_url(branch_a.base)
171
171
self.assertEquals(out, 'Merging from remembered location %s\n' % (base,))
172
self.assertEquals(err, '+N b\nAll changes applied successfully.\n')
172
self.assertEquals(err, 'All changes applied successfully.\n')
173
173
self.assertEquals(abspath(branch_b.get_parent()), abspath(parent))
174
# re-open tree as external run_bzr modified it
174
# re-open tree as external runbzr modified it
175
175
tree_b = branch_b.bzrdir.open_workingtree()
176
176
tree_b.commit('merge branch_a')
177
177
# test explicit --remember
178
out, err = self.run_bzr('merge ../branch_c --remember')
178
out, err = self.runbzr('merge ../branch_c --remember')
179
179
self.assertEquals(out, '')
180
self.assertEquals(err, '+N c\nAll changes applied successfully.\n')
180
self.assertEquals(err, 'All changes applied successfully.\n')
181
181
self.assertEquals(abspath(branch_b.get_parent()),
182
182
abspath(branch_c.bzrdir.root_transport.base))
183
# re-open tree as external run_bzr modified it
183
# re-open tree as external runbzr modified it
184
184
tree_b = branch_b.bzrdir.open_workingtree()
185
185
tree_b.commit('merge branch_c')
205
205
tree_b.commit('message')
206
206
os.chdir('branch_b')
207
file('../bundle', 'wb').write(self.run_bzr('bundle ../branch_a')[0])
207
file('../bundle', 'wb').write(self.runbzr('bundle ../branch_a')[0])
208
208
os.chdir('../branch_a')
209
self.run_bzr('merge ../bundle', retcode=1)
209
self.runbzr('merge ../bundle', retcode=1)
210
210
testament_a = Testament.from_revision(tree_a.branch.repository,
211
211
tree_b.get_parent_ids()[0])
212
212
testament_b = Testament.from_revision(tree_b.branch.repository,
232
232
tree_a.rename_one('file_1', 'file_i')
233
233
tree_a.commit('commit 2')
234
234
tree_a.rename_one('file_2', 'file_ii')
236
self.run_bzr('merge a --uncommitted -d b')
237
self.failUnlessExists('b/file_1')
238
self.failUnlessExists('b/file_ii')
240
self.run_bzr_error(('Cannot use --uncommitted and --revision',),
241
'merge /a --uncommitted -r1 -d b')
243
def pullable_branch(self):
246
self.example_branch()
248
self.run_bzr('branch a b')
250
file('goodbye', 'wt').write('quux')
251
self.run_bzr(['commit', '-m', "mode u's are always good"])
254
def pullable_branch(self):
255
tree_a = self.make_branch_and_tree('a')
256
self.build_tree(['a/file'])
258
self.id1 = tree_a.commit('commit 1')
260
tree_b = self.make_branch_and_tree('b')
261
tree_b.pull(tree_a.branch)
262
file('b/file', 'wb').write('foo')
263
self.id2 = tree_b.commit('commit 2')
265
def test_merge_pull(self):
266
self.pullable_branch()
268
(out, err) = self.run_bzr('merge --pull ../b')
269
self.assertContainsRe(err, 'Now on revision 2\\.')
270
tree_a = WorkingTree.open('.')
271
self.assertEqual([self.id2], tree_a.get_parent_ids())
273
def test_merge_kind_change(self):
274
tree_a = self.make_branch_and_tree('tree_a')
275
self.build_tree_contents([('tree_a/file', 'content_1')])
276
tree_a.add('file', 'file-id')
277
tree_a.commit('added file')
278
tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree()
279
os.unlink('tree_a/file')
280
self.build_tree(['tree_a/file/'])
281
tree_a.commit('changed file to directory')
283
self.run_bzr('merge ../tree_a')
284
self.assertEqual('directory', file_kind('file'))
236
self.run_bzr('merge', '../a', '--uncommitted')
237
self.failUnlessExists('file_1')
238
self.failUnlessExists('file_ii')
285
239
tree_b.revert([])
286
self.assertEqual('file', file_kind('file'))
287
self.build_tree_contents([('file', 'content_2')])
288
tree_b.commit('content change')
289
self.run_bzr('merge ../tree_a', retcode=1)
290
self.assertEqual(tree_b.conflicts(),
291
[ContentsConflict('file', file_id='file-id')])
240
self.run_bzr_error(('Cannot use --uncommitted and --revision',),
241
'merge', '../a', '--uncommitted', '-r1')