Merge lp:~jelmer/brz/amend into lp:brz

Proposed by Jelmer Vernooij
Status: Needs review
Proposed branch: lp:~jelmer/brz/amend
Merge into: lp:brz
Diff against target: 323 lines (+106/-35)
6 files modified
breezy/builtins.py (+30/-11)
breezy/commit.py (+28/-14)
breezy/msgeditor.py (+11/-3)
breezy/mutabletree.py (+8/-6)
breezy/tests/blackbox/test_commit.py (+26/-1)
doc/en/release-notes/brz-3.1.txt (+3/-0)
To merge this branch: bzr merge lp:~jelmer/brz/amend
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+368874@code.launchpad.net

Commit message

Add a --amend option to commit.

Description of the change

Add a --amend option to commit.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

All looks pretty sane. Adding new positional args can lead to annoying compat bugs, but `make_commit_message_template_encoded()` is presumably not widely used. Could probably do with some more focused tests for this later, but for now just see one inline nit.

review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Unmerged revisions

6780. By Jelmer Vernooij

Fix docstring.

6779. By Jelmer Vernooij

Fix up tests for amend.

6778. By Jelmer Vernooij

Use WorkingTree.update during amend.

6777. By Jelmer Vernooij

merge trunk.

6776. By Jelmer Vernooij

Merge trunk.

6775. By Jelmer Vernooij

Add tests for amend.

6774. By Jelmer Vernooij

Merge lock context branch.

6773. By Jelmer Vernooij

