1
# Copyright (C) 2004, 2005 by 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
# DO NOT change this to cStringIO - it results in control files
19
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
21
from StringIO import StringIO
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command, display_command
28
from bzrlib.branch import Branch
29
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
30
from bzrlib.errors import DivergedBranches
31
from bzrlib.option import Option
32
from bzrlib.revisionspec import RevisionSpec
34
from bzrlib.trace import mutter, note, log_error, warning
35
from bzrlib.workingtree import WorkingTree
38
class cmd_status(Command):
39
"""Display status summary.
41
This reports on versioned and unknown files, reporting them
42
grouped by state. Possible states are:
45
Versioned in the working copy but not in the previous revision.
48
Versioned in the previous revision but removed or deleted
52
Path of this file changed from the previous revision;
53
the text may also have changed. This includes files whose
54
parent directory was renamed.
57
Text has changed since the previous revision.
60
Nothing about this file has changed since the previous revision.
61
Only shown with --all.
64
Not versioned and not matching an ignore pattern.
66
To see ignored files use 'bzr ignored'. For details in the
67
changes to file texts, use 'bzr diff'.
69
If no arguments are specified, the status of the entire working
70
directory is shown. Otherwise, only the status of the specified
71
files or directories is reported. If a directory is given, status
72
is reported for everything inside that directory.
74
If a revision argument is given, the status is calculated against
75
that revision, or between two revisions if two are provided.
78
# XXX: FIXME: bzr status should accept a -r option to show changes
79
# relative to a revision, or between revisions
81
# TODO: --no-recurse, --recurse options
83
takes_args = ['file*']
84
takes_options = ['all', 'show-ids']
85
aliases = ['st', 'stat']
88
def run(self, all=False, show_ids=False, file_list=None, revision=None):
90
b, relpath = Branch.open_containing(file_list[0])
91
if relpath == '' and len(file_list) == 1:
94
# generate relative paths.
95
# note that if this is a remote branch, we would want
96
# relpath against the transport. RBC 20051018
97
tree = WorkingTree(b.base, b)
98
file_list = [tree.relpath(x) for x in file_list]
100
b = Branch.open_containing('.')[0]
102
from bzrlib.status import show_status
103
show_status(b, show_unchanged=all, show_ids=show_ids,
104
specific_files=file_list, revision=revision)
107
class cmd_cat_revision(Command):
108
"""Write out metadata for a revision.
110
The revision to print can either be specified by a specific
111
revision identifier, or you can use --revision.
115
takes_args = ['revision_id?']
116
takes_options = ['revision']
119
def run(self, revision_id=None, revision=None):
121
if revision_id is not None and revision is not None:
122
raise BzrCommandError('You can only supply one of revision_id or --revision')
123
if revision_id is None and revision is None:
124
raise BzrCommandError('You must supply either --revision or a revision_id')
125
b = Branch.open_containing('.')[0]
126
if revision_id is not None:
127
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
128
elif revision is not None:
131
raise BzrCommandError('You cannot specify a NULL revision.')
132
revno, rev_id = rev.in_history(b)
133
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
136
class cmd_revno(Command):
137
"""Show current revision number.
139
This is equal to the number of revisions on this branch."""
142
print Branch.open_containing('.')[0].revno()
145
class cmd_revision_info(Command):
146
"""Show revision number and revision id for a given revision identifier.
149
takes_args = ['revision_info*']
150
takes_options = ['revision']
152
def run(self, revision=None, revision_info_list=[]):
155
if revision is not None:
156
revs.extend(revision)
157
if revision_info_list is not None:
158
for rev in revision_info_list:
159
revs.append(RevisionSpec(rev))
161
raise BzrCommandError('You must supply a revision identifier')
163
b = Branch.open_containing('.')[0]
166
revinfo = rev.in_history(b)
167
if revinfo.revno is None:
168
print ' %s' % revinfo.rev_id
170
print '%4d %s' % (revinfo.revno, revinfo.rev_id)
173
class cmd_add(Command):
174
"""Add specified files or directories.
176
In non-recursive mode, all the named items are added, regardless
177
of whether they were previously ignored. A warning is given if
178
any of the named files are already versioned.
180
In recursive mode (the default), files are treated the same way
181
but the behaviour for directories is different. Directories that
182
are already versioned do not give a warning. All directories,
183
whether already versioned or not, are searched for files or
184
subdirectories that are neither versioned or ignored, and these
185
are added. This search proceeds recursively into versioned
186
directories. If no names are given '.' is assumed.
188
Therefore simply saying 'bzr add' will version all files that
189
are currently unknown.
191
Adding a file whose parent directory is not versioned will
192
implicitly add the parent, and so on up to the root. This means
193
you should never need to explictly add a directory, they'll just
194
get added when you add a file in the directory.
196
takes_args = ['file*']
197
takes_options = ['no-recurse', 'quiet']
199
def run(self, file_list, no_recurse=False, quiet=False):
200
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
202
reporter = add_reporter_null
204
reporter = add_reporter_print
205
smart_add(file_list, not no_recurse, reporter)
208
class cmd_mkdir(Command):
209
"""Create a new versioned directory.
211
This is equivalent to creating the directory and then adding it.
213
takes_args = ['dir+']
215
def run(self, dir_list):
221
b = Branch.open_containing(d)[0]
226
class cmd_relpath(Command):
227
"""Show path of a file relative to root"""
228
takes_args = ['filename']
232
def run(self, filename):
233
branch, relpath = Branch.open_containing(filename)
237
class cmd_inventory(Command):
238
"""Show inventory of the current working copy or a revision."""
239
takes_options = ['revision', 'show-ids']
242
def run(self, revision=None, show_ids=False):
243
b = Branch.open_containing('.')[0]
245
inv = b.read_working_inventory()
247
if len(revision) > 1:
248
raise BzrCommandError('bzr inventory --revision takes'
249
' exactly one revision identifier')
250
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
252
for path, entry in inv.entries():
254
print '%-50s %s' % (path, entry.file_id)
259
class cmd_move(Command):
260
"""Move files to a different directory.
265
The destination must be a versioned directory in the same branch.
267
takes_args = ['source$', 'dest']
268
def run(self, source_list, dest):
269
b = Branch.open_containing('.')[0]
271
# TODO: glob expansion on windows?
272
tree = WorkingTree(b.base, b)
273
b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
276
class cmd_rename(Command):
277
"""Change the name of an entry.
280
bzr rename frob.c frobber.c
281
bzr rename src/frob.c lib/frob.c
283
It is an error if the destination name exists.
285
See also the 'move' command, which moves files into a different
286
directory without changing their name.
288
# TODO: Some way to rename multiple files without invoking
289
# bzr for each one?"""
290
takes_args = ['from_name', 'to_name']
292
def run(self, from_name, to_name):
293
b = Branch.open_containing('.')[0]
294
tree = WorkingTree(b.base, b)
295
b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
298
class cmd_mv(Command):
299
"""Move or rename a file.
302
bzr mv OLDNAME NEWNAME
303
bzr mv SOURCE... DESTINATION
305
If the last argument is a versioned directory, all the other names
306
are moved into it. Otherwise, there must be exactly two arguments
307
and the file is changed to a new name, which must not already exist.
309
Files cannot be moved between branches.
311
takes_args = ['names*']
312
def run(self, names_list):
313
if len(names_list) < 2:
314
raise BzrCommandError("missing file argument")
315
b = Branch.open_containing(names_list[0])[0]
316
tree = WorkingTree(b.base, b)
317
rel_names = [tree.relpath(x) for x in names_list]
319
if os.path.isdir(names_list[-1]):
320
# move into existing directory
321
for pair in b.move(rel_names[:-1], rel_names[-1]):
322
print "%s => %s" % pair
324
if len(names_list) != 2:
325
raise BzrCommandError('to mv multiple files the destination '
326
'must be a versioned directory')
327
b.rename_one(rel_names[0], rel_names[1])
328
print "%s => %s" % (rel_names[0], rel_names[1])
333
class cmd_pull(Command):
334
"""Pull any changes from another branch into the current one.
336
If there is no default location set, the first pull will set it. After
337
that, you can omit the location to use the default. To change the
338
default, use --remember.
340
This command only works on branches that have not diverged. Branches are
341
considered diverged if both branches have had commits without first
342
pulling from the other.
344
If branches have diverged, you can use 'bzr merge' to pull the text changes
345
from one into the other. Once one branch has merged, the other should
346
be able to pull it again.
348
If you want to forget your local changes and just update your branch to
349
match the remote one, use --overwrite.
351
takes_options = ['remember', 'overwrite']
352
takes_args = ['location?']
354
def run(self, location=None, remember=False, overwrite=False):
355
from bzrlib.merge import merge
356
from shutil import rmtree
359
br_to = Branch.open_containing('.')[0]
360
stored_loc = br_to.get_parent()
362
if stored_loc is None:
363
raise BzrCommandError("No pull location known or specified.")
365
print "Using saved location: %s" % stored_loc
366
location = stored_loc
367
br_from = Branch.open(location)
369
br_to.working_tree().pull(br_from, remember, overwrite)
370
except DivergedBranches:
371
raise BzrCommandError("These branches have diverged."
375
class cmd_branch(Command):
376
"""Create a new copy of a branch.
378
If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
379
be used. In other words, "branch ../foo/bar" will attempt to create ./bar.
381
To retrieve the branch as of a particular revision, supply the --revision
382
parameter, as in "branch foo/bar -r 5".
384
--basis is to speed up branching from remote branches. When specified, it
385
copies all the file-contents, inventory and revision data from the basis
386
branch before copying anything from the remote branch.
388
takes_args = ['from_location', 'to_location?']
389
takes_options = ['revision', 'basis']
390
aliases = ['get', 'clone']
392
def run(self, from_location, to_location=None, revision=None, basis=None):
393
from bzrlib.clone import copy_branch
395
from shutil import rmtree
398
elif len(revision) > 1:
399
raise BzrCommandError(
400
'bzr branch --revision takes exactly 1 revision value')
402
br_from = Branch.open(from_location)
404
if e.errno == errno.ENOENT:
405
raise BzrCommandError('Source location "%s" does not'
406
' exist.' % to_location)
411
if basis is not None:
412
basis_branch = Branch.open_containing(basis)[0]
415
if len(revision) == 1 and revision[0] is not None:
416
revision_id = revision[0].in_history(br_from)[1]
419
if to_location is None:
420
to_location = os.path.basename(from_location.rstrip("/\\"))
423
name = os.path.basename(to_location) + '\n'
425
os.mkdir(to_location)
427
if e.errno == errno.EEXIST:
428
raise BzrCommandError('Target directory "%s" already'
429
' exists.' % to_location)
430
if e.errno == errno.ENOENT:
431
raise BzrCommandError('Parent of "%s" does not exist.' %
436
copy_branch(br_from, to_location, revision_id, basis_branch)
437
except bzrlib.errors.NoSuchRevision:
439
msg = "The branch %s has no revision %s." % (from_location, revision[0])
440
raise BzrCommandError(msg)
441
except bzrlib.errors.UnlistableBranch:
443
msg = "The branch %s cannot be used as a --basis"
444
raise BzrCommandError(msg)
446
branch = Branch.open(to_location)
447
name = StringIO(name)
448
branch.put_controlfile('branch-name', name)
453
class cmd_renames(Command):
454
"""Show list of renamed files.
456
# TODO: Option to show renames between two historical versions.
458
# TODO: Only show renames under dir, rather than in the whole branch.
459
takes_args = ['dir?']
462
def run(self, dir='.'):
463
b = Branch.open_containing(dir)[0]
464
old_inv = b.basis_tree().inventory
465
new_inv = b.read_working_inventory()
467
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
469
for old_name, new_name in renames:
470
print "%s => %s" % (old_name, new_name)
473
class cmd_info(Command):
474
"""Show statistical information about a branch."""
475
takes_args = ['branch?']
478
def run(self, branch=None):
480
b = Branch.open_containing(branch)[0]
484
class cmd_remove(Command):
485
"""Make a file unversioned.
487
This makes bzr stop tracking changes to a versioned file. It does
488
not delete the working copy.
490
takes_args = ['file+']
491
takes_options = ['verbose']
494
def run(self, file_list, verbose=False):
495
b = Branch.open_containing(file_list[0])[0]
496
tree = WorkingTree(b.base, b)
497
tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
500
class cmd_file_id(Command):
501
"""Print file_id of a particular file or directory.
503
The file_id is assigned when the file is first added and remains the
504
same through all revisions where the file exists, even when it is
508
takes_args = ['filename']
510
def run(self, filename):
511
b, relpath = Branch.open_containing(filename)
512
i = b.inventory.path2id(relpath)
514
raise BzrError("%r is not a versioned file" % filename)
519
class cmd_file_path(Command):
520
"""Print path of file_ids to a file or directory.
522
This prints one line for each directory down to the target,
523
starting at the branch root."""
525
takes_args = ['filename']
527
def run(self, filename):
528
b, relpath = Branch.open_containing(filename)
530
fid = inv.path2id(relpath)
532
raise BzrError("%r is not a versioned file" % filename)
533
for fip in inv.get_idpath(fid):
537
class cmd_revision_history(Command):
538
"""Display list of revision ids on this branch."""
542
for patchid in Branch.open_containing('.')[0].revision_history():
546
class cmd_ancestry(Command):
547
"""List all revisions merged into this branch."""
551
b = Branch.open_containing('.')[0]
552
for revision_id in b.get_ancestry(b.last_revision()):
556
class cmd_directories(Command):
557
"""Display list of versioned directories in this branch."""
560
for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
567
class cmd_init(Command):
568
"""Make a directory into a versioned branch.
570
Use this to create an empty branch, or before importing an
573
Recipe for importing a tree of files:
578
bzr commit -m 'imported project'
581
Branch.initialize('.')
584
class cmd_diff(Command):
585
"""Show differences in working tree.
587
If files are listed, only the changes in those files are listed.
588
Otherwise, all changes for the tree are listed.
595
# TODO: Allow diff across branches.
596
# TODO: Option to use external diff command; could be GNU diff, wdiff,
597
# or a graphical diff.
599
# TODO: Python difflib is not exactly the same as unidiff; should
600
# either fix it up or prefer to use an external diff.
602
# TODO: If a directory is given, diff everything under that.
604
# TODO: Selected-file diff is inefficient and doesn't show you
607
# TODO: This probably handles non-Unix newlines poorly.
609
takes_args = ['file*']
610
takes_options = ['revision', 'diff-options']
611
aliases = ['di', 'dif']
614
def run(self, revision=None, file_list=None, diff_options=None):
615
from bzrlib.diff import show_diff
618
b = Branch.open_containing(file_list[0])[0]
619
tree = WorkingTree(b.base, b)
620
file_list = [tree.relpath(f) for f in file_list]
621
if file_list == ['']:
622
# just pointing to top-of-tree
625
b = Branch.open_containing('.')[0]
627
if revision is not None:
628
if len(revision) == 1:
629
show_diff(b, revision[0], specific_files=file_list,
630
external_diff_options=diff_options)
631
elif len(revision) == 2:
632
show_diff(b, revision[0], specific_files=file_list,
633
external_diff_options=diff_options,
634
revision2=revision[1])
636
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
638
show_diff(b, None, specific_files=file_list,
639
external_diff_options=diff_options)
644
class cmd_deleted(Command):
645
"""List files deleted in the working tree.
647
# TODO: Show files deleted since a previous revision, or
648
# between two revisions.
649
# TODO: Much more efficient way to do this: read in new
650
# directories with readdir, rather than stating each one. Same
651
# level of effort but possibly much less IO. (Or possibly not,
652
# if the directories are very large...)
654
def run(self, show_ids=False):
655
b = Branch.open_containing('.')[0]
657
new = b.working_tree()
658
for path, ie in old.inventory.iter_entries():
659
if not new.has_id(ie.file_id):
661
print '%-50s %s' % (path, ie.file_id)
666
class cmd_modified(Command):
667
"""List files modified in working tree."""
671
from bzrlib.delta import compare_trees
673
b = Branch.open_containing('.')[0]
674
td = compare_trees(b.basis_tree(), b.working_tree())
676
for path, id, kind, text_modified, meta_modified in td.modified:
681
class cmd_added(Command):
682
"""List files added in working tree."""
686
b = Branch.open_containing('.')[0]
687
wt = b.working_tree()
688
basis_inv = b.basis_tree().inventory
691
if file_id in basis_inv:
693
path = inv.id2path(file_id)
694
if not os.access(b.abspath(path), os.F_OK):
700
class cmd_root(Command):
701
"""Show the tree root directory.
703
The root is the nearest enclosing directory with a .bzr control
705
takes_args = ['filename?']
707
def run(self, filename=None):
708
"""Print the branch root."""
709
b = Branch.open_containing(filename)[0]
713
class cmd_log(Command):
714
"""Show log of this branch.
716
To request a range of logs, you can use the command -r begin:end
717
-r revision requests a specific revision, -r :end or -r begin: are
721
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
723
takes_args = ['filename?']
724
takes_options = [Option('forward',
725
help='show from oldest to newest'),
726
'timezone', 'verbose',
727
'show-ids', 'revision',
728
Option('line', help='format with one line per revision'),
731
help='show revisions whose message matches this regexp',
733
Option('short', help='use moderately short format'),
736
def run(self, filename=None, timezone='original',
745
from bzrlib.log import log_formatter, show_log
747
assert message is None or isinstance(message, basestring), \
748
"invalid message argument %r" % message
749
direction = (forward and 'forward') or 'reverse'
752
b, fp = Branch.open_containing(filename)
754
file_id = b.read_working_inventory().path2id(fp)
756
file_id = None # points to branch root
758
b, relpath = Branch.open_containing('.')
764
elif len(revision) == 1:
765
rev1 = rev2 = revision[0].in_history(b).revno
766
elif len(revision) == 2:
767
rev1 = revision[0].in_history(b).revno
768
rev2 = revision[1].in_history(b).revno
770
raise BzrCommandError('bzr log --revision takes one or two values.')
777
mutter('encoding log as %r' % bzrlib.user_encoding)
779
# use 'replace' so that we don't abort if trying to write out
780
# in e.g. the default C locale.
781
outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
788
lf = log_formatter(log_format,
791
show_timezone=timezone)
804
class cmd_touching_revisions(Command):
805
"""Return revision-ids which affected a particular file.
807
A more user-friendly interface is "bzr log FILE"."""
809
takes_args = ["filename"]
811
def run(self, filename):
812
b, relpath = Branch.open_containing(filename)[0]
813
inv = b.read_working_inventory()
814
file_id = inv.path2id(relpath)
815
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
816
print "%6d %s" % (revno, what)
819
class cmd_ls(Command):
820
"""List files in a tree.
822
# TODO: Take a revision or remote path and list that tree instead.
825
def run(self, revision=None, verbose=False):
826
b, relpath = Branch.open_containing('.')[0]
828
tree = b.working_tree()
830
tree = b.revision_tree(revision.in_history(b).rev_id)
831
for fp, fc, kind, fid, entry in tree.list_files():
833
kindch = entry.kind_character()
834
print '%-8s %s%s' % (fc, fp, kindch)
840
class cmd_unknowns(Command):
841
"""List unknown files."""
844
from bzrlib.osutils import quotefn
845
for f in Branch.open_containing('.')[0].unknowns():
850
class cmd_ignore(Command):
851
"""Ignore a command or pattern.
853
To remove patterns from the ignore list, edit the .bzrignore file.
855
If the pattern contains a slash, it is compared to the whole path
856
from the branch root. Otherwise, it is compared to only the last
857
component of the path. To match a file only in the root directory,
860
Ignore patterns are case-insensitive on case-insensitive systems.
862
Note: wildcards must be quoted from the shell on Unix.
865
bzr ignore ./Makefile
868
# TODO: Complain if the filename is absolute
869
takes_args = ['name_pattern']
871
def run(self, name_pattern):
872
from bzrlib.atomicfile import AtomicFile
875
b, relpath = Branch.open_containing('.')
876
ifn = b.abspath('.bzrignore')
878
if os.path.exists(ifn):
881
igns = f.read().decode('utf-8')
887
# TODO: If the file already uses crlf-style termination, maybe
888
# we should use that for the newly added lines?
890
if igns and igns[-1] != '\n':
892
igns += name_pattern + '\n'
895
f = AtomicFile(ifn, 'wt')
896
f.write(igns.encode('utf-8'))
901
inv = b.working_tree().inventory
902
if inv.path2id('.bzrignore'):
903
mutter('.bzrignore is already versioned')
905
mutter('need to make new .bzrignore file versioned')
906
b.add(['.bzrignore'])
910
class cmd_ignored(Command):
911
"""List ignored files and the patterns that matched them.
913
See also: bzr ignore"""
916
tree = Branch.open_containing('.')[0].working_tree()
917
for path, file_class, kind, file_id, entry in tree.list_files():
918
if file_class != 'I':
920
## XXX: Slightly inefficient since this was already calculated
921
pat = tree.is_ignored(path)
922
print '%-50s %s' % (path, pat)
925
class cmd_lookup_revision(Command):
926
"""Lookup the revision-id from a revision-number
929
bzr lookup-revision 33
932
takes_args = ['revno']
935
def run(self, revno):
939
raise BzrCommandError("not a valid revision-number: %r" % revno)
941
print Branch.open_containing('.')[0].get_rev_id(revno)
944
class cmd_export(Command):
945
"""Export past revision to destination directory.
947
If no revision is specified this exports the last committed revision.
949
Format may be an "exporter" name, such as tar, tgz, tbz2. If none is
950
given, try to find the format with the extension. If no extension
951
is found exports to a directory (equivalent to --format=dir).
953
Root may be the top directory for tar, tgz and tbz2 formats. If none
954
is given, the top directory will be the root name of the file."""
955
# TODO: list known exporters
956
takes_args = ['dest']
957
takes_options = ['revision', 'format', 'root']
958
def run(self, dest, revision=None, format=None, root=None):
960
b = Branch.open_containing('.')[0]
962
rev_id = b.last_revision()
964
if len(revision) != 1:
965
raise BzrError('bzr export --revision takes exactly 1 argument')
966
rev_id = revision[0].in_history(b).rev_id
967
t = b.revision_tree(rev_id)
968
arg_root, ext = os.path.splitext(os.path.basename(dest))
969
if ext in ('.gz', '.bz2'):
970
new_root, new_ext = os.path.splitext(arg_root)
971
if new_ext == '.tar':
979
elif ext in (".tar.gz", ".tgz"):
981
elif ext in (".tar.bz2", ".tbz2"):
985
t.export(dest, format, root)
988
class cmd_cat(Command):
989
"""Write a file's text from a previous revision."""
991
takes_options = ['revision']
992
takes_args = ['filename']
995
def run(self, filename, revision=None):
997
raise BzrCommandError("bzr cat requires a revision number")
998
elif len(revision) != 1:
999
raise BzrCommandError("bzr cat --revision takes exactly one number")
1000
b, relpath = Branch.open_containing(filename)
1001
b.print_file(relpath, revision[0].in_history(b).revno)
1004
class cmd_local_time_offset(Command):
1005
"""Show the offset in seconds from GMT to local time."""
1009
print bzrlib.osutils.local_time_offset()
1013
class cmd_commit(Command):
1014
"""Commit changes into a new revision.
1016
If no arguments are given, the entire tree is committed.
1018
If selected files are specified, only changes to those files are
1019
committed. If a directory is specified then the directory and everything
1020
within it is committed.
1022
A selected-file commit may fail in some cases where the committed
1023
tree would be invalid, such as trying to commit a file in a
1024
newly-added directory that is not itself committed.
1026
# TODO: Run hooks on tree to-be-committed, and after commit.
1028
# TODO: Strict commit that fails if there are deleted files.
1029
# (what does "deleted files" mean ??)
1031
# TODO: Give better message for -s, --summary, used by tla people
1033
# XXX: verbose currently does nothing
1035
takes_args = ['selected*']
1036
takes_options = ['message', 'verbose',
1038
help='commit even if nothing has changed'),
1039
Option('file', type=str,
1041
help='file containing commit message'),
1043
help="refuse to commit if there are unknown "
1044
"files in the working tree."),
1046
aliases = ['ci', 'checkin']
1048
def run(self, message=None, file=None, verbose=True, selected_list=None,
1049
unchanged=False, strict=False):
1050
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1052
from bzrlib.msgeditor import edit_commit_message
1053
from bzrlib.status import show_status
1054
from cStringIO import StringIO
1056
b = Branch.open_containing('.')[0]
1057
tree = WorkingTree(b.base, b)
1059
selected_list = [tree.relpath(s) for s in selected_list]
1060
if message is None and not file:
1061
catcher = StringIO()
1062
show_status(b, specific_files=selected_list,
1064
message = edit_commit_message(catcher.getvalue())
1067
raise BzrCommandError("please specify a commit message"
1068
" with either --message or --file")
1069
elif message and file:
1070
raise BzrCommandError("please specify either --message or --file")
1074
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1077
raise BzrCommandError("empty commit message specified")
1080
b.commit(message, specific_files=selected_list,
1081
allow_pointless=unchanged, strict=strict)
1082
except PointlessCommit:
1083
# FIXME: This should really happen before the file is read in;
1084
# perhaps prepare the commit; get the message; then actually commit
1085
raise BzrCommandError("no changes to commit",
1086
["use --unchanged to commit anyhow"])
1087
except ConflictsInTree:
1088
raise BzrCommandError("Conflicts detected in working tree. "
1089
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1090
except StrictCommitFailed:
1091
raise BzrCommandError("Commit refused because there are unknown "
1092
"files in the working tree.")
1095
class cmd_check(Command):
1096
"""Validate consistency of branch history.
1098
This command checks various invariants about the branch storage to
1099
detect data corruption or bzr bugs.
1101
takes_args = ['dir?']
1102
takes_options = ['verbose']
1104
def run(self, dir='.', verbose=False):
1105
from bzrlib.check import check
1106
check(Branch.open_containing(dir)[0], verbose)
1109
class cmd_scan_cache(Command):
1112
from bzrlib.hashcache import HashCache
1118
print '%6d stats' % c.stat_count
1119
print '%6d in hashcache' % len(c._cache)
1120
print '%6d files removed from cache' % c.removed_count
1121
print '%6d hashes updated' % c.update_count
1122
print '%6d files changed too recently to cache' % c.danger_count
1129
class cmd_upgrade(Command):
1130
"""Upgrade branch storage to current format.
1132
The check command or bzr developers may sometimes advise you to run
1135
This version of this command upgrades from the full-text storage
1136
used by bzr 0.0.8 and earlier to the weave format (v5).
1138
takes_args = ['dir?']
1140
def run(self, dir='.'):
1141
from bzrlib.upgrade import upgrade
1145
class cmd_whoami(Command):
1146
"""Show bzr user id."""
1147
takes_options = ['email']
1150
def run(self, email=False):
1152
b = bzrlib.branch.Branch.open_containing('.')[0]
1153
config = bzrlib.config.BranchConfig(b)
1154
except NotBranchError:
1155
config = bzrlib.config.GlobalConfig()
1158
print config.user_email()
1160
print config.username()
1163
class cmd_selftest(Command):
1164
"""Run internal test suite.
1166
This creates temporary test directories in the working directory,
1167
but not existing data is affected. These directories are deleted
1168
if the tests pass, or left behind to help in debugging if they
1171
If arguments are given, they are regular expressions that say
1172
which tests should run.
1174
# TODO: --list should give a list of all available tests
1176
takes_args = ['testspecs*']
1177
takes_options = ['verbose',
1178
Option('one', help='stop when one test fails'),
1181
def run(self, testspecs_list=None, verbose=False, one=False):
1183
from bzrlib.selftest import selftest
1184
# we don't want progress meters from the tests to go to the
1185
# real output; and we don't want log messages cluttering up
1187
save_ui = bzrlib.ui.ui_factory
1188
bzrlib.trace.info('running tests...')
1190
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
1191
if testspecs_list is not None:
1192
pattern = '|'.join(testspecs_list)
1195
result = selftest(verbose=verbose,
1197
stop_on_failure=one)
1199
bzrlib.trace.info('tests passed')
1201
bzrlib.trace.info('tests failed')
1202
return int(not result)
1204
bzrlib.ui.ui_factory = save_ui
1208
print "bzr (bazaar-ng) %s" % bzrlib.__version__
1209
# is bzrlib itself in a branch?
1210
bzrrev = bzrlib.get_bzr_revision()
1212
print " (bzr checkout, revision %d {%s})" % bzrrev
1213
print bzrlib.__copyright__
1214
print "http://bazaar-ng.org/"
1216
print "bzr comes with ABSOLUTELY NO WARRANTY. bzr is free software, and"
1217
print "you may use, modify and redistribute it under the terms of the GNU"
1218
print "General Public License version 2 or later."
1221
class cmd_version(Command):
1222
"""Show version of bzr."""
1227
class cmd_rocks(Command):
1228
"""Statement of optimism."""
1232
print "it sure does!"
1235
class cmd_find_merge_base(Command):
1236
"""Find and print a base revision for merging two branches.
1238
# TODO: Options to specify revisions on either side, as if
1239
# merging only part of the history.
1240
takes_args = ['branch', 'other']
1244
def run(self, branch, other):
1245
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1247
branch1 = Branch.open_containing(branch)[0]
1248
branch2 = Branch.open_containing(other)[0]
1250
history_1 = branch1.revision_history()
1251
history_2 = branch2.revision_history()
1253
last1 = branch1.last_revision()
1254
last2 = branch2.last_revision()
1256
source = MultipleRevisionSources(branch1, branch2)
1258
base_rev_id = common_ancestor(last1, last2, source)
1260
print 'merge base is revision %s' % base_rev_id
1264
if base_revno is None:
1265
raise bzrlib.errors.UnrelatedBranches()
1267
print ' r%-6d in %s' % (base_revno, branch)
1269
other_revno = branch2.revision_id_to_revno(base_revid)
1271
print ' r%-6d in %s' % (other_revno, other)
1275
class cmd_merge(Command):
1276
"""Perform a three-way merge.
1278
The branch is the branch you will merge from. By default, it will
1279
merge the latest revision. If you specify a revision, that
1280
revision will be merged. If you specify two revisions, the first
1281
will be used as a BASE, and the second one as OTHER. Revision
1282
numbers are always relative to the specified branch.
1284
By default bzr will try to merge in all new work from the other
1285
branch, automatically determining an appropriate base. If this
1286
fails, you may need to give an explicit base.
1290
To merge the latest revision from bzr.dev
1291
bzr merge ../bzr.dev
1293
To merge changes up to and including revision 82 from bzr.dev
1294
bzr merge -r 82 ../bzr.dev
1296
To merge the changes introduced by 82, without previous changes:
1297
bzr merge -r 81..82 ../bzr.dev
1299
merge refuses to run if there are any uncommitted changes, unless
1302
takes_args = ['branch?']
1303
takes_options = ['revision', 'force', 'merge-type',
1304
Option('show-base', help="Show base revision text in "
1307
def run(self, branch=None, revision=None, force=False, merge_type=None,
1309
from bzrlib.merge import merge
1310
from bzrlib.merge_core import ApplyMerge3
1311
if merge_type is None:
1312
merge_type = ApplyMerge3
1314
branch = Branch.open_containing('.')[0].get_parent()
1316
raise BzrCommandError("No merge location known or specified.")
1318
print "Using saved location: %s" % branch
1319
if revision is None or len(revision) < 1:
1321
other = [branch, -1]
1323
if len(revision) == 1:
1325
other_branch = Branch.open_containing(branch)[0]
1326
revno = revision[0].in_history(other_branch).revno
1327
other = [branch, revno]
1329
assert len(revision) == 2
1330
if None in revision:
1331
raise BzrCommandError(
1332
"Merge doesn't permit that revision specifier.")
1333
b = Branch.open_containing(branch)[0]
1335
base = [branch, revision[0].in_history(b).revno]
1336
other = [branch, revision[1].in_history(b).revno]
1339
conflict_count = merge(other, base, check_clean=(not force),
1340
merge_type=merge_type,
1341
show_base=show_base)
1342
if conflict_count != 0:
1346
except bzrlib.errors.AmbiguousBase, e:
1347
m = ("sorry, bzr can't determine the right merge base yet\n"
1348
"candidates are:\n "
1349
+ "\n ".join(e.bases)
1351
"please specify an explicit base with -r,\n"
1352
"and (if you want) report this to the bzr developers\n")
1356
class cmd_revert(Command):
1357
"""Reverse all changes since the last commit.
1359
Only versioned files are affected. Specify filenames to revert only
1360
those files. By default, any files that are changed will be backed up
1361
first. Backup files have a '~' appended to their name.
1363
takes_options = ['revision', 'no-backup']
1364
takes_args = ['file*']
1365
aliases = ['merge-revert']
1367
def run(self, revision=None, no_backup=False, file_list=None):
1368
from bzrlib.merge import merge
1369
from bzrlib.commands import parse_spec
1371
if file_list is not None:
1372
if len(file_list) == 0:
1373
raise BzrCommandError("No files specified")
1374
if revision is None:
1376
elif len(revision) != 1:
1377
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1379
b = Branch.open_containing('.')[0]
1380
revno = revision[0].in_history(b).revno
1381
merge(('.', revno), parse_spec('.'),
1384
backup_files=not no_backup,
1385
file_list=file_list)
1387
Branch.open_containing('.')[0].set_pending_merges([])
1390
class cmd_assert_fail(Command):
1391
"""Test reporting of assertion failures"""
1394
assert False, "always fails"
1397
class cmd_help(Command):
1398
"""Show help on a command or other topic.
1400
For a list of all available commands, say 'bzr help commands'."""
1401
takes_options = ['long']
1402
takes_args = ['topic?']
1406
def run(self, topic=None, long=False):
1408
if topic is None and long:
1413
class cmd_shell_complete(Command):
1414
"""Show appropriate completions for context.
1416
For a list of all available commands, say 'bzr shell-complete'."""
1417
takes_args = ['context?']
1422
def run(self, context=None):
1423
import shellcomplete
1424
shellcomplete.shellcomplete(context)
1427
class cmd_fetch(Command):
1428
"""Copy in history from another branch but don't merge it.
1430
This is an internal method used for pull and merge."""
1432
takes_args = ['from_branch', 'to_branch']
1433
def run(self, from_branch, to_branch):
1434
from bzrlib.fetch import Fetcher
1435
from bzrlib.branch import Branch
1436
from_b = Branch(from_branch)
1437
to_b = Branch(to_branch)
1438
Fetcher(to_b, from_b)
1442
class cmd_missing(Command):
1443
"""What is missing in this branch relative to other branch.
1445
# TODO: rewrite this in terms of ancestry so that it shows only
1448
takes_args = ['remote?']
1449
aliases = ['mis', 'miss']
1450
# We don't have to add quiet to the list, because
1451
# unknown options are parsed as booleans
1452
takes_options = ['verbose', 'quiet']
1455
def run(self, remote=None, verbose=False, quiet=False):
1456
from bzrlib.errors import BzrCommandError
1457
from bzrlib.missing import show_missing
1459
if verbose and quiet:
1460
raise BzrCommandError('Cannot pass both quiet and verbose')
1462
b = Branch.open_containing('.')[0]
1463
parent = b.get_parent()
1466
raise BzrCommandError("No missing location known or specified.")
1469
print "Using last location: %s" % parent
1471
elif parent is None:
1472
# We only update parent if it did not exist, missing
1473
# should not change the parent
1474
b.set_parent(remote)
1475
br_remote = Branch.open_containing(remote)[0]
1476
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1479
class cmd_plugins(Command):
1484
import bzrlib.plugin
1485
from inspect import getdoc
1486
for plugin in bzrlib.plugin.all_plugins:
1487
if hasattr(plugin, '__path__'):
1488
print plugin.__path__[0]
1489
elif hasattr(plugin, '__file__'):
1490
print plugin.__file__
1496
print '\t', d.split('\n')[0]
1499
class cmd_testament(Command):
1500
"""Show testament (signing-form) of a revision."""
1501
takes_options = ['revision', 'long']
1502
takes_args = ['branch?']
1504
def run(self, branch='.', revision=None, long=False):
1505
from bzrlib.testament import Testament
1506
b = Branch.open_containing(branch)[0]
1509
if revision is None:
1510
rev_id = b.last_revision()
1512
rev_id = revision[0].in_history(b).rev_id
1513
t = Testament.from_revision(b, rev_id)
1515
sys.stdout.writelines(t.as_text_lines())
1517
sys.stdout.write(t.as_short_text())
1522
class cmd_annotate(Command):
1523
"""Show the origin of each line in a file.
1525
This prints out the given file with an annotation on the left side
1526
indicating which revision, author and date introduced the change.
1528
If the origin is the same for a run of consecutive lines, it is
1529
shown only at the top, unless the --all option is given.
1531
# TODO: annotate directories; showing when each file was last changed
1532
# TODO: annotate a previous version of a file
1533
# TODO: if the working copy is modified, show annotations on that
1534
# with new uncommitted lines marked
1535
aliases = ['blame', 'praise']
1536
takes_args = ['filename']
1537
takes_options = [Option('all', help='show annotations on all lines'),
1538
Option('long', help='show date in annotations'),
1542
def run(self, filename, all=False, long=False):
1543
from bzrlib.annotate import annotate_file
1544
b, relpath = Branch.open_containing(filename)
1547
tree = WorkingTree(b.base, b)
1548
tree = b.revision_tree(b.last_revision())
1549
file_id = tree.inventory.path2id(relpath)
1550
file_version = tree.inventory[file_id].revision
1551
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1556
class cmd_re_sign(Command):
1557
"""Create a digital signature for an existing revision."""
1558
# TODO be able to replace existing ones.
1560
hidden = True # is this right ?
1561
takes_args = ['revision_id?']
1562
takes_options = ['revision']
1564
def run(self, revision_id=None, revision=None):
1565
import bzrlib.config as config
1566
import bzrlib.gpg as gpg
1567
if revision_id is not None and revision is not None:
1568
raise BzrCommandError('You can only supply one of revision_id or --revision')
1569
if revision_id is None and revision is None:
1570
raise BzrCommandError('You must supply either --revision or a revision_id')
1571
b = Branch.open_containing('.')[0]
1572
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1573
if revision_id is not None:
1574
b.sign_revision(revision_id, gpg_strategy)
1575
elif revision is not None:
1576
if len(revision) == 1:
1577
revno, rev_id = revision[0].in_history(b)
1578
b.sign_revision(rev_id, gpg_strategy)
1579
elif len(revision) == 2:
1580
# are they both on rh- if so we can walk between them
1581
# might be nice to have a range helper for arbitrary
1582
# revision paths. hmm.
1583
from_revno, from_revid = revision[0].in_history(b)
1584
to_revno, to_revid = revision[1].in_history(b)
1585
if to_revid is None:
1586
to_revno = b.revno()
1587
if from_revno is None or to_revno is None:
1588
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1589
for revno in range(from_revno, to_revno + 1):
1590
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1592
raise BzrCommandError('Please supply either one revision, or a range.')
1595
# these get imported and then picked up by the scan for cmd_*
1596
# TODO: Some more consistent way to split command definitions across files;
1597
# we do need to load at least some information about them to know of
1599
from bzrlib.conflicts import cmd_resolve, cmd_conflicts