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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""builtin bzr commands"""
20
from StringIO import StringIO
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
31
29
from bzrlib import (
42
40
merge as _mod_merge,
47
45
revision as _mod_revision,
55
53
from bzrlib.branch import Branch
56
54
from bzrlib.conflicts import ConflictList
57
from bzrlib.revisionspec import RevisionSpec
55
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
58
56
from bzrlib.smtp_connection import SMTPConnection
59
57
from bzrlib.workingtree import WorkingTree
62
60
from bzrlib.commands import Command, display_command
63
from bzrlib.option import ListOption, Option, RegistryOption
64
from bzrlib.progress import DummyProgress, ProgressPhase
65
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
68
def tree_files(file_list, default_branch=u'.'):
61
from bzrlib.option import (
68
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
71
def tree_files(file_list, default_branch=u'.', canonicalize=True,
70
return internal_tree_files(file_list, default_branch)
74
return internal_tree_files(file_list, default_branch, canonicalize,
71
76
except errors.FileInWrongBranch, e:
72
77
raise errors.BzrCommandError("%s is not in the same branch as %s" %
73
78
(e.path, file_list[0]))
81
def tree_files_for_add(file_list):
83
Return a tree and list of absolute paths from a file list.
85
Similar to tree_files, but add handles files a bit differently, so it a
86
custom implementation. In particular, MutableTreeTree.smart_add expects
87
absolute paths, which it immediately converts to relative paths.
89
# FIXME Would be nice to just return the relative paths like
90
# internal_tree_files does, but there are a large number of unit tests
91
# that assume the current interface to mutabletree.smart_add
93
tree, relpath = WorkingTree.open_containing(file_list[0])
94
if tree.supports_views():
95
view_files = tree.views.lookup_view()
97
for filename in file_list:
98
if not osutils.is_inside_any(view_files, filename):
99
raise errors.FileOutsideView(filename, view_files)
100
file_list = file_list[:]
101
file_list[0] = tree.abspath(relpath)
103
tree = WorkingTree.open_containing(u'.')[0]
104
if tree.supports_views():
105
view_files = tree.views.lookup_view()
107
file_list = view_files
108
view_str = views.view_display_str(view_files)
109
note("Ignoring files outside view. View is %s" % view_str)
110
return tree, file_list
113
def _get_one_revision(command_name, revisions):
114
if revisions is None:
116
if len(revisions) != 1:
117
raise errors.BzrCommandError(
118
'bzr %s --revision takes exactly one revision identifier' % (
123
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
126
if revisions is None:
128
rev_tree = tree.basis_tree()
130
rev_tree = branch.basis_tree()
132
revision = _get_one_revision(command_name, revisions)
133
rev_tree = revision.as_tree(branch)
76
137
# XXX: Bad function name; should possibly also be a class method of
77
138
# WorkingTree rather than a function.
78
def internal_tree_files(file_list, default_branch=u'.'):
139
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
79
141
"""Convert command-line paths to a WorkingTree and relative paths.
81
143
This is typically used for command-line processors that take one or
215
337
# TODO: jam 20060112 should cat-revision always output utf-8?
216
338
if revision_id is not None:
217
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
339
revision_id = osutils.safe_revision_id(revision_id, warn=False)
341
self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
342
except errors.NoSuchRevision:
343
msg = "The repository %s contains no revision %s." % (b.repository.base,
345
raise errors.BzrCommandError(msg)
218
346
elif revision is not None:
219
347
for rev in revision:
221
349
raise errors.BzrCommandError('You cannot specify a NULL'
223
revno, rev_id = rev.in_history(b)
351
rev_id = rev.as_revision_id(b)
224
352
self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
355
class cmd_dump_btree(Command):
356
"""Dump the contents of a btree index file to stdout.
358
PATH is a btree index file, it can be any URL. This includes things like
359
.bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
361
By default, the tuples stored in the index file will be displayed. With
362
--raw, we will uncompress the pages, but otherwise display the raw bytes
366
# TODO: Do we want to dump the internal nodes as well?
367
# TODO: It would be nice to be able to dump the un-parsed information,
368
# rather than only going through iter_all_entries. However, this is
369
# good enough for a start
371
encoding_type = 'exact'
372
takes_args = ['path']
373
takes_options = [Option('raw', help='Write the uncompressed bytes out,'
374
' rather than the parsed tuples.'),
377
def run(self, path, raw=False):
378
dirname, basename = osutils.split(path)
379
t = transport.get_transport(dirname)
381
self._dump_raw_bytes(t, basename)
383
self._dump_entries(t, basename)
385
def _get_index_and_bytes(self, trans, basename):
386
"""Create a BTreeGraphIndex and raw bytes."""
387
bt = btree_index.BTreeGraphIndex(trans, basename, None)
388
bytes = trans.get_bytes(basename)
389
bt._file = cStringIO.StringIO(bytes)
390
bt._size = len(bytes)
393
def _dump_raw_bytes(self, trans, basename):
396
# We need to parse at least the root node.
397
# This is because the first page of every row starts with an
398
# uncompressed header.
399
bt, bytes = self._get_index_and_bytes(trans, basename)
400
for page_idx, page_start in enumerate(xrange(0, len(bytes),
401
btree_index._PAGE_SIZE)):
402
page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
403
page_bytes = bytes[page_start:page_end]
405
self.outf.write('Root node:\n')
406
header_end, data = bt._parse_header_from_bytes(page_bytes)
407
self.outf.write(page_bytes[:header_end])
409
self.outf.write('\nPage %d\n' % (page_idx,))
410
decomp_bytes = zlib.decompress(page_bytes)
411
self.outf.write(decomp_bytes)
412
self.outf.write('\n')
414
def _dump_entries(self, trans, basename):
416
st = trans.stat(basename)
417
except errors.TransportNotPossible:
418
# We can't stat, so we'll fake it because we have to do the 'get()'
420
bt, _ = self._get_index_and_bytes(trans, basename)
422
bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
423
for node in bt.iter_all_entries():
424
# Node is made up of:
425
# (index, key, value, [references])
426
self.outf.write('%s\n' % (node[1:],))
227
429
class cmd_remove_tree(Command):
228
430
"""Remove the working tree from a given branch/checkout.
688
1012
' directory exists, but does not already'
689
1013
' have a control directory. This flag will'
690
1014
' allow push to proceed.'),
1016
help='Create a stacked branch that references the public location '
1017
'of the parent branch.'),
1018
Option('stacked-on',
1019
help='Create a stacked branch that refers to another branch '
1020
'for the commit history. Only the work not present in the '
1021
'referenced branch is included in the branch created.',
692
1024
takes_args = ['location?']
693
1025
encoding_type = 'replace'
695
1027
def run(self, location=None, remember=False, overwrite=False,
696
create_prefix=False, verbose=False,
697
use_existing_dir=False,
699
# FIXME: Way too big! Put this into a function called from the
1028
create_prefix=False, verbose=False, revision=None,
1029
use_existing_dir=False, directory=None, stacked_on=None,
1031
from bzrlib.push import _show_push_branch
1033
# Get the source branch and revision_id
701
1034
if directory is None:
703
1036
br_from = Branch.open_containing(directory)[0]
704
stored_loc = br_from.get_push_location()
1037
revision = _get_one_revision('push', revision)
1038
if revision is not None:
1039
revision_id = revision.in_history(br_from).rev_id
1043
# Get the stacked_on branch, if any
1044
if stacked_on is not None:
1045
stacked_on = urlutils.normalize_url(stacked_on)
1047
parent_url = br_from.get_parent()
1049
parent = Branch.open(parent_url)
1050
stacked_on = parent.get_public_branch()
1052
# I considered excluding non-http url's here, thus forcing
1053
# 'public' branches only, but that only works for some
1054
# users, so it's best to just depend on the user spotting an
1055
# error by the feedback given to them. RBC 20080227.
1056
stacked_on = parent_url
1058
raise errors.BzrCommandError(
1059
"Could not determine branch to refer to.")
1061
# Get the destination location
705
1062
if location is None:
1063
stored_loc = br_from.get_push_location()
706
1064
if stored_loc is None:
707
raise errors.BzrCommandError("No push location known or specified.")
1065
raise errors.BzrCommandError(
1066
"No push location known or specified.")
709
1068
display_url = urlutils.unescape_for_display(stored_loc,
710
1069
self.outf.encoding)
711
self.outf.write("Using saved location: %s\n" % display_url)
1070
self.outf.write("Using saved push location: %s\n" % display_url)
712
1071
location = stored_loc
714
to_transport = transport.get_transport(location)
716
br_to = repository_to = dir_to = None
718
dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
719
except errors.NotBranchError:
720
pass # Didn't find anything
722
# If we can open a branch, use its direct repository, otherwise see
723
# if there is a repository without a branch.
725
br_to = dir_to.open_branch()
726
except errors.NotBranchError:
727
# Didn't find a branch, can we find a repository?
729
repository_to = dir_to.find_repository()
730
except errors.NoRepositoryPresent:
733
# Found a branch, so we must have found a repository
734
repository_to = br_to.repository
739
# The destination doesn't exist; create it.
740
# XXX: Refactor the create_prefix/no_create_prefix code into a
741
# common helper function
743
to_transport.mkdir('.')
744
except errors.FileExists:
745
if not use_existing_dir:
746
raise errors.BzrCommandError("Target directory %s"
747
" already exists, but does not have a valid .bzr"
748
" directory. Supply --use-existing-dir to push"
749
" there anyway." % location)
750
except errors.NoSuchFile:
751
if not create_prefix:
752
raise errors.BzrCommandError("Parent directory of %s"
754
"\nYou may supply --create-prefix to create all"
755
" leading parent directories."
757
_create_prefix(to_transport)
759
# Now the target directory exists, but doesn't have a .bzr
760
# directory. So we need to create it, along with any work to create
761
# all of the dependent branches, etc.
762
dir_to = br_from.bzrdir.clone_on_transport(to_transport,
763
revision_id=br_from.last_revision())
764
br_to = dir_to.open_branch()
765
# TODO: Some more useful message about what was copied
766
note('Created new branch.')
767
# We successfully created the target, remember it
768
if br_from.get_push_location() is None or remember:
769
br_from.set_push_location(br_to.base)
770
elif repository_to is None:
771
# we have a bzrdir but no branch or repository
772
# XXX: Figure out what to do other than complain.
773
raise errors.BzrCommandError("At %s you have a valid .bzr control"
774
" directory, but not a branch or repository. This is an"
775
" unsupported configuration. Please move the target directory"
776
" out of the way and try again."
779
# We have a repository but no branch, copy the revisions, and then
781
last_revision_id = br_from.last_revision()
782
repository_to.fetch(br_from.repository,
783
revision_id=last_revision_id)
784
br_to = br_from.clone(dir_to, revision_id=last_revision_id)
785
note('Created new branch.')
786
if br_from.get_push_location() is None or remember:
787
br_from.set_push_location(br_to.base)
788
else: # We have a valid to branch
789
# We were able to connect to the remote location, so remember it
790
# we don't need to successfully push because of possible divergence.
791
if br_from.get_push_location() is None or remember:
792
br_from.set_push_location(br_to.base)
794
old_rh = br_to.revision_history()
797
tree_to = dir_to.open_workingtree()
798
except errors.NotLocalUrl:
799
warning("This transport does not update the working "
800
"tree of: %s. See 'bzr help working-trees' for "
801
"more information." % br_to.base)
802
push_result = br_from.push(br_to, overwrite)
803
except errors.NoWorkingTree:
804
push_result = br_from.push(br_to, overwrite)
808
push_result = br_from.push(tree_to.branch, overwrite)
812
except errors.DivergedBranches:
813
raise errors.BzrCommandError('These branches have diverged.'
814
' Try using "merge" and then "push".')
815
if push_result is not None:
816
push_result.report(self.outf)
818
new_rh = br_to.revision_history()
821
from bzrlib.log import show_changed_revisions
822
show_changed_revisions(br_to, old_rh, new_rh,
825
# we probably did a clone rather than a push, so a message was
1073
_show_push_branch(br_from, revision_id, location, self.outf,
1074
verbose=verbose, overwrite=overwrite, remember=remember,
1075
stacked_on=stacked_on, create_prefix=create_prefix,
1076
use_existing_dir=use_existing_dir)
830
1079
class cmd_branch(Command):
1599
1929
raise errors.BzrCommandError(msg)
1932
def _parse_levels(s):
1936
msg = "The levels argument must be an integer."
1937
raise errors.BzrCommandError(msg)
1602
1940
class cmd_log(Command):
1603
"""Show log of a branch, file, or directory.
1605
By default show the log of the branch containing the working directory.
1607
To request a range of logs, you can use the command -r begin..end
1608
-r revision requests a specific revision, -r ..end or -r begin.. are
1612
Log the current branch::
1620
Log the last 10 revisions of a branch::
1622
bzr log -r -10.. http://server/branch
1941
"""Show historical log for a branch or subset of a branch.
1943
log is bzr's default tool for exploring the history of a branch.
1944
The branch to use is taken from the first parameter. If no parameters
1945
are given, the branch containing the working directory is logged.
1946
Here are some simple examples::
1948
bzr log log the current branch
1949
bzr log foo.py log a file in its branch
1950
bzr log http://server/branch log a branch on a server
1952
The filtering, ordering and information shown for each revision can
1953
be controlled as explained below. By default, all revisions are
1954
shown sorted (topologically) so that newer revisions appear before
1955
older ones and descendants always appear before ancestors. If displayed,
1956
merged revisions are shown indented under the revision in which they
1961
The log format controls how information about each revision is
1962
displayed. The standard log formats are called ``long``, ``short``
1963
and ``line``. The default is long. See ``bzr help log-formats``
1964
for more details on log formats.
1966
The following options can be used to control what information is
1969
-l N display a maximum of N revisions
1970
-n N display N levels of revisions (0 for all, 1 for collapsed)
1971
-v display a status summary (delta) for each revision
1972
-p display a diff (patch) for each revision
1973
--show-ids display revision-ids (and file-ids), not just revnos
1975
Note that the default number of levels to display is a function of the
1976
log format. If the -n option is not used, the standard log formats show
1977
just the top level (mainline).
1979
Status summaries are shown using status flags like A, M, etc. To see
1980
the changes explained using words like ``added`` and ``modified``
1981
instead, use the -vv option.
1985
To display revisions from oldest to newest, use the --forward option.
1986
In most cases, using this option will have little impact on the total
1987
time taken to produce a log, though --forward does not incrementally
1988
display revisions like --reverse does when it can.
1990
:Revision filtering:
1992
The -r option can be used to specify what revision or range of revisions
1993
to filter against. The various forms are shown below::
1995
-rX display revision X
1996
-rX.. display revision X and later
1997
-r..Y display up to and including revision Y
1998
-rX..Y display from X to Y inclusive
2000
See ``bzr help revisionspec`` for details on how to specify X and Y.
2001
Some common examples are given below::
2003
-r-1 show just the tip
2004
-r-10.. show the last 10 mainline revisions
2005
-rsubmit:.. show what's new on this branch
2006
-rancestor:path.. show changes since the common ancestor of this
2007
branch and the one at location path
2008
-rdate:yesterday.. show changes since yesterday
2010
When logging a range of revisions using -rX..Y, log starts at
2011
revision Y and searches back in history through the primary
2012
("left-hand") parents until it finds X. When logging just the
2013
top level (using -n1), an error is reported if X is not found
2014
along the way. If multi-level logging is used (-n0), X may be
2015
a nested merge revision and the log will be truncated accordingly.
2019
If parameters are given and the first one is not a branch, the log
2020
will be filtered to show only those revisions that changed the
2021
nominated files or directories.
2023
Filenames are interpreted within their historical context. To log a
2024
deleted file, specify a revision range so that the file existed at
2025
the end or start of the range.
2027
Historical context is also important when interpreting pathnames of
2028
renamed files/directories. Consider the following example:
2030
* revision 1: add tutorial.txt
2031
* revision 2: modify tutorial.txt
2032
* revision 3: rename tutorial.txt to guide.txt; add tutorial.txt
2036
* ``bzr log guide.txt`` will log the file added in revision 1
2038
* ``bzr log tutorial.txt`` will log the new file added in revision 3
2040
* ``bzr log -r2 -p tutorial.txt`` will show the changes made to
2041
the original file in revision 2.
2043
* ``bzr log -r2 -p guide.txt`` will display an error message as there
2044
was no file called guide.txt in revision 2.
2046
Renames are always followed by log. By design, there is no need to
2047
explicitly ask for this (and no way to stop logging a file back
2048
until it was last renamed).
2052
The --message option can be used for finding revisions that match a
2053
regular expression in a commit message.
2057
GUI tools and IDEs are often better at exploring history than command
2058
line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2059
respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2060
http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2062
Web interfaces are often better at exploring history than command line
2063
tools, particularly for branches on servers. You may prefer Loggerhead
2064
or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
2066
You may find it useful to add the aliases below to ``bazaar.conf``::
2070
top = log -l10 --line
2073
``bzr tip`` will then show the latest revision while ``bzr top``
2074
will show the last 10 mainline revisions. To see the details of a
2075
particular revision X, ``bzr show -rX``.
2077
If you are interested in looking deeper into a particular merge X,
2078
use ``bzr log -n0 -rX``.
2080
``bzr log -v`` on a branch with lots of history is currently
2081
very slow. A fix for this issue is currently under development.
2082
With or without that fix, it is recommended that a revision range
2083
be given when using the -v option.
2085
bzr has a generic full-text matching plugin, bzr-search, that can be
2086
used to find revisions matching user names, commit messages, etc.
2087
Among other features, this plugin can find all revisions containing
2088
a list of words but not others.
2090
When exploring non-mainline history on large projects with deep
2091
history, the performance of log can be greatly improved by installing
2092
the historycache plugin. This plugin buffers historical information
2093
trading disk space for faster speed.
1625
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
1627
takes_args = ['location?']
2095
takes_args = ['file*']
2096
_see_also = ['log-formats', 'revisionspec']
1628
2097
takes_options = [
1629
2098
Option('forward',
1630
2099
help='Show from oldest to newest.'),
1633
help='Display timezone as local, original, or utc.'),
2101
custom_help('verbose',
1636
2102
help='Show files changed in each revision.'),
2106
type=bzrlib.option._parse_revision_str,
2108
help='Show just the specified revision.'
2109
' See also "help revisionspec".'),
2113
help='Number of levels to display - 0 for all, 1 for flat.',
2115
type=_parse_levels),
1640
2116
Option('message',
1641
2117
short_name='m',
1642
2118
help='Show revisions whose message matches this '
1643
2119
'regular expression.',
1645
2121
Option('limit',
1646
2123
help='Limit the output to the first N revisions.',
1648
2125
type=_parse_limit),
2128
help='Show changes made in each revision as a patch.'),
2129
Option('include-merges',
2130
help='Show merged revisions like --levels 0 does.'),
1650
2132
encoding_type = 'replace'
1652
2134
@display_command
1653
def run(self, location=None, timezone='original',
2135
def run(self, file_list=None, timezone='original',
1655
2137
show_ids=False,
1658
2141
log_format=None,
1661
from bzrlib.log import show_log
1662
assert message is None or isinstance(message, basestring), \
1663
"invalid message argument %r" % message
2146
include_merges=False):
2147
from bzrlib.log import (
2149
make_log_request_dict,
2150
_get_info_for_log_files,
1664
2152
direction = (forward and 'forward') or 'reverse'
1669
# find the file id to log:
1671
tree, b, fp = bzrdir.BzrDir.open_containing_tree_or_branch(
1675
tree = b.basis_tree()
1676
file_id = tree.path2id(fp)
2157
raise errors.BzrCommandError(
2158
'--levels and --include-merges are mutually exclusive')
2160
if change is not None:
2162
raise errors.RangeInChangeOption()
2163
if revision is not None:
2164
raise errors.BzrCommandError(
2165
'--revision and --change are mutually exclusive')
2170
filter_by_dir = False
2172
# find the file ids to log and check for directory filtering
2173
b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
2175
for relpath, file_id, kind in file_info_list:
1677
2176
if file_id is None:
1678
2177
raise errors.BzrCommandError(
1679
"Path does not have any revision history: %s" %
2178
"Path unknown at end or start of revision range: %s" %
2180
# If the relpath is the top of the tree, we log everything
2185
file_ids.append(file_id)
2186
filter_by_dir = filter_by_dir or (
2187
kind in ['directory', 'tree-reference'])
1683
# FIXME ? log the current subdir only RBC 20060203
2190
# FIXME ? log the current subdir only RBC 20060203
1684
2191
if revision is not None \
1685
2192
and len(revision) > 0 and revision[0].get_branch():
1686
2193
location = revision[0].get_branch()
1689
2196
dir, relpath = bzrdir.BzrDir.open_containing(location)
1690
2197
b = dir.open_branch()
2198
rev1, rev2 = _get_revision_range(revision, b, self.name())
2200
# Decide on the type of delta & diff filtering to use
2201
# TODO: add an --all-files option to make this configurable & consistent
2209
diff_type = 'partial'
1694
if revision is None:
1697
elif len(revision) == 1:
1698
rev1 = rev2 = revision[0].in_history(b)
1699
elif len(revision) == 2:
1700
if revision[1].get_branch() != revision[0].get_branch():
1701
# b is taken from revision[0].get_branch(), and
1702
# show_log will use its revision_history. Having
1703
# different branches will lead to weird behaviors.
1704
raise errors.BzrCommandError(
1705
"Log doesn't accept two revisions in different"
1707
rev1 = revision[0].in_history(b)
1708
rev2 = revision[1].in_history(b)
1710
raise errors.BzrCommandError(
1711
'bzr log --revision takes one or two values.')
2215
# Build the log formatter
1713
2216
if log_format is None:
1714
2217
log_format = log.log_formatter_registry.get_default(b)
1716
2218
lf = log_format(show_ids=show_ids, to_file=self.outf,
1717
show_timezone=timezone)
1723
direction=direction,
1724
start_revision=rev1,
2219
show_timezone=timezone,
2220
delta_format=get_verbosity_level(),
2222
show_advice=levels is None)
2224
# Choose the algorithm for doing the logging. It's annoying
2225
# having multiple code paths like this but necessary until
2226
# the underlying repository format is faster at generating
2227
# deltas or can provide everything we need from the indices.
2228
# The default algorithm - match-using-deltas - works for
2229
# multiple files and directories and is faster for small
2230
# amounts of history (200 revisions say). However, it's too
2231
# slow for logging a single file in a repository with deep
2232
# history, i.e. > 10K revisions. In the spirit of "do no
2233
# evil when adding features", we continue to use the
2234
# original algorithm - per-file-graph - for the "single
2235
# file that isn't a directory without showing a delta" case.
2236
partial_history = revision and b.repository._format.supports_chks
2237
match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2238
or delta_type or partial_history)
2240
# Build the LogRequest and execute it
2241
if len(file_ids) == 0:
2243
rqst = make_log_request_dict(
2244
direction=direction, specific_fileids=file_ids,
2245
start_revision=rev1, end_revision=rev2, limit=limit,
2246
message_search=message, delta_type=delta_type,
2247
diff_type=diff_type, _match_using_deltas=match_using_deltas)
2248
Logger(b, rqst).show(lf)
2253
def _get_revision_range(revisionspec_list, branch, command_name):
2254
"""Take the input of a revision option and turn it into a revision range.
2256
It returns RevisionInfo objects which can be used to obtain the rev_id's
2257
of the desired revisions. It does some user input validations.
2259
if revisionspec_list is None:
2262
elif len(revisionspec_list) == 1:
2263
rev1 = rev2 = revisionspec_list[0].in_history(branch)
2264
elif len(revisionspec_list) == 2:
2265
start_spec = revisionspec_list[0]
2266
end_spec = revisionspec_list[1]
2267
if end_spec.get_branch() != start_spec.get_branch():
2268
# b is taken from revision[0].get_branch(), and
2269
# show_log will use its revision_history. Having
2270
# different branches will lead to weird behaviors.
2271
raise errors.BzrCommandError(
2272
"bzr %s doesn't accept two revisions in different"
2273
" branches." % command_name)
2274
rev1 = start_spec.in_history(branch)
2275
# Avoid loading all of history when we know a missing
2276
# end of range means the last revision ...
2277
if end_spec.spec is None:
2278
last_revno, last_revision_id = branch.last_revision_info()
2279
rev2 = RevisionInfo(branch, last_revno, last_revision_id)
2281
rev2 = end_spec.in_history(branch)
2283
raise errors.BzrCommandError(
2284
'bzr %s --revision takes one or two values.' % command_name)
2288
def _revision_range_to_revid_range(revision_range):
2291
if revision_range[0] is not None:
2292
rev_id1 = revision_range[0].rev_id
2293
if revision_range[1] is not None:
2294
rev_id2 = revision_range[1].rev_id
2295
return rev_id1, rev_id2
1732
2297
def get_log_format(long=False, short=False, line=False, default='long'):
1733
2298
log_format = default
2510
3275
short_name='x',
2511
3276
help='Exclude tests that match this regular'
2512
3277
' expression.'),
3279
help='Output test progress via subunit.'),
2513
3280
Option('strict', help='Fail on missing dependencies or '
2514
3281
'known failures.'),
3282
Option('load-list', type=str, argname='TESTLISTFILE',
3283
help='Load a test id list from a text file.'),
3284
ListOption('debugflag', type=str, short_name='E',
3285
help='Turn on a selftest debug flag.'),
3286
ListOption('starting-with', type=str, argname='TESTID',
3287
param_name='starting_with', short_name='s',
3289
'Load only the tests starting with TESTID.'),
2516
3291
encoding_type = 'replace'
2518
def run(self, testspecs_list=None, verbose=None, one=False,
3294
Command.__init__(self)
3295
self.additional_selftest_args = {}
3297
def run(self, testspecs_list=None, verbose=False, one=False,
2519
3298
transport=None, benchmark=None,
2520
3299
lsprof_timed=None, cache_dir=None,
2521
3300
first=False, list_only=False,
2522
randomize=None, exclude=None, strict=False):
3301
randomize=None, exclude=None, strict=False,
3302
load_list=None, debugflag=None, starting_with=None, subunit=False,
2524
3304
from bzrlib.tests import selftest
2525
3305
import bzrlib.benchmarks as benchmarks
2526
3306
from bzrlib.benchmarks import tree_creator
2527
from bzrlib.version import show_version
3308
# Make deprecation warnings visible, unless -Werror is set
3309
symbol_versioning.activate_deprecation_warnings(override=False)
2529
3311
if cache_dir is not None:
2530
3312
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2532
show_version(show_config=False, show_copyright=False)
2534
3313
if testspecs_list is not None:
2535
3314
pattern = '|'.join(testspecs_list)
3319
from bzrlib.tests import SubUnitBzrRunner
3321
raise errors.BzrCommandError("subunit not available. subunit "
3322
"needs to be installed to use --subunit.")
3323
self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
3325
self.additional_selftest_args.setdefault(
3326
'suite_decorators', []).append(parallel)
2539
3328
test_suite_factory = benchmarks.test_suite
3329
# Unless user explicitly asks for quiet, be verbose in benchmarks
3330
verbose = not is_quiet()
2542
3331
# TODO: should possibly lock the history file...
2543
3332
benchfile = open(".perf_history", "at", buffering=1)
2545
3334
test_suite_factory = None
2548
3335
benchfile = None
2550
result = selftest(verbose=verbose,
2552
stop_on_failure=one,
2553
transport=transport,
2554
test_suite_factory=test_suite_factory,
2555
lsprof_timed=lsprof_timed,
2556
bench_history=benchfile,
2557
matching_tests_first=first,
2558
list_only=list_only,
2559
random_seed=randomize,
2560
exclude_pattern=exclude,
3337
selftest_kwargs = {"verbose": verbose,
3339
"stop_on_failure": one,
3340
"transport": transport,
3341
"test_suite_factory": test_suite_factory,
3342
"lsprof_timed": lsprof_timed,
3343
"bench_history": benchfile,
3344
"matching_tests_first": first,
3345
"list_only": list_only,
3346
"random_seed": randomize,
3347
"exclude_pattern": exclude,
3349
"load_list": load_list,
3350
"debug_flags": debugflag,
3351
"starting_with": starting_with
3353
selftest_kwargs.update(self.additional_selftest_args)
3354
result = selftest(**selftest_kwargs)
2564
3356
if benchfile is not None:
2565
3357
benchfile.close()
2567
info('tests passed')
2569
info('tests failed')
2570
3358
return int(not result)
2573
3361
class cmd_version(Command):
2574
3362
"""Show version of bzr."""
3364
encoding_type = 'replace'
3366
Option("short", help="Print just the version number."),
2576
3369
@display_command
3370
def run(self, short=False):
2578
3371
from bzrlib.version import show_version
3373
self.outf.write(bzrlib.version_string + '\n')
3375
show_version(to_file=self.outf)
2582
3378
class cmd_rocks(Command):
4051
5157
short_name='d',
5160
RegistryOption.from_kwargs('sort',
5161
'Sort tags by different criteria.', title='Sorting',
5162
alpha='Sort tags lexicographically (default).',
5163
time='Sort tags chronologically.',
4056
5169
@display_command
4060
5176
branch, relpath = Branch.open_containing(directory)
4061
for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
4062
self.outf.write('%-20s %s\n' % (tag_name, target))
4065
def _create_prefix(cur_transport):
4066
needed = [cur_transport]
4067
# Recurse upwards until we can create a directory successfully
4069
new_transport = cur_transport.clone('..')
4070
if new_transport.base == cur_transport.base:
4071
raise errors.BzrCommandError(
4072
"Failed to create path prefix for %s."
4073
% cur_transport.base)
4075
new_transport.mkdir('.')
4076
except errors.NoSuchFile:
4077
needed.append(new_transport)
4078
cur_transport = new_transport
4081
# Now we only need to create child directories
4083
cur_transport = needed.pop()
4084
cur_transport.ensure_base()
4087
def _get_mergeable_helper(location):
4088
"""Get a merge directive or bundle if 'location' points to one.
4090
Try try to identify a bundle and returns its mergeable form. If it's not,
4091
we return the tried transport anyway so that it can reused to access the
4094
:param location: can point to a bundle or a branch.
4096
:return: mergeable, transport
4099
url = urlutils.normalize_url(location)
4100
url, filename = urlutils.split(url, exclude_trailing_slash=False)
4101
location_transport = transport.get_transport(url)
4104
# There may be redirections but we ignore the intermediate
4105
# and final transports used
4106
read = bundle.read_mergeable_from_transport
4107
mergeable, t = read(location_transport, filename)
4108
except errors.NotABundle:
4109
# Continue on considering this url a Branch but adjust the
4110
# location_transport
4111
location_transport = location_transport.clone(filename)
4112
return mergeable, location_transport
5178
tags = branch.tags.get_tag_dict().items()
5185
graph = branch.repository.get_graph()
5186
rev1, rev2 = _get_revision_range(revision, branch, self.name())
5187
revid1, revid2 = rev1.rev_id, rev2.rev_id
5188
# only show revisions between revid1 and revid2 (inclusive)
5189
tags = [(tag, revid) for tag, revid in tags if
5190
graph.is_between(revid, revid1, revid2)]
5195
elif sort == 'time':
5197
for tag, revid in tags:
5199
revobj = branch.repository.get_revision(revid)
5200
except errors.NoSuchRevision:
5201
timestamp = sys.maxint # place them at the end
5203
timestamp = revobj.timestamp
5204
timestamps[revid] = timestamp
5205
tags.sort(key=lambda x: timestamps[x[1]])
5207
# [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5208
revno_map = branch.get_revision_id_to_revno_map()
5209
tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
5210
for tag, revid in tags ]
5211
for tag, revspec in tags:
5212
self.outf.write('%-20s %s\n' % (tag, revspec))
5215
class cmd_reconfigure(Command):
5216
"""Reconfigure the type of a bzr directory.
5218
A target configuration must be specified.
5220
For checkouts, the bind-to location will be auto-detected if not specified.
5221
The order of preference is
5222
1. For a lightweight checkout, the current bound location.
5223
2. For branches that used to be checkouts, the previously-bound location.
5224
3. The push location.
5225
4. The parent location.
5226
If none of these is available, --bind-to must be specified.
5229
_see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
5230
takes_args = ['location?']
5232
RegistryOption.from_kwargs(
5234
title='Target type',
5235
help='The type to reconfigure the directory to.',
5236
value_switches=True, enum_switch=False,
5237
branch='Reconfigure to be an unbound branch with no working tree.',
5238
tree='Reconfigure to be an unbound branch with a working tree.',
5239
checkout='Reconfigure to be a bound branch with a working tree.',
5240
lightweight_checkout='Reconfigure to be a lightweight'
5241
' checkout (with no local history).',
5242
standalone='Reconfigure to be a standalone branch '
5243
'(i.e. stop using shared repository).',
5244
use_shared='Reconfigure to use a shared repository.',
5245
with_trees='Reconfigure repository to create '
5246
'working trees on branches by default.',
5247
with_no_trees='Reconfigure repository to not create '
5248
'working trees on branches by default.'
5250
Option('bind-to', help='Branch to bind checkout to.', type=str),
5252
help='Perform reconfiguration even if local changes'
5256
def run(self, location=None, target_type=None, bind_to=None, force=False):
5257
directory = bzrdir.BzrDir.open(location)
5258
if target_type is None:
5259
raise errors.BzrCommandError('No target configuration specified')
5260
elif target_type == 'branch':
5261
reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5262
elif target_type == 'tree':
5263
reconfiguration = reconfigure.Reconfigure.to_tree(directory)
5264
elif target_type == 'checkout':
5265
reconfiguration = reconfigure.Reconfigure.to_checkout(
5267
elif target_type == 'lightweight-checkout':
5268
reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
5270
elif target_type == 'use-shared':
5271
reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
5272
elif target_type == 'standalone':
5273
reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
5274
elif target_type == 'with-trees':
5275
reconfiguration = reconfigure.Reconfigure.set_repository_trees(
5277
elif target_type == 'with-no-trees':
5278
reconfiguration = reconfigure.Reconfigure.set_repository_trees(
5280
reconfiguration.apply(force)
5283
class cmd_switch(Command):
5284
"""Set the branch of a checkout and update.
5286
For lightweight checkouts, this changes the branch being referenced.
5287
For heavyweight checkouts, this checks that there are no local commits
5288
versus the current bound branch, then it makes the local branch a mirror
5289
of the new location and binds to it.
5291
In both cases, the working tree is updated and uncommitted changes
5292
are merged. The user can commit or revert these as they desire.
5294
Pending merges need to be committed or reverted before using switch.
5296
The path to the branch to switch to can be specified relative to the parent
5297
directory of the current branch. For example, if you are currently in a
5298
checkout of /path/to/branch, specifying 'newbranch' will find a branch at
5301
Bound branches use the nickname of its master branch unless it is set
5302
locally, in which case switching will update the the local nickname to be
5306
takes_args = ['to_location']
5307
takes_options = [Option('force',
5308
help='Switch even if local commits will be lost.')
5311
def run(self, to_location, force=False):
5312
from bzrlib import switch
5314
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5316
branch = control_dir.open_branch()
5317
had_explicit_nick = branch.get_config().has_explicit_nickname()
5318
except errors.NotBranchError:
5319
had_explicit_nick = False
5321
to_branch = Branch.open(to_location)
5322
except errors.NotBranchError:
5323
this_url = self._get_branch_location(control_dir)
5324
to_branch = Branch.open(
5325
urlutils.join(this_url, '..', to_location))
5326
switch.switch(control_dir, to_branch, force)
5327
if had_explicit_nick:
5328
branch = control_dir.open_branch() #get the new branch!
5329
branch.nick = to_branch.nick
5330
note('Switched to branch: %s',
5331
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5333
def _get_branch_location(self, control_dir):
5334
"""Return location of branch for this control dir."""
5336
this_branch = control_dir.open_branch()
5337
# This may be a heavy checkout, where we want the master branch
5338
master_location = this_branch.get_bound_location()
5339
if master_location is not None:
5340
return master_location
5341
# If not, use a local sibling
5342
return this_branch.base
5343
except errors.NotBranchError:
5344
format = control_dir.find_branch_format()
5345
if getattr(format, 'get_reference', None) is not None:
5346
return format.get_reference(control_dir)
5348
return control_dir.root_transport.base
5351
class cmd_view(Command):
5352
"""Manage filtered views.
5354
Views provide a mask over the tree so that users can focus on
5355
a subset of a tree when doing their work. After creating a view,
5356
commands that support a list of files - status, diff, commit, etc -
5357
effectively have that list of files implicitly given each time.
5358
An explicit list of files can still be given but those files
5359
must be within the current view.
5361
In most cases, a view has a short life-span: it is created to make
5362
a selected change and is deleted once that change is committed.
5363
At other times, you may wish to create one or more named views
5364
and switch between them.
5366
To disable the current view without deleting it, you can switch to
5367
the pseudo view called ``off``. This can be useful when you need
5368
to see the whole tree for an operation or two (e.g. merge) but
5369
want to switch back to your view after that.
5372
To define the current view::
5374
bzr view file1 dir1 ...
5376
To list the current view::
5380
To delete the current view::
5384
To disable the current view without deleting it::
5386
bzr view --switch off
5388
To define a named view and switch to it::
5390
bzr view --name view-name file1 dir1 ...
5392
To list a named view::
5394
bzr view --name view-name
5396
To delete a named view::
5398
bzr view --name view-name --delete
5400
To switch to a named view::
5402
bzr view --switch view-name
5404
To list all views defined::
5408
To delete all views::
5410
bzr view --delete --all
5414
takes_args = ['file*']
5417
help='Apply list or delete action to all views.',
5420
help='Delete the view.',
5423
help='Name of the view to define, list or delete.',
5427
help='Name of the view to switch to.',
5432
def run(self, file_list,
5438
tree, file_list = tree_files(file_list, apply_view=False)
5439
current_view, view_dict = tree.views.get_view_info()
5444
raise errors.BzrCommandError(
5445
"Both --delete and a file list specified")
5447
raise errors.BzrCommandError(
5448
"Both --delete and --switch specified")
5450
tree.views.set_view_info(None, {})
5451
self.outf.write("Deleted all views.\n")
5453
raise errors.BzrCommandError("No current view to delete")
5455
tree.views.delete_view(name)
5456
self.outf.write("Deleted '%s' view.\n" % name)
5459
raise errors.BzrCommandError(
5460
"Both --switch and a file list specified")
5462
raise errors.BzrCommandError(
5463
"Both --switch and --all specified")
5464
elif switch == 'off':
5465
if current_view is None:
5466
raise errors.BzrCommandError("No current view to disable")
5467
tree.views.set_view_info(None, view_dict)
5468
self.outf.write("Disabled '%s' view.\n" % (current_view))
5470
tree.views.set_view_info(switch, view_dict)
5471
view_str = views.view_display_str(tree.views.lookup_view())
5472
self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
5475
self.outf.write('Views defined:\n')
5476
for view in sorted(view_dict):
5477
if view == current_view:
5481
view_str = views.view_display_str(view_dict[view])
5482
self.outf.write('%s %-20s %s\n' % (active, view, view_str))
5484
self.outf.write('No views defined.\n')
5487
# No name given and no current view set
5490
raise errors.BzrCommandError(
5491
"Cannot change the 'off' pseudo view")
5492
tree.views.set_view(name, sorted(file_list))
5493
view_str = views.view_display_str(tree.views.lookup_view())
5494
self.outf.write("Using '%s' view: %s\n" % (name, view_str))
5498
# No name given and no current view set
5499
self.outf.write('No current view.\n')
5501
view_str = views.view_display_str(tree.views.lookup_view(name))
5502
self.outf.write("'%s' view is: %s\n" % (name, view_str))
5505
class cmd_hooks(Command):
5511
for hook_key in sorted(hooks.known_hooks.keys()):
5512
some_hooks = hooks.known_hooks_key_to_object(hook_key)
5513
self.outf.write("%s:\n" % type(some_hooks).__name__)
5514
for hook_name, hook_point in sorted(some_hooks.items()):
5515
self.outf.write(" %s:\n" % (hook_name,))
5516
found_hooks = list(hook_point)
5518
for hook in found_hooks:
5519
self.outf.write(" %s\n" %
5520
(some_hooks.get_hook_name(hook),))
5522
self.outf.write(" <no hooks installed>\n")
5525
class cmd_shelve(Command):
5526
"""Temporarily set aside some changes from the current tree.
5528
Shelve allows you to temporarily put changes you've made "on the shelf",
5529
ie. out of the way, until a later time when you can bring them back from
5530
the shelf with the 'unshelve' command. The changes are stored alongside
5531
your working tree, and so they aren't propagated along with your branch nor
5532
will they survive its deletion.
5534
If shelve --list is specified, previously-shelved changes are listed.
5536
Shelve is intended to help separate several sets of changes that have
5537
been inappropriately mingled. If you just want to get rid of all changes
5538
and you don't need to restore them later, use revert. If you want to
5539
shelve all text changes at once, use shelve --all.
5541
If filenames are specified, only the changes to those files will be
5542
shelved. Other files will be left untouched.
5544
If a revision is specified, changes since that revision will be shelved.
5546
You can put multiple items on the shelf, and by default, 'unshelve' will
5547
restore the most recently shelved changes.
5550
takes_args = ['file*']
5554
Option('all', help='Shelve all changes.'),
5556
RegistryOption('writer', 'Method to use for writing diffs.',
5557
bzrlib.option.diff_writer_registry,
5558
value_switches=True, enum_switch=False),
5560
Option('list', help='List shelved changes.'),
5562
help='Destroy removed changes instead of shelving them.'),
5564
_see_also = ['unshelve']
5566
def run(self, revision=None, all=False, file_list=None, message=None,
5567
writer=None, list=False, destroy=False):
5569
return self.run_for_list()
5570
from bzrlib.shelf_ui import Shelver
5572
writer = bzrlib.option.diff_writer_registry.get()
5574
Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5575
message, destroy=destroy).run()
5576
except errors.UserAbort:
5579
def run_for_list(self):
5580
tree = WorkingTree.open_containing('.')[0]
5583
manager = tree.get_shelf_manager()
5584
shelves = manager.active_shelves()
5585
if len(shelves) == 0:
5586
note('No shelved changes.')
5588
for shelf_id in reversed(shelves):
5589
message = manager.get_metadata(shelf_id).get('message')
5591
message = '<no message>'
5592
self.outf.write('%3d: %s\n' % (shelf_id, message))
5598
class cmd_unshelve(Command):
5599
"""Restore shelved changes.
5601
By default, the most recently shelved changes are restored. However if you
5602
specify a shelf by id those changes will be restored instead. This works
5603
best when the changes don't depend on each other.
5606
takes_args = ['shelf_id?']
5608
RegistryOption.from_kwargs(
5609
'action', help="The action to perform.",
5610
enum_switch=False, value_switches=True,
5611
apply="Apply changes and remove from the shelf.",
5612
dry_run="Show changes, but do not apply or remove them.",
5613
delete_only="Delete changes without applying them."
5616
_see_also = ['shelve']
5618
def run(self, shelf_id=None, action='apply'):
5619
from bzrlib.shelf_ui import Unshelver
5620
Unshelver.from_args(shelf_id, action).run()
5623
class cmd_clean_tree(Command):
5624
"""Remove unwanted files from working tree.
5626
By default, only unknown files, not ignored files, are deleted. Versioned
5627
files are never deleted.
5629
Another class is 'detritus', which includes files emitted by bzr during
5630
normal operations and selftests. (The value of these files decreases with
5633
If no options are specified, unknown files are deleted. Otherwise, option
5634
flags are respected, and may be combined.
5636
To check what clean-tree will do, use --dry-run.
5638
takes_options = [Option('ignored', help='Delete all ignored files.'),
5639
Option('detritus', help='Delete conflict files, merge'
5640
' backups, and failed selftest dirs.'),
5642
help='Delete files unknown to bzr (default).'),
5643
Option('dry-run', help='Show files to delete instead of'
5645
Option('force', help='Do not prompt before deleting.')]
5646
def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5648
from bzrlib.clean_tree import clean_tree
5649
if not (unknown or ignored or detritus):
5653
clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5654
dry_run=dry_run, no_prompt=force)
5657
class cmd_reference(Command):
5658
"""list, view and set branch locations for nested trees.
5660
If no arguments are provided, lists the branch locations for nested trees.
5661
If one argument is provided, display the branch location for that tree.
5662
If two arguments are provided, set the branch location for that tree.
5667
takes_args = ['path?', 'location?']
5669
def run(self, path=None, location=None):
5671
if path is not None:
5673
tree, branch, relpath =(
5674
bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
5675
if path is not None:
5678
tree = branch.basis_tree()
5680
info = branch._get_all_reference_info().iteritems()
5681
self._display_reference_info(tree, branch, info)
5683
file_id = tree.path2id(path)
5685
raise errors.NotVersionedError(path)
5686
if location is None:
5687
info = [(file_id, branch.get_reference_info(file_id))]
5688
self._display_reference_info(tree, branch, info)
5690
branch.set_reference_info(file_id, path, location)
5692
def _display_reference_info(self, tree, branch, info):
5694
for file_id, (path, location) in info:
5696
path = tree.id2path(file_id)
5697
except errors.NoSuchId:
5699
ref_list.append((path, location))
5700
for path, location in sorted(ref_list):
5701
self.outf.write('%s %s\n' % (path, location))
4115
5704
# these get imported and then picked up by the scan for cmd_*
4116
5705
# TODO: Some more consistent way to split command definitions across files;
4117
# we do need to load at least some information about them to know of
5706
# we do need to load at least some information about them to know of
4118
5707
# aliases. ideally we would avoid loading the implementation until the
4119
5708
# details were needed.
4120
5709
from bzrlib.cmd_version_info import cmd_version_info