~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_uncommit.py

Merge bzr.dev (and fix NEWS)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011, 2013, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Test the uncommit command."""
18
18
 
19
19
import os
20
20
 
21
 
from bzrlib import uncommit
 
21
from bzrlib import uncommit, workingtree
22
22
from bzrlib.bzrdir import BzrDirMetaFormat1
23
 
from bzrlib.errors import BoundBranchOutOfDate
 
23
from bzrlib.errors import BzrError, BoundBranchOutOfDate
24
24
from bzrlib.tests import TestCaseWithTransport
25
 
from bzrlib.tests.matchers import ContainsNoVfsCalls
26
 
from bzrlib.tests.script import (
27
 
    run_script,
28
 
    ScriptRunner,
29
 
    )
30
25
 
31
26
 
32
27
class TestUncommit(TestCaseWithTransport):
37
32
        wt.add(['a', 'b', 'c'])
38
33
        wt.commit('initial commit', rev_id='a1')
39
34
 
40
 
        self.build_tree_contents([('tree/a', 'new contents of a\n')])
 
35
        open('tree/a', 'wb').write('new contents of a\n')
41
36
        wt.commit('second commit', rev_id='a2')
42
37
 
43
38
        return wt
47
42
        wt = self.create_simple_tree()
48
43
 
49
44
        os.chdir('tree')
50
 
        out, err = self.run_bzr('uncommit --dry-run --force')
 
45
        out, err = self.run_bzr('uncommit', '--dry-run', '--force')
51
46
        self.assertContainsRe(out, 'Dry-run')
52
47
        self.assertNotContainsRe(out, 'initial commit')
53
48
        self.assertContainsRe(out, 'second commit')
54
49
 
55
50
        # Nothing has changed
56
 
        self.assertEqual(['a2'], wt.get_parent_ids())
 
51
        self.assertEqual('a2', wt.last_revision())
57
52
 
58
53
        # Uncommit, don't prompt
59
 
        out, err = self.run_bzr('uncommit --force')
 
54
        out, err = self.run_bzr('uncommit', '--force')
60
55
        self.assertNotContainsRe(out, 'initial commit')
61
56
        self.assertContainsRe(out, 'second commit')
62
57
 
63
58
        # This should look like we are back in revno 1
64
 
        self.assertEqual(['a1'], wt.get_parent_ids())
 
59
        self.assertEqual('a1', wt.last_revision())
65
60
        out, err = self.run_bzr('status')
66
 
        self.assertEqual(out, 'modified:\n  a\n')
67
 
 
68
 
    def test_uncommit_interactive(self):
69
 
        """Uncommit seeks confirmation, and doesn't proceed without it."""
70
 
        wt = self.create_simple_tree()
71
 
        os.chdir('tree')
72
 
        run_script(self, """    
73
 
        $ bzr uncommit
74
 
        ...
75
 
        The above revision(s) will be removed.
76
 
        2>Uncommit these revisions? ([y]es, [n]o): no
77
 
        <n
78
 
        Canceled
79
 
        """)
80
 
        self.assertEqual(['a2'], wt.get_parent_ids())
81
 
 
82
 
    def test_uncommit_no_history(self):
83
 
        wt = self.make_branch_and_tree('tree')
84
 
        out, err = self.run_bzr('uncommit --force', retcode=1)
85
 
        self.assertEqual('', err)
86
 
        self.assertEqual('No revisions to uncommit.\n', out)
 
61
        self.assertEquals(out, 'modified:\n  a\n')
87
62
 
88
63
    def test_uncommit_checkout(self):
89
64
        wt = self.create_simple_tree()
90
 
        checkout_tree = wt.branch.create_checkout('checkout')
91
 
 
92
 
        self.assertEqual(['a2'], checkout_tree.get_parent_ids())
 
65
 
 
66
        checkout_tree = wt.bzrdir.sprout('checkout').open_workingtree()
 
67
        checkout_tree.branch.bind(wt.branch)
 
68
 
 
69
        self.assertEqual('a2', checkout_tree.last_revision())
93
70
 
94
71
        os.chdir('checkout')
95
 
        out, err = self.run_bzr('uncommit --dry-run --force')
 
72
        out, err = self.run_bzr('uncommit', '--dry-run', '--force')
96
73
        self.assertContainsRe(out, 'Dry-run')
97
74
        self.assertNotContainsRe(out, 'initial commit')
98
75
        self.assertContainsRe(out, 'second commit')
99
76
 
100
 
        self.assertEqual(['a2'], checkout_tree.get_parent_ids())
 
77
        self.assertEqual('a2', checkout_tree.last_revision())
101
78
 
102
 
        out, err = self.run_bzr('uncommit --force')
 
79
        out, err = self.run_bzr('uncommit', '--force')
103
80
        self.assertNotContainsRe(out, 'initial commit')
