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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
self.build_tree_contents([('tree/a', '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 uncommitted 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_shows_log_with_revision_id(self):
217
wt = self.create_simple_tree()
219
out, err = self.run_bzr('uncommit --force', working_dir='tree')
220
self.assertContainsRe(out, r'second commit')
221
self.assertContainsRe(err, r'You can restore the old tip by running')
222
self.assertContainsRe(err, r'bzr pull . -r revid:a2')
224
def test_uncommit_octopus_merge(self):
225
# Check that uncommit keeps the pending merges in the same order
226
# though it will also filter out ones in the ancestry
227
wt = self.create_simple_tree()
229
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
230
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
232
tree2.commit('unchanged', rev_id='b3')
233
tree3.commit('unchanged', rev_id='c3')
235
wt.merge_from_branch(tree2.branch)
236
wt.merge_from_branch(tree3.branch, force=True)
237
wt.commit('merge b3, c3', rev_id='a3')
239
tree2.commit('unchanged', rev_id='b4')
240
tree3.commit('unchanged', rev_id='c4')
242
wt.merge_from_branch(tree3.branch)
243
wt.merge_from_branch(tree2.branch, force=True)
244
wt.commit('merge b4, c4', rev_id='a4')
246
self.assertEqual(['a4'], wt.get_parent_ids())
249
out, err = self.run_bzr('uncommit --force -r 2')
251
self.assertEqual(['a2', 'c4', 'b4'], wt.get_parent_ids())
253
def test_uncommit_nonascii(self):
254
tree = self.make_branch_and_tree('tree')
255
tree.commit(u'\u1234 message')
256
out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
257
self.assertContainsRe(out, r'\? message')