1
# Copyright (C) 2005, 2006, 2008 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
"""Test the uncommit command."""
21
from bzrlib import uncommit, workingtree
22
from bzrlib.bzrdir import BzrDirMetaFormat1
23
from bzrlib.errors import BzrError, BoundBranchOutOfDate
24
from bzrlib.tests import TestCaseWithTransport
27
class TestUncommit(TestCaseWithTransport):
29
def create_simple_tree(self):
30
wt = self.make_branch_and_tree('tree')
31
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
32
wt.add(['a', 'b', 'c'])
33
wt.commit('initial commit', rev_id='a1')
35
open('tree/a', 'wb').write('new contents of a\n')
36
wt.commit('second commit', rev_id='a2')
40
def test_uncommit(self):
41
"""Test uncommit functionality."""
42
wt = self.create_simple_tree()
45
out, err = self.run_bzr('uncommit --dry-run --force')
46
self.assertContainsRe(out, 'Dry-run')
47
self.assertNotContainsRe(out, 'initial commit')
48
self.assertContainsRe(out, 'second commit')
51
self.assertEqual(['a2'], wt.get_parent_ids())
53
# Uncommit, don't prompt
54
out, err = self.run_bzr('uncommit --force')
55
self.assertNotContainsRe(out, 'initial commit')
56
self.assertContainsRe(out, 'second commit')
58
# This should look like we are back in revno 1
59
self.assertEqual(['a1'], wt.get_parent_ids())
60
out, err = self.run_bzr('status')
61
self.assertEquals(out, 'modified:\n a\n')
63
def test_uncommit_no_history(self):
64
wt = self.make_branch_and_tree('tree')
65
out, err = self.run_bzr('uncommit --force', retcode=1)
66
self.assertEqual('', err)
67
self.assertEqual('No revisions to uncommit.\n', out)
69
def test_uncommit_checkout(self):
70
wt = self.create_simple_tree()
71
checkout_tree = wt.branch.create_checkout('checkout')
73
self.assertEqual(['a2'], checkout_tree.get_parent_ids())
76
out, err = self.run_bzr('uncommit --dry-run --force')
77
self.assertContainsRe(out, 'Dry-run')
78
self.assertNotContainsRe(out, 'initial commit')
79
self.assertContainsRe(out, 'second commit')
81
self.assertEqual(['a2'], checkout_tree.get_parent_ids())
83
out, err = self.run_bzr('uncommit --force')
84
self.assertNotContainsRe(out, 'initial commit')
85
self.assertContainsRe(out, 'second commit')
87
# uncommit in a checkout should uncommit the parent branch
88
# (but doesn't effect the other working tree)
89
self.assertEquals(['a1'], checkout_tree.get_parent_ids())
90
self.assertEquals('a1', wt.branch.last_revision())
91
self.assertEquals(['a2'], wt.get_parent_ids())
93
def test_uncommit_bound(self):
95
a = BzrDirMetaFormat1().initialize('a')
98
t_a = a.create_workingtree()
99
t_a.commit('commit 1')
100
t_a.commit('commit 2')
101
t_a.commit('commit 3')
102
b = t_a.branch.create_checkout('b').branch
104
self.assertEqual(len(b.revision_history()), 2)
105
self.assertEqual(len(t_a.branch.revision_history()), 2)
106
# update A's tree to not have the uncomitted revision referenced.
108
t_a.commit('commit 3b')
109
self.assertRaises(BoundBranchOutOfDate, uncommit.uncommit, b)
113
def test_uncommit_bound_local(self):
114
t_a = self.make_branch_and_tree('a')
115
rev_id1 = t_a.commit('commit 1')
116
rev_id2 = t_a.commit('commit 2')
117
rev_id3 = t_a.commit('commit 3')
118
b = t_a.branch.create_checkout('b').branch
120
out, err = self.run_bzr(['uncommit', '--local', 'b', '--force'])
121
self.assertEqual(rev_id3, t_a.last_revision())
122
self.assertEqual((3, rev_id3), t_a.branch.last_revision_info())
123
self.assertEqual((2, rev_id2), b.last_revision_info())
125
def test_uncommit_revision(self):
126
wt = self.create_simple_tree()
129
out, err = self.run_bzr('uncommit -r1 --force')
131
self.assertNotContainsRe(out, 'initial commit')
132
self.assertContainsRe(out, 'second commit')
133
self.assertEqual(['a1'], wt.get_parent_ids())
134
self.assertEqual('a1', wt.branch.last_revision())
136
def test_uncommit_neg_1(self):
137
wt = self.create_simple_tree()
139
out, err = self.run_bzr('uncommit -r -1', retcode=1)
140
self.assertEqual('No revisions to uncommit.\n', out)
142
def test_uncommit_merges(self):
143
wt = self.create_simple_tree()
145
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
147
tree2.commit('unchanged', rev_id='b3')
148
tree2.commit('unchanged', rev_id='b4')
150
wt.merge_from_branch(tree2.branch)
151
wt.commit('merge b4', rev_id='a3')
153
self.assertEqual(['a3'], wt.get_parent_ids())
156
out, err = self.run_bzr('uncommit --force')
158
self.assertEqual(['a2', 'b4'], wt.get_parent_ids())
160
def test_uncommit_pending_merge(self):
161
wt = self.create_simple_tree()
162
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
163
tree2.commit('unchanged', rev_id='b3')
165
wt.branch.fetch(tree2.branch)
166
wt.set_pending_merges(['b3'])
169
out, err = self.run_bzr('uncommit --force')
170
self.assertEqual(['a1', 'b3'], wt.get_parent_ids())
172
def test_uncommit_multiple_merge(self):
173
wt = self.create_simple_tree()
175
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
176
tree2.commit('unchanged', rev_id='b3')
178
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
179
tree3.commit('unchanged', rev_id='c3')
181
wt.merge_from_branch(tree2.branch)
182
wt.commit('merge b3', rev_id='a3')
184
wt.merge_from_branch(tree3.branch)
185
wt.commit('merge c3', rev_id='a4')
187
self.assertEqual(['a4'], wt.get_parent_ids())
190
out, err = self.run_bzr('uncommit --force -r 2')
192
self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
194
def test_uncommit_merge_plus_pending(self):
195
wt = self.create_simple_tree()
197
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
198
tree2.commit('unchanged', rev_id='b3')
199
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
200
tree3.commit('unchanged', rev_id='c3')
202
wt.branch.fetch(tree2.branch)
203
wt.set_pending_merges(['b3'])
204
wt.commit('merge b3', rev_id='a3')
207
wt.merge_from_branch(tree3.branch)
209
self.assertEqual(['a3', 'c3'], wt.get_parent_ids())
212
out, err = self.run_bzr('uncommit --force -r 2')
214
self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
216
def test_uncommit_octopus_merge(self):
217
# Check that uncommit keeps the pending merges in the same order
218
# though it will also filter out ones in the ancestry
219
wt = self.create_simple_tree()
221
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
222
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
224
tree2.commit('unchanged', rev_id='b3')
225
tree3.commit('unchanged', rev_id='c3')
227
wt.merge_from_branch(tree2.branch)
228
wt.merge_from_branch(tree3.branch)
229
wt.commit('merge b3, c3', rev_id='a3')
231
tree2.commit('unchanged', rev_id='b4')
232
tree3.commit('unchanged', rev_id='c4')
234
wt.merge_from_branch(tree3.branch)
235
wt.merge_from_branch(tree2.branch)
236
wt.commit('merge b4, c4', rev_id='a4')
238
self.assertEqual(['a4'], wt.get_parent_ids())
241
out, err = self.run_bzr('uncommit --force -r 2')
243
self.assertEqual(['a2', 'c4', 'b4'], wt.get_parent_ids())
245
def test_uncommit_nonascii(self):
246
tree = self.make_branch_and_tree('tree')
247
tree.commit(u'\u1234 message')
248
out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
249
self.assertContainsRe(out, r'\? message')