104
81
        self.assertContainsRe(out, 'second commit')
105
82
 
106
83
        # uncommit in a checkout should uncommit the parent branch
107
84
        # (but doesn't effect the other working tree)
108
 
        self.assertEqual(['a1'], checkout_tree.get_parent_ids())
109
 
        self.assertEqual('a1', wt.branch.last_revision())
110
 
        self.assertEqual(['a2'], wt.get_parent_ids())
 
85
        self.assertEquals('a1', checkout_tree.last_revision())
 
86
        self.assertEquals('a1', wt.branch.last_revision())
 
87
        self.assertEquals('a2', wt.last_revision())
111
88
 
112
89
    def test_uncommit_bound(self):
113
90
        os.mkdir('a')
114
91
        a = BzrDirMetaFormat1().initialize('a')
115
92
        a.create_repository()
116
93
        a.create_branch()
117
 
        t_a = a.create_workingtree()
118
 
        t_a.commit('commit 1')
119
 
        t_a.commit('commit 2')
120
 
        t_a.commit('commit 3')
121
 
        b = t_a.branch.create_checkout('b').branch
 
94
        t = a.create_workingtree()
 
95
        t.commit('commit 1')
 
96
        t.commit('commit 2')
 
97
        t.commit('commit 3')
 
98
        b = t.bzrdir.sprout('b').open_branch()
 
99
        b.bind(t.branch)
122
100
        uncommit.uncommit(b)
123
 
        self.assertEqual(b.last_revision_info()[0], 2)
124
 
        self.assertEqual(t_a.branch.last_revision_info()[0], 2)
125
 
        # update A's tree to not have the uncommitted revision referenced.
126
 
        t_a.update()
127
 
        t_a.commit('commit 3b')
 
101
        t.set_last_revision(t.branch.last_revision())
 
102
        self.assertEqual(len(b.revision_history()), 2)
 
103
        self.assertEqual(len(t.branch.revision_history()), 2)
 
104
        t.commit('commit 3b')
128
105
        self.assertRaises(BoundBranchOutOfDate, uncommit.uncommit, b)
129
 
        b.pull(t_a.branch)
 
106
        b.pull(t.branch)
130
107
        uncommit.uncommit(b)
131
108
 
132
 
    def test_uncommit_bound_local(self):
133
 
        t_a = self.make_branch_and_tree('a')
134
 
        rev_id1 = t_a.commit('commit 1')
135
 
        rev_id2 = t_a.commit('commit 2')
136
 
        rev_id3 = t_a.commit('commit 3')
137
 
        b = t_a.branch.create_checkout('b').branch
138
 
 
139
 
        out, err = self.run_bzr(['uncommit', '--local', 'b', '--force'])
140
 
        self.assertEqual(rev_id3, t_a.last_revision())
141
 
        self.assertEqual((3, rev_id3), t_a.branch.last_revision_info())
142
 
        self.assertEqual((2, rev_id2), b.last_revision_info())
143
 
 
144
109
    def test_uncommit_revision(self):
145
110
        wt = self.create_simple_tree()
146
111
 
147
112
        os.chdir('tree')
148
 
        out, err = self.run_bzr('uncommit -r1 --force')
 
113
        out, err = self.run_bzr('uncommit', '-r1', '--force')
149
114
 
150
115
        self.assertNotContainsRe(out, 'initial commit')
151
116
        self.assertContainsRe(out, 'second commit')
152
 
        self.assertEqual(['a1'], wt.get_parent_ids())
 
117
        self.assertEqual('a1', wt.last_revision())
153
118
        self.assertEqual('a1', wt.branch.last_revision())
154
119
 
155
120
    def test_uncommit_neg_1(self):
156
121
        wt = self.create_simple_tree()
157
122
        os.chdir('tree')
158
 
        out, err = self.run_bzr('uncommit -r -1', retcode=1)
 
123
        out, err = self.run_bzr('uncommit', '-r', '-1', retcode=1)
159
124
        self.assertEqual('No revisions to uncommit.\n', out)
160
125
 
161
126
    def test_uncommit_merges(self):
166
131
        tree2.commit('unchanged', rev_id='b3')
167
132
        tree2.commit('unchanged', rev_id='b4')
168
133
 
169
 
        wt.merge_from_branch(tree2.branch)
 
134
        wt.branch.fetch(tree2.branch)
 
135
        wt.set_pending_merges(['b4'])
170
136
        wt.commit('merge b4', rev_id='a3')
171
137
 
172
 
        self.assertEqual(['a3'], wt.get_parent_ids())
 
138
        self.assertEqual('a3', wt.last_revision())
 
139
        self.assertEqual([], wt.pending_merges())
173
140
 
174
141
        os.chdir('tree')
175
 
        out, err = self.run_bzr('uncommit --force')
 
