1
# Copyright (C) 2005-2010 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
25
from bzrlib.tests.script import (
31
class TestUncommit(TestCaseWithTransport):
33
def create_simple_tree(self):
34
wt = self.make_branch_and_tree('tree')
35
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
36
wt.add(['a', 'b', 'c'])
37
wt.commit('initial commit', rev_id='a1')
39
self.build_tree_contents([('tree/a', 'new contents of a\n')])
40
wt.commit('second commit', rev_id='a2')
44
def test_uncommit(self):
45
"""Test uncommit functionality."""
46
wt = self.create_simple_tree()
49
out, err = self.run_bzr('uncommit --dry-run --force')
50
self.assertContainsRe(out, 'Dry-run')
51
self.assertNotContainsRe(out, 'initial commit')
52
self.assertContainsRe(out, 'second commit')
55
self.assertEqual(['a2'], wt.get_parent_ids())
57
# Uncommit, don't prompt
58
out, err = self.run_bzr('uncommit --force')
59
self.assertNotContainsRe(out, 'initial commit')
60
self.assertContainsRe(out, 'second commit')
62
# This should look like we are back in revno 1
63
self.assertEqual(['a1'], wt.get_parent_ids())
64
out, err = self.run_bzr('status')
65
self.assertEquals(out, 'modified:\n a\n')
67
def test_uncommit_interactive(self):
68
"""Uncommit seeks confirmation, and doesn't proceed without it."""
69
wt = self.create_simple_tree()
74
The above revision(s) will be removed.
75
2>Uncommit these revisions? [y/n]:
79
self.assertEqual(['a2'], wt.get_parent_ids())
81
def test_uncommit_no_history(self):
82
wt = self.make_branch_and_tree('tree')
83
out, err = self.run_bzr('uncommit --force', retcode=1)
84
self.assertEqual('', err)
85
self.assertEqual('No revisions to uncommit.\n', out)
87
def test_uncommit_checkout(self):
88
wt = self.create_simple_tree()
89
checkout_tree = wt.branch.create_checkout('checkout')
91
self.assertEqual(['a2'], checkout_tree.get_parent_ids())
94
out, err = self.run_bzr('uncommit --dry-run --force')
95
self.assertContainsRe(out, 'Dry-run')
96
self.assertNotContainsRe(out, 'initial commit')
97
self.assertContainsRe(out, 'second commit')
99
self.assertEqual(['a2'], checkout_tree.get_parent_ids())
101
out, err = self.run_bzr('uncommit --force')
102
self.assertNotContainsRe(out, 'initial commit')
103
self.assertContainsRe(out, 'second commit')
105
# uncommit in a checkout should uncommit the parent branch
106
# (but doesn't effect the other working tree)
107
self.assertEquals(['a1'], checkout_tree.get_parent_ids())
108
self.assertEquals('a1', wt.branch.last_revision())
109
self.assertEquals(['a2'], wt.get_parent_ids())
111
def test_uncommit_bound(self):
113
a = BzrDirMetaFormat1().initialize('a')
114
a.create_repository()
116
t_a = a.create_workingtree()
117
t_a.commit('commit 1')
118
t_a.commit('commit 2')
119
t_a.commit('commit 3')
120
b = t_a.branch.create_checkout('b').branch
122
self.assertEqual(len(b.revision_history()), 2)
123
self.assertEqual(len(t_a.branch.revision_history()), 2)
124
# update A's tree to not have the uncommitted revision referenced.
126
t_a.commit('commit 3b')
127
self.assertRaises(BoundBranchOutOfDate, uncommit.uncommit, b)
131
def test_uncommit_bound_local(self):
132
t_a = self.make_branch_and_tree('a')
133
rev_id1 = t_a.commit('commit 1')
134
rev_id2 = t_a.commit('commit 2')
135
rev_id3 = t_a.commit('commit 3')
136
b = t_a.branch.create_checkout('b').branch
138
out, err = self.run_bzr(['uncommit', '--local', 'b', '--force'])
139
self.assertEqual(rev_id3, t_a.last_revision())
140
self.assertEqual((3, rev_id3), t_a.branch.last_revision_info())
141
self.assertEqual((2, rev_id2), b.last_revision_info())
143
def test_uncommit_revision(self):
144
wt = self.create_simple_tree()
147
out, err = self.run_bzr('uncommit -r1 --force')
149
self.assertNotContainsRe(out, 'initial commit')
150
self.assertContainsRe(out, 'second commit')
151
self.assertEqual(['a1'], wt.get_parent_ids())
152
self.assertEqual('a1', wt.branch.last_revision())
154
def test_uncommit_neg_1(self):
155
wt = self.create_simple_tree()
157
out, err = self.run_bzr('uncommit -r -1', retcode=1)
158
self.assertEqual('No revisions to uncommit.\n', out)
160
def test_uncommit_merges(self):
161
wt = self.create_simple_tree()
163
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
165
tree2.commit('unchanged', rev_id='b3')
166
tree2.commit('unchanged', rev_id='b4')
168
wt.merge_from_branch(tree2.branch)
169
wt.commit('merge b4', rev_id='a3')
171
self.assertEqual(['a3'], wt.get_parent_ids())
174
out, err = self.run_bzr('uncommit --force')
176
self.assertEqual(['a2', 'b4'], wt.get_parent_ids())
178
def test_uncommit_pending_merge(self):
179
wt = self.create_simple_tree()
180
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
181
tree2.commit('unchanged', rev_id='b3')
183
wt.branch.fetch(tree2.branch)
184
wt.set_pending_merges(['b3'])
187
out, err = self.run_bzr('uncommit --force')
188
self.assertEqual(['a1', 'b3'], wt.get_parent_ids())
190
def test_uncommit_multiple_merge(self):
191
wt = self.create_simple_tree()
193
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
194
tree2.commit('unchanged', rev_id='b3')
196
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
197
tree3.commit('unchanged', rev_id='c3')
199
wt.merge_from_branch(tree2.branch)
200
wt.commit('merge b3', rev_id='a3')
202
wt.merge_from_branch(tree3.branch)
203
wt.commit('merge c3', rev_id='a4')
205
self.assertEqual(['a4'], wt.get_parent_ids())
208
out, err = self.run_bzr('uncommit --force -r 2')
210
self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
212
def test_uncommit_merge_plus_pending(self):
213
wt = self.create_simple_tree()
215
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
216
tree2.commit('unchanged', rev_id='b3')
217
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
218
tree3.commit('unchanged', rev_id='c3')
220
wt.branch.fetch(tree2.branch)
221
wt.set_pending_merges(['b3'])
222
wt.commit('merge b3', rev_id='a3')
225
wt.merge_from_branch(tree3.branch)
227
self.assertEqual(['a3', 'c3'], wt.get_parent_ids())
230
out, err = self.run_bzr('uncommit --force -r 2')
232
self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
234
def test_uncommit_shows_log_with_revision_id(self):
235
wt = self.create_simple_tree()
237
script = ScriptRunner()
238
script.run_script(self, """
240
$ bzr uncommit --force
244
The above revision(s) will be removed.
245
You can restore the old tip by running:
246
bzr pull . -r revid:a2
249
def test_uncommit_octopus_merge(self):
250
# Check that uncommit keeps the pending merges in the same order
251
# though it will also filter out ones in the ancestry
252
wt = self.create_simple_tree()
254
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
255
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
257
tree2.commit('unchanged', rev_id='b3')
258
tree3.commit('unchanged', rev_id='c3')
260
wt.merge_from_branch(tree2.branch)
261
wt.merge_from_branch(tree3.branch, force=True)
262
wt.commit('merge b3, c3', rev_id='a3')
264
tree2.commit('unchanged', rev_id='b4')
265
tree3.commit('unchanged', rev_id='c4')
267
wt.merge_from_branch(tree3.branch)
268
wt.merge_from_branch(tree2.branch, force=True)
269
wt.commit('merge b4, c4', rev_id='a4')
271
self.assertEqual(['a4'], wt.get_parent_ids())
274
out, err = self.run_bzr('uncommit --force -r 2')
276
self.assertEqual(['a2', 'c4', 'b4'], wt.get_parent_ids())
278
def test_uncommit_nonascii(self):
279
tree = self.make_branch_and_tree('tree')
280
tree.commit(u'\u1234 message')
281
out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
282
self.assertContainsRe(out, r'\? message')