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()
177
tree2.commit('unchanged', rev_id='b3')
179
wt.merge_from_branch(tree2.branch)
180
wt.commit('merge b3', rev_id='a3')
182
tree2.commit('unchanged', rev_id='b4')
184
wt.merge_from_branch(tree2.branch)
185
wt.commit('merge b4', 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', 'b4'], 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()
199
tree2.commit('unchanged', rev_id='b3')
200
wt.branch.fetch(tree2.branch)
201
wt.set_pending_merges(['b3'])
202
wt.commit('merge b3', rev_id='a3')
204
tree2.commit('unchanged', rev_id='b4')
205
wt.branch.fetch(tree2.branch)
206
wt.set_pending_merges(['b4'])
208
self.assertEqual(['a3', 'b4'], wt.get_parent_ids())
211
out, err = self.run_bzr('uncommit --force -r 2')
213
self.assertEqual(['a2', 'b3', 'b4'], wt.get_parent_ids())
215
def test_uncommit_octopus_merge(self):
216
# Check that uncommit keeps the pending merges in the same order
217
wt = self.create_simple_tree()
219
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
220
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
222
tree2.commit('unchanged', rev_id='b3')
223
tree3.commit('unchanged', rev_id='c3')
225
wt.merge_from_branch(tree2.branch)
226
wt.merge_from_branch(tree3.branch)
227
wt.commit('merge b3, c3', rev_id='a3')
229
tree2.commit('unchanged', rev_id='b4')
230
tree3.commit('unchanged', rev_id='c4')
232
wt.merge_from_branch(tree3.branch)
233
wt.merge_from_branch(tree2.branch)
234
wt.commit('merge b4, c4', rev_id='a4')
236
self.assertEqual(['a4'], wt.get_parent_ids())
239
out, err = self.run_bzr('uncommit --force -r 2')
241
self.assertEqual(['a2', 'b3', 'c3', 'c4', 'b4'], wt.get_parent_ids())
243
def test_uncommit_nonascii(self):
244
tree = self.make_branch_and_tree('tree')
245
tree.commit(u'\u1234 message')
246
out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
247
self.assertContainsRe(out, r'\? message')