142
        out, err = self.run_bzr('uncommit', '--force')
176
143
 
177
 
        self.assertEqual(['a2', 'b4'], wt.get_parent_ids())
 
144
        self.assertEqual('a2', wt.last_revision())
 
145
        self.assertEqual(['b4'], wt.pending_merges())
178
146
 
179
147
    def test_uncommit_pending_merge(self):
180
148
        wt = self.create_simple_tree()
185
153
        wt.set_pending_merges(['b3'])
186
154
 
187
155
        os.chdir('tree')
188
 
        out, err = self.run_bzr('uncommit --force')
189
 
        self.assertEqual(['a1', 'b3'], wt.get_parent_ids())
 
156
        out, err = self.run_bzr('uncommit', '--force')
 
157
        self.assertEqual('a1', wt.last_revision())
 
158
        self.assertEqual(['b3'], wt.pending_merges())
190
159
 
191
160
    def test_uncommit_multiple_merge(self):
192
161
        wt = self.create_simple_tree()
193
162
 
194
163
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
 
164
 
195
165
        tree2.commit('unchanged', rev_id='b3')
196
 
 
197
 
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
198
 
        tree3.commit('unchanged', rev_id='c3')
199
 
 
200
 
        wt.merge_from_branch(tree2.branch)
 
166
        wt.branch.fetch(tree2.branch)
 
167
        wt.set_pending_merges(['b3'])
201
168
        wt.commit('merge b3', rev_id='a3')
202
169
 
203
 
        wt.merge_from_branch(tree3.branch)
204
 
        wt.commit('merge c3', rev_id='a4')
 
170
        tree2.commit('unchanged', rev_id='b4')
 
171
        wt.branch.fetch(tree2.branch)
 
172
        wt.set_pending_merges(['b4'])
 
173
        wt.commit('merge b4', rev_id='a4')
205
174
 
206
 
        self.assertEqual(['a4'], wt.get_parent_ids())
 
175
        self.assertEqual('a4', wt.last_revision())
 
176
        self.assertEqual([], wt.pending_merges())
207
177
 
208
178
        os.chdir('tree')
209
 
        out, err = self.run_bzr('uncommit --force -r 2')
 
179
        out, err = self.run_bzr('uncommit', '--force', '-r', '2')
210
180
 
211
 
        self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
 
181
        self.assertEqual('a2', wt.last_revision())
 
182
        self.assertEqual(['b3', 'b4'], wt.pending_merges())
212
183
 
213
184
    def test_uncommit_merge_plus_pending(self):
214
185
        wt = self.create_simple_tree()
215
186
 
216
187
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
 
188
 
217
189
        tree2.commit('unchanged', rev_id='b3')
218
 
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
219
 
        tree3.commit('unchanged', rev_id='c3')
220
 
 
221
190
        wt.branch.fetch(tree2.branch)
222
191
        wt.set_pending_merges(['b3'])
223
192
        wt.commit('merge b3', rev_id='a3')
224
193
 
225
 
 
226
 
        wt.merge_from_branch(tree3.branch)
227
 
 
228
 
        self.assertEqual(['a3', 'c3'], wt.get_parent_ids())
 
194
        tree2.commit('unchanged', rev_id='b4')
 
195
        wt.branch.fetch(tree2.branch)
 
196
        wt.set_pending_merges(['b4'])
 
197
 
 
198
        self.assertEqual('a3', wt.last_revision())
 
199
        self.assertEqual(['b4'], wt.pending_merges())
229
200
 
230
201
        os.chdir('tree')
231
 
        out, err = self.run_bzr('uncommit --force -r 2')
232
 
 
233
 
        self.assertEqual(['a2', 'b3', 'c3'], wt.get_parent_ids())
234
 
 
235
 
    def test_uncommit_shows_log_with_revision_id(self):
236
 
        wt = self.create_simple_tree()
237
 
 
238
 
        script = ScriptRunner()
239
 
        script.run_script(self, """
240
 
$ cd tree
241
 
$ bzr uncommit --force 
242
 
    2 ...
243
 
      second commit
244
 
...
245
 
The above revision(s) will be removed.
246
 
You can restore the old tip by running:
247
 
  bzr pull . -r revid:a2
248
 
""")
 
202
        out, err = self.run_bzr('uncommit', '--force', '-r', '2')
 
203
 
 
204
        self.assertEqual('a2', wt.last_revision())
 
205
        self.assertEqual(['b3', 'b4'], wt.pending_merges())
249
206
 
250
207
    def test_uncommit_octopus_merge(self):
251
208
        # Check that uncommit keeps the pending merges in the same order
252
 
        # though it will also filter out ones in the ancestry
253
209
        wt = self.create_simple_tree()
254
210
 
255
211
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
257
213
 
258
214
        tree2.commit('unchanged', rev_id='b3')