Add --amend option to commit.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/builtins.py'
2--- breezy/builtins.py 2019-06-15 12:04:34 +0000
3+++ breezy/builtins.py 2019-06-16 02:56:15 +0000
4@@ -3537,7 +3537,11 @@
5 Option('lossy',
6 help='When committing to a foreign version control '
7 'system do not push data that can not be natively '
8- 'represented.'), ]
9+ 'represented.'),
10+ Option('amend',
11+ help='Rather than create a new commit, amend the last '
12+ 'one.'),
13+ ]
14 aliases = ['ci', 'checkin']
15
16 def _iter_bug_urls(self, bugs, branch, status):
17@@ -3578,7 +3582,7 @@
18 def run(self, message=None, file=None, verbose=False, selected_list=None,
19 unchanged=False, strict=False, local=False, fixes=None, bugs=None,
20 author=None, show_diff=False, exclude=None, commit_time=None,
21- lossy=False):
22+ lossy=False, amend=False):
23 import itertools
24 from .commit import (
25 PointlessCommit,
26@@ -3592,7 +3596,7 @@
27 generate_commit_message_template,
28 make_commit_message_template_encoded,
29 set_commit_message,
30- )
31+ )
32
33 commit_stamp = offset = None
34 if commit_time is not None:
35@@ -3611,6 +3615,18 @@
36 # selected-file merge commit is not done yet
37 selected_list = []
38
39+ template_message = None
40+
41+ if amend:
42+ rev = tree.branch.repository.get_revision(tree.last_revision())
43+ properties.update(rev.properties)
44+ template_message = rev.message
45+ if author is None:
46+ author = rev.get_apparent_authors()
47+ parents = rev.parent_ids
48+ else:
49+ parents = None
50+
51 if fixes is None:
52 fixes = []
53 if bugs is None:
54@@ -3656,9 +3672,10 @@
55 else:
56 # No message supplied: make one up.
57 # text is the status of the tree
58- text = make_commit_message_template_encoded(tree,
59- selected_list, diff=show_diff,
60- output_encoding=osutils.get_user_encoding())
61+ text = make_commit_message_template_encoded(
62+ tree, commit_obj.basis_revid, selected_list,
63+ diff=show_diff,
64+ output_encoding=osutils.get_user_encoding())
65 # start_message is the template generated from hooks
66 # XXX: Warning - looks like hooks return unicode,
67 # make_commit_message_template_encoded returns user encoding.
68@@ -3666,13 +3683,15 @@
69 # avoid this.
70 my_message = set_commit_message(commit_obj)
71 if my_message is None:
72- start_message = generate_commit_message_template(
73- commit_obj)
74+ if template_message is not None:
75+ start_message = template_message
76+ else:
77+ start_message = generate_commit_message_template(commit_obj)
78 if start_message is not None:
79 start_message = start_message.encode(
80 osutils.get_user_encoding())
81- my_message = edit_commit_message_encoded(text,
82- start_message=start_message)
83+ my_message = edit_commit_message_encoded(
84+ text, start_message=start_message)
85 if my_message is None:
86 raise errors.BzrCommandError(gettext("please specify a commit"
87 " message with either --message or --file"))
88@@ -3695,7 +3714,7 @@
89 authors=author, timestamp=commit_stamp,
90 timezone=offset,
91 exclude=tree.safe_relpath_files(exclude),
92- lossy=lossy)
93+ lossy=lossy, parents=parents)
94 except PointlessCommit:
95 raise errors.BzrCommandError(gettext("No changes to commit."
96 " Please 'brz add' the files you want to commit, or use"
97
98=== modified file 'breezy/commit.py'
99--- breezy/commit.py 2019-06-15 15:59:17 +0000
100+++ breezy/commit.py 2019-06-16 02:56:15 +0000
101@@ -245,7 +245,8 @@
102 recursive='down',
103 exclude=None,
104 possible_master_transports=None,
105- lossy=False):
106+ lossy=False,
107+ parents=None):
108 """Commit working copy as a new revision.
109
110 :param message: the commit message (it or message_callback is required)
111@@ -303,12 +304,13 @@
112 recursive=recursive,
113 exclude=exclude,
114 possible_master_transports=possible_master_transports,
115- lossy=lossy)
116+ lossy=lossy,
117+ parents=parents)
118
119 def _commit(self, operation, message, timestamp, timezone, committer,
120 specific_files, rev_id, allow_pointless, strict, verbose,
121 working_tree, local, reporter, message_callback, recursive,
122- exclude, possible_master_transports, lossy):
123+ exclude, possible_master_transports, lossy, parents):
124 mutter('preparing to commit')
125
126 if working_tree is None:
127@@ -359,11 +361,21 @@
128
129 self.work_tree.lock_write()
130 operation.add_cleanup(self.work_tree.unlock)
131- self.parents = self.work_tree.get_parent_ids()
132+ if parents is None:
133+ parents = self.work_tree.get_parent_ids()
134+ self.parents = parents
135 self.pb = ui.ui_factory.nested_progress_bar()
136 operation.add_cleanup(self.pb.finished)
137- self.basis_revid = self.work_tree.last_revision()
138- self.basis_tree = self.work_tree.basis_tree()
139+ if len(parents) > 0:
140+ self.basis_revid = parents[0]
141+ else:
142+ self.basis_revid = breezy.revision.NULL_REVISION
143+ self.wt_basis_tree = self.work_tree.basis_tree()
144+ try:
145+ self.basis_tree = self.work_tree.revision_tree(self.basis_revid)
146+ except errors.NoSuchRevisionInTree:
147+ self.basis_tree = self.branch.repository.revision_tree(
148+ self.basis_revid)
149 self.basis_tree.lock_read()
150 operation.add_cleanup(self.basis_tree.unlock)
151 # Cannot commit with conflicts present.
152@@ -462,8 +474,12 @@
153 # as updating its basis and unversioning paths that were missing.
154 self.work_tree.unversion(self.deleted_paths)
155 self._set_progress_stage("Updating the working tree")
156- self.work_tree.update_basis_by_delta(self.rev_id,
157- self.builder.get_basis_delta())
158+ if self.work_tree.last_revision() == self.basis_revid:
159+ invdelta = self.builder.get_basis_delta()
160+ self.work_tree.update_basis_by_delta(self.rev_id, invdelta)
161+ else:
162+ with self.wt_basis_tree.lock_read():
163+ self.work_tree.set_last_revision(self.rev_id)
164 self.reporter.completed(new_revno, self.rev_id)
165 self._process_post_hooks(old_revno, new_revno)
166 return self.rev_id
167@@ -587,15 +603,13 @@
168 # - in a checkout scenario the tree may have no
169 # parents but the branch may do.
170 first_tree_parent = breezy.revision.NULL_REVISION
171- try:
172- old_revno, master_last = self.master_branch.last_revision_info()
173- except errors.UnsupportedOperation:
174- master_last = self.master_branch.last_revision()
175- old_revno = self.branch.revision_id_to_revno(master_last)
176+ master_last = self.master_branch.last_revision()
177 if master_last != first_tree_parent:
178 if master_last != breezy.revision.NULL_REVISION:
179 raise errors.OutOfDateTree(self.work_tree)
180- if self.branch.repository.has_revision(first_tree_parent):
181+
182+ if self.branch.repository.has_revision(self.basis_revid):
183+ old_revno = self.branch.revision_id_to_revno(self.basis_revid)
184 new_revno = old_revno + 1
185 else:
186 # ghost parents never appear in revision history.
187
188=== modified file 'breezy/msgeditor.py'
189--- breezy/msgeditor.py 2019-06-16 01:03:51 +0000
190+++ breezy/msgeditor.py 2019-06-16 02:56:15 +0000
191@@ -32,7 +32,10 @@
192 transport,
193 ui,
194 )
195-from .errors import BzrError
196+from .errors import (
197+ BzrError,
198+ NoSuchRevisionInTree,
199+ )
200 from .hooks import Hooks
201 from .sixish import (
202 BytesIO,
203@@ -267,12 +270,17 @@
204 return status_tmp.getvalue()
205
206
207-def make_commit_message_template_encoded(working_tree, specific_files,
208+def make_commit_message_template_encoded(working_tree, basis_revid, specific_files,
209 diff=None, output_encoding='utf-8'):
210 """Prepare a template file for a commit into a branch.
211
212 Returns an encoded string.
213 """
214+ try:
215+ basis_tree = working_tree.revision_tree(basis_revid)
216+ except NoSuchRevisionInTree:
217+ basis_tree = working_tree.branch.repository.revision_tree(basis_revid)
218+
219 # TODO: make provision for this to be overridden or modified by a hook
220 #
221 # TODO: Rather than running the status command, should prepare a draft of
222@@ -285,7 +293,7 @@
223
224 if diff:
225 stream = BytesIO()
226- show_diff_trees(working_tree.basis_tree(),
227+ show_diff_trees(basis_tree,
228 working_tree, stream, specific_files,
229 path_encoding=output_encoding)
230 template = template + b'\n' + stream.getvalue()
231
232=== modified file 'breezy/mutabletree.py'
233--- breezy/mutabletree.py 2019-06-15 12:04:34 +0000
234+++ breezy/mutabletree.py 2019-06-16 02:56:15 +0000
235@@ -156,7 +156,7 @@
236
237 def commit(self, message=None, revprops=None, *args, **kwargs):
238 # avoid circular imports
239- from breezy import commit
240+ from . import commit
241 possible_master_transports = []
242 with self.lock_write():
243 revprops = commit.Commit.update_revprops(
244@@ -165,14 +165,16 @@
245 kwargs.pop('authors', None),
246 kwargs.get('local', False),
247 possible_master_transports)
248- # args for wt.commit start at message from the Commit.commit method,
249+ # args for wt.commit start at message from the Commit.commit
250+ # method,
251 args = (message, ) + args
252 for hook in MutableTree.hooks['start_commit']:
253 hook(self)
254- committed_id = commit.Commit().commit(working_tree=self,
255- revprops=revprops,
256- possible_master_transports=possible_master_transports,
257- *args, **kwargs)
258+ committed_id = commit.Commit().commit(
259+ working_tree=self,
260+ revprops=revprops,
261+ possible_master_transports=possible_master_transports,
262+ *args, **kwargs)
263 post_hook_params = PostCommitHookParams(self)
264 for hook in MutableTree.hooks['post_commit']:
265 hook(post_hook_params)
266
267=== modified file 'breezy/tests/blackbox/test_commit.py'
268--- breezy/tests/blackbox/test_commit.py 2018-11-16 11:37:47 +0000
269+++ breezy/tests/blackbox/test_commit.py 2019-06-16 02:56:15 +0000
270@@ -877,6 +877,31 @@
271 ['Unable to determine your name'],
272 ['commit', '-m', 'initial'], working_dir='foo')
273
274+ def test_commit_amend(self):
275+ """Ensure --amend works."""
276+ tree = self.make_branch_and_tree('foo')
277+ self.build_tree_contents([('foo/foo.txt', 'hello')])
278+ self.run_bzr(['add'], working_dir='foo')
279+ out, err = self.run_bzr("commit -m original\\ message foo/foo.txt")
280+ revid1 = tree.last_revision()
281+ self.assertEqualDiff(out, '')
282+ self.assertContainsRe(err, '^Committing to: .*\n'
283+ 'added foo\.txt\n'
284+ 'Committed revision 1\.\n$')
285+ self.build_tree_contents([('foo/foo.txt', 'hello again')])
286+ out, err = self.run_bzr("commit --amend -m new\\ message foo/foo.txt")
287+ self.assertEqualDiff(out, '')
288+ self.assertContainsRe(err, '^Committing to: .*\n'
289+ 'added foo\.txt\n'
290+ 'Committed revision 1\.\n$')
291+ self.assertEqualDiff(out, '')
292+ revid2 = tree.last_revision()
293+ self.assertNotEqual(revid1, revid2)
294+ self.assertEqual('hello again', tree.get_file_text('foo.txt'))
295+ basis_tree = tree.basis_tree()
296+ with basis_tree.lock_read():
297+ self.assertEqual('hello again', basis_tree.get_file_text('foo.txt'))
298+
299 def test_commit_recursive_checkout(self):
300 """Ensure that a commit to a recursive checkout fails cleanly.
301 """
302@@ -925,7 +950,7 @@
303 # being too low. If rpc_count increases, more network roundtrips have
304 # become necessary for this use case. Please do not adjust this number
305 # upwards without agreement from bzr's network support maintainers.
306- self.assertLength(211, self.hpss_calls)
307+ self.assertLength(212, self.hpss_calls)
308 self.assertLength(2, self.hpss_connections)
309 self.expectFailure("commit still uses VFS calls",
310 self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
311
312=== modified file 'doc/en/release-notes/brz-3.1.txt'
313--- doc/en/release-notes/brz-3.1.txt 2019-06-15 19:09:08 +0000
314+++ doc/en/release-notes/brz-3.1.txt 2019-06-16 02:56:15 +0000
315@@ -43,6 +43,9 @@
316 * Automatically upgrade to branch format 8 when setting branch references.
317 (Jelmer Vernooij)
318
319+* A new ``--amend`` option has been added to ``brz commit``.
320+ (Jelmer Vernooij, #507529)
321+
322 Bug Fixes
323 *********
324

Subscribers

People subscribed via source and target branches