Mercurial > public > mercurial-scm > hg
comparison mercurial/commands.py @ 5775:2dd202a6e15b
bisect: make bisect a built-in command
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 31 Dec 2007 18:20:34 -0600 |
parents | 8a5d8fb59ed2 |
children | 35ec669cdd43 |
comparison
equal
deleted
inserted
replaced
5774:c850a8640981 | 5775:2dd202a6e15b |
---|---|
9 from i18n import _ | 9 from i18n import _ |
10 import os, re, sys, urllib | 10 import os, re, sys, urllib |
11 import hg, util, revlog, bundlerepo, extensions | 11 import hg, util, revlog, bundlerepo, extensions |
12 import difflib, patch, time, help, mdiff, tempfile | 12 import difflib, patch, time, help, mdiff, tempfile |
13 import errno, version, socket | 13 import errno, version, socket |
14 import archival, changegroup, cmdutil, hgweb.server, sshserver | 14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect |
15 | 15 |
16 # Commands start here, listed alphabetically | 16 # Commands start here, listed alphabetically |
17 | 17 |
18 def add(ui, repo, *pats, **opts): | 18 def add(ui, repo, *pats, **opts): |
19 """add the specified files on the next commit | 19 """add the specified files on the next commit |
243 else: | 243 else: |
244 ui.status(_('the backout changeset is a new head - ' | 244 ui.status(_('the backout changeset is a new head - ' |
245 'do not forget to merge\n')) | 245 'do not forget to merge\n')) |
246 ui.status(_('(use "backout --merge" ' | 246 ui.status(_('(use "backout --merge" ' |
247 'if you want to auto-merge)\n')) | 247 'if you want to auto-merge)\n')) |
248 | |
249 def bisect(ui, repo, rev=None, extra=None, | |
250 reset=None, good=None, bad=None, skip=None, noupdate=None): | |
251 """subdivision search of changesets | |
252 | |
253 This command helps to find changesets which introduce problems. | |
254 To use, mark the earliest changeset you know exhibits the problem | |
255 as bad, then mark the latest changeset which is free from the | |
256 problem as good. Bisect will update your working directory to a | |
257 revision for testing. Once you have performed tests, mark the | |
258 working directory as bad or good and bisect will either update to | |
259 another candidate changeset or announce that it has found the bad | |
260 revision. | |
261 | |
262 Note: bisect expects bad revisions to be descendants of good | |
263 revisions. If you are looking for the point at which a problem was | |
264 fixed, then make the problem-free state \"bad\" and the | |
265 problematic state \"good.\" | |
266 """ | |
267 # backward compatibility | |
268 if rev in "good bad reset init".split(): | |
269 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n")) | |
270 cmd, rev, extra = rev, extra, None | |
271 if cmd == "good": | |
272 good = True | |
273 elif cmd == "bad": | |
274 bad = True | |
275 else: | |
276 reset = True | |
277 elif extra or good + bad + skip + reset > 1: | |
278 raise util.Abort("Incompatible arguments") | |
279 | |
280 if reset: | |
281 p = repo.join("bisect.state") | |
282 if os.path.exists(p): | |
283 os.unlink(p) | |
284 return | |
285 | |
286 # load state | |
287 state = {'good': [], 'bad': [], 'skip': []} | |
288 if os.path.exists(repo.join("bisect.state")): | |
289 for l in repo.opener("bisect.state"): | |
290 kind, node = l[:-1].split() | |
291 node = repo.lookup(node) | |
292 if kind not in state: | |
293 raise util.Abort(_("unknown bisect kind %s") % kind) | |
294 state[kind].append(node) | |
295 | |
296 # update state | |
297 node = repo.lookup(rev or '.') | |
298 if good: | |
299 state['good'].append(node) | |
300 elif bad: | |
301 state['bad'].append(node) | |
302 elif skip: | |
303 state['skip'].append(node) | |
304 | |
305 # save state | |
306 f = repo.opener("bisect.state", "w", atomictemp=True) | |
307 wlock = repo.wlock() | |
308 try: | |
309 for kind in state: | |
310 for node in state[kind]: | |
311 f.write("%s %s\n" % (kind, hg.hex(node))) | |
312 f.rename() | |
313 finally: | |
314 del wlock | |
315 | |
316 if not state['good'] or not state['bad']: | |
317 return | |
318 | |
319 # actually bisect | |
320 node, changesets = hbisect.bisect(repo.changelog, state) | |
321 if changesets == 0: | |
322 ui.write(_("The first bad revision is:\n")) | |
323 displayer = cmdutil.show_changeset(ui, repo, {}) | |
324 displayer.show(changenode=node) | |
325 elif node is not None: | |
326 # compute the approximate number of remaining tests | |
327 tests, size = 0, 2 | |
328 while size <= changesets: | |
329 tests, size = tests + 1, size * 2 | |
330 rev = repo.changelog.rev(node) | |
331 ui.write(_("Testing changeset %s:%s " | |
332 "(%s changesets remaining, ~%s tests)\n") | |
333 % (rev, hg.short(node), changesets, tests)) | |
334 if not noupdate: | |
335 cmdutil.bail_if_changed(repo) | |
336 return hg.clean(repo, node) | |
248 | 337 |
249 def branch(ui, repo, label=None, **opts): | 338 def branch(ui, repo, label=None, **opts): |
250 """set or show the current branch name | 339 """set or show the current branch name |
251 | 340 |
252 With no argument, show the current branch name. With one argument, | 341 With no argument, show the current branch name. With one argument, |
2656 _('merge with old dirstate parent after backout')), | 2745 _('merge with old dirstate parent after backout')), |
2657 ('', 'parent', '', _('parent to choose when backing out merge')), | 2746 ('', 'parent', '', _('parent to choose when backing out merge')), |
2658 ('r', 'rev', '', _('revision to backout')), | 2747 ('r', 'rev', '', _('revision to backout')), |
2659 ] + walkopts + commitopts + commitopts2, | 2748 ] + walkopts + commitopts + commitopts2, |
2660 _('hg backout [OPTION]... [-r] REV')), | 2749 _('hg backout [OPTION]... [-r] REV')), |
2750 "bisect": (bisect, | |
2751 [('r', 'reset', False, _('reset bisect state')), | |
2752 ('g', 'good', False, _('mark changeset good')), | |
2753 ('b', 'bad', False, _('mark changeset bad')), | |
2754 ('s', 'skip', False, _('skip testing changeset')), | |
2755 ('U', 'noupdate', False, _('do not update to target'))], | |
2756 _("hg bisect [-gbsr] [REV]")), | |
2661 "branch": | 2757 "branch": |
2662 (branch, | 2758 (branch, |
2663 [('f', 'force', None, | 2759 [('f', 'force', None, |
2664 _('set branch name even if it shadows an existing branch'))], | 2760 _('set branch name even if it shadows an existing branch'))], |
2665 _('hg branch [NAME]')), | 2761 _('hg branch [NAME]')), |