259
215
        tree3.commit('unchanged', rev_id='c3')
260
 
 
261
 
        wt.merge_from_branch(tree2.branch)
262
 
        wt.merge_from_branch(tree3.branch, force=True)
 
216
        wt.branch.fetch(tree2.branch)
 
217
        wt.branch.fetch(tree3.branch)
 
218
        wt.set_pending_merges(['b3', 'c3'])
263
219
        wt.commit('merge b3, c3', rev_id='a3')
264
220
 
265
221
        tree2.commit('unchanged', rev_id='b4')
266
222
        tree3.commit('unchanged', rev_id='c4')
267
 
 
268
 
        wt.merge_from_branch(tree3.branch)
269
 
        wt.merge_from_branch(tree2.branch, force=True)
 
223
        wt.branch.fetch(tree2.branch)
 
224
        wt.branch.fetch(tree3.branch)
 
225
        wt.set_pending_merges(['c4', 'b4'])
270
226
        wt.commit('merge b4, c4', rev_id='a4')
271
227
 
272
 
        self.assertEqual(['a4'], wt.get_parent_ids())
 
228
        self.assertEqual('a4', wt.last_revision())
 
229
        self.assertEqual([], wt.pending_merges())
273
230
 
274
231
        os.chdir('tree')
275
 
        out, err = self.run_bzr('uncommit --force -r 2')
276
 
 
277
 
        self.assertEqual(['a2', 'c4', 'b4'], wt.get_parent_ids())
278
 
 
279
 
    def test_uncommit_nonascii(self):
280
 
        tree = self.make_branch_and_tree('tree')
281
 
        tree.commit(u'\u1234 message')
282
 
        out, err = self.run_bzr('uncommit --force tree', encoding='ascii')
283
 
        self.assertContainsRe(out, r'\? message')
284
 
 
285
 
    def test_uncommit_removes_tags(self):
286
 
        tree = self.make_branch_and_tree('tree')
287
 
        revid = tree.commit('message')
288
 
        tree.branch.tags.set_tag("atag", revid)
289
 
        out, err = self.run_bzr('uncommit --force tree')
290
 
        self.assertEqual({}, tree.branch.tags.get_tag_dict())
291
 
 
292
 
    def test_uncommit_keep_tags(self):
293
 
        tree = self.make_branch_and_tree('tree')
294
 
        revid = tree.commit('message')
295
 
        tree.branch.tags.set_tag("atag", revid)
296
 
        out, err = self.run_bzr('uncommit --keep-tags --force tree')
297
 
        self.assertEqual({"atag": revid}, tree.branch.tags.get_tag_dict())
298
 
 
299
 
 
300
 
class TestSmartServerUncommit(TestCaseWithTransport):
301
 
 
302
 
    def test_uncommit(self):
303
 
        self.setup_smart_server_with_call_log()
304
 
        t = self.make_branch_and_tree('from')
305
 
        for count in range(2):
306
 
            t.commit(message='commit %d' % count)
307
 
        self.reset_smart_call_log()
308
 
        out, err = self.run_bzr(['uncommit', '--force', self.get_url('from')])
309
 
        # This figure represent the amount of work to perform this use case. It
310
 
        # is entirely ok to reduce this number if a test fails due to rpc_count
311
 
        # being too low. If rpc_count increases, more network roundtrips have
312
 
        # become necessary for this use case. Please do not adjust this number
313
 
        # upwards without agreement from bzr's network support maintainers.
314
 
        self.assertLength(14, self.hpss_calls)
315
 
        self.assertLength(1, self.hpss_connections)
316
 
        self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
317
 
 
318
 
 
319
 
class TestInconsistentDelta(TestCaseWithTransport):
320
 
    # See https://bugs.launchpad.net/bzr/+bug/855155
321
 
    # See https://bugs.launchpad.net/bzr/+bug/1100385
322
 
    # bzr uncommit may result in error
323
 
    # 'An inconsistent delta was supplied involving'
324
 
 
325
 
    def test_inconsistent_delta(self):
326
 
        # Script taken from https://bugs.launchpad.net/bzr/+bug/855155/comments/26
327
 
        wt = self.make_branch_and_tree('test')
328
 
        self.build_tree(['test/a/', 'test/a/b', 'test/a/c'])
329
 
        wt.add(['a', 'a/b', 'a/c'])
330
 
        wt.commit('initial commit', rev_id='a1')
331
 
        wt.remove(['a/b', 'a/c'])
332
 
        wt.commit('remove b and c', rev_id='a2')
333
 
        self.run_bzr("uncommit --force test")
 
232
        out, err = self.run_bzr('uncommit', '--force', '-r', '2')
 
233
 
 
234
        self.assertEqual('a2', wt.last_revision())
 
235
        self.assertEqual(['b3', 'c3', 'c4', 'b4'], wt.pending_merges())