14
14
# along with this program; if not, write to the Free Software
15
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.revision import common_ancestor
30
import bzrlib.errors as errors
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
32
NotBranchError, DivergedBranches, NotConflicted,
33
NoSuchFile, NoWorkingTree)
34
from bzrlib.option import Option
35
from bzrlib.revisionspec import RevisionSpec
22
36
import bzrlib.trace
23
37
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError
25
from bzrlib.branch import find_branch
26
from bzrlib import BZRDIR
27
from bzrlib.commands import Command
38
from bzrlib.workingtree import WorkingTree
41
def branch_files(file_list, default_branch='.'):
43
return inner_branch_files(file_list, default_branch)
44
except NotBranchError:
45
raise BzrCommandError("%s is not in the same branch as %s" %
46
(filename, file_list[0]))
48
def inner_branch_files(file_list, default_branch='.'):
50
Return a branch and list of branch-relative paths.
51
If supplied file_list is empty or None, the branch default will be used,
52
and returned file_list will match the original.
54
if file_list is None or len(file_list) == 0:
55
return Branch.open_containing(default_branch)[0], file_list
56
b = Branch.open_containing(file_list[0])[0]
58
# note that if this is a remote branch, we would want
59
# relpath against the transport. RBC 20051018
60
# Most branch ops can't meaningfully operate on files in remote branches;
61
# the above comment was in cmd_status. ADHB 20051026
62
tree = WorkingTree(b.base, b)
64
for filename in file_list:
65
new_list.append(tree.relpath(filename))
69
# TODO: Make sure no commands unconditionally use the working directory as a
70
# branch. If a filename argument is used, the first of them should be used to
71
# specify the branch. (Perhaps this can be factored out into some kind of
72
# Argument class, representing a file in a branch, where the first occurrence
30
75
class cmd_status(Command):
31
76
"""Display status summary.
63
108
files or directories is reported. If a directory is given, status
64
109
is reported for everything inside that directory.
66
If a revision is specified, the changes since that revision are shown.
111
If a revision argument is given, the status is calculated against
112
that revision, or between two revisions if two are provided.
115
# TODO: --no-recurse, --recurse options
68
117
takes_args = ['file*']
69
118
takes_options = ['all', 'show-ids', 'revision']
70
119
aliases = ['st', 'stat']
72
def run(self, all=False, show_ids=False, file_list=None):
74
b = find_branch(file_list[0])
75
file_list = [b.relpath(x) for x in file_list]
76
# special case: only one path was given and it's the root
122
def run(self, all=False, show_ids=False, file_list=None, revision=None):
123
b, file_list = branch_files(file_list)
83
125
from bzrlib.status import show_status
84
126
show_status(b, show_unchanged=all, show_ids=show_ids,
85
specific_files=file_list)
127
specific_files=file_list, revision=revision)
88
130
class cmd_cat_revision(Command):
89
"""Write out metadata for a revision."""
131
"""Write out metadata for a revision.
133
The revision to print can either be specified by a specific
134
revision identifier, or you can use --revision.
92
takes_args = ['revision_id']
138
takes_args = ['revision_id?']
139
takes_options = ['revision']
94
def run(self, revision_id):
96
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
142
def run(self, revision_id=None, revision=None):
144
if revision_id is not None and revision is not None:
145
raise BzrCommandError('You can only supply one of revision_id or --revision')
146
if revision_id is None and revision is None:
147
raise BzrCommandError('You must supply either --revision or a revision_id')
148
b = Branch.open_containing('.')[0]
149
if revision_id is not None:
150
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
151
elif revision is not None:
154
raise BzrCommandError('You cannot specify a NULL revision.')
155
revno, rev_id = rev.in_history(b)
156
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
99
159
class cmd_revno(Command):
100
160
"""Show current revision number.
102
162
This is equal to the number of revisions on this branch."""
104
print find_branch('.').revno()
165
print Branch.open_containing('.')[0].revno()
107
168
class cmd_revision_info(Command):
145
211
Therefore simply saying 'bzr add' will version all files that
146
212
are currently unknown.
148
TODO: Perhaps adding a file whose directly is not versioned should
149
recursively add that parent, rather than giving an error?
214
Adding a file whose parent directory is not versioned will
215
implicitly add the parent, and so on up to the root. This means
216
you should never need to explictly add a directory, they'll just
217
get added when you add a file in the directory.
151
219
takes_args = ['file*']
152
takes_options = ['verbose', 'no-recurse']
220
takes_options = ['no-recurse', 'quiet']
154
def run(self, file_list, verbose=False, no_recurse=False):
155
# verbose currently has no effect
156
from bzrlib.add import smart_add, add_reporter_print
157
smart_add(file_list, not no_recurse, add_reporter_print)
222
def run(self, file_list, no_recurse=False, quiet=False):
223
from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
225
reporter = add_reporter_null
227
reporter = add_reporter_print
228
smart_add(file_list, not no_recurse, reporter)
161
231
class cmd_mkdir(Command):
274
343
if len(names_list) != 2:
275
344
raise BzrCommandError('to mv multiple files the destination '
276
345
'must be a versioned directory')
277
for pair in b.move(rel_names[0], rel_names[1]):
278
print "%s => %s" % pair
346
b.rename_one(rel_names[0], rel_names[1])
347
print "%s => %s" % (rel_names[0], rel_names[1])
283
350
class cmd_pull(Command):
284
351
"""Pull any changes from another branch into the current one.
286
If the location is omitted, the last-used location will be used.
287
Both the revision history and the working directory will be
353
If there is no default location set, the first pull will set it. After
354
that, you can omit the location to use the default. To change the
355
default, use --remember.
290
357
This command only works on branches that have not diverged. Branches are
291
358
considered diverged if both branches have had commits without first
292
359
pulling from the other.
294
361
If branches have diverged, you can use 'bzr merge' to pull the text changes
295
from one into the other.
362
from one into the other. Once one branch has merged, the other should
363
be able to pull it again.
365
If you want to forget your local changes and just update your branch to
366
match the remote one, use --overwrite.
368
takes_options = ['remember', 'overwrite', 'verbose']
297
369
takes_args = ['location?']
299
def run(self, location=None):
371
def run(self, location=None, remember=False, overwrite=False, verbose=False):
300
372
from bzrlib.merge import merge
302
373
from shutil import rmtree
304
from bzrlib.branch import pull_loc
306
br_to = find_branch('.')
309
stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
311
if e.errno != errno.ENOENT:
376
br_to = Branch.open_containing('.')[0]
377
bound_loc = br_to.get_bound_location()
379
br = Branch.open(bound_loc)
380
stored_loc = br.get_parent()
383
stored_loc = br_to.get_parent()
313
384
if location is None:
314
385
if stored_loc is None:
315
386
raise BzrCommandError("No pull location known or specified.")
317
print "Using last location: %s" % stored_loc
318
location = stored_loc
319
cache_root = tempfile.mkdtemp()
320
from bzrlib.branch import DivergedBranches
321
br_from = find_branch(location)
322
location = pull_loc(br_from)
323
old_revno = br_to.revno()
325
from branch import find_cached_branch, DivergedBranches
326
br_from = find_cached_branch(location, cache_root)
327
location = pull_loc(br_from)
328
old_revno = br_to.revno()
330
br_to.update_revisions(br_from)
331
except DivergedBranches:
332
raise BzrCommandError("These branches have diverged."
335
merge(('.', -1), ('.', old_revno), check_clean=False)
336
if location != stored_loc:
337
br_to.controlfile("x-pull", "wb").write(location + "\n")
388
print "Using saved location: %s" % stored_loc
389
location = stored_loc
390
br_from = Branch.open(location)
392
old_rh = br_to.revision_history()
393
br_to.working_tree().pull(br_from, overwrite)
394
except DivergedBranches:
395
raise BzrCommandError("These branches have diverged."
397
if br_to.get_parent() is None or remember:
398
br_to.set_parent(location)
401
new_rh = br_to.revision_history()
404
from bzrlib.log import show_changed_revisions
405
show_changed_revisions(br_to, old_rh, new_rh)
408
class cmd_push(Command):
409
"""Push this branch into another branch.
411
The remote branch will not have its working tree populated because this
412
is both expensive, and may not be supported on the remote file system.
414
Some smart servers or protocols *may* put the working tree in place.
416
If there is no default push location set, the first push will set it.
417
After that, you can omit the location to use the default. To change the
418
default, use --remember.
420
This command only works on branches that have not diverged. Branches are
421
considered diverged if the branch being pushed to is not an older version
424
If branches have diverged, you can use 'bzr push --overwrite' to replace
425
the other branch completely.
427
If you want to ensure you have the different changes in the other branch,
428
do a merge (see bzr help merge) from the other branch, and commit that
429
before doing a 'push --overwrite'.
431
takes_options = ['remember', 'overwrite',
432
Option('create-prefix',
433
help='Create the path leading up to the branch '
434
'if it does not already exist')]
435
takes_args = ['location?']
437
def run(self, location=None, remember=False, overwrite=False,
438
create_prefix=False, verbose=False):
440
from shutil import rmtree
441
from bzrlib.transport import get_transport
443
br_from = Branch.open_containing('.')[0]
444
stored_loc = br_from.get_push_location()
446
if stored_loc is None:
447
raise BzrCommandError("No push location known or specified.")
449
print "Using saved location: %s" % stored_loc
450
location = stored_loc
452
br_to = Branch.open(location)
453
except NotBranchError:
455
transport = get_transport(location).clone('..')
456
if not create_prefix:
458
transport.mkdir(transport.relpath(location))
460
raise BzrCommandError("Parent directory of %s "
461
"does not exist." % location)
463
current = transport.base
464
needed = [(transport, transport.relpath(location))]
467
transport, relpath = needed[-1]
468
transport.mkdir(relpath)
471
new_transport = transport.clone('..')
472
needed.append((new_transport,
473
new_transport.relpath(transport.base)))
474
if new_transport.base == transport.base:
475
raise BzrCommandError("Could not creeate "
479
br_to = Branch.initialize(location)
481
old_rh = br_to.revision_history()
482
br_to.pull(br_from, overwrite)
483
except DivergedBranches:
484
raise BzrCommandError("These branches have diverged."
485
" Try a merge then push with overwrite.")
486
if br_from.get_push_location() is None or remember:
487
br_from.set_push_location(location)
490
new_rh = br_to.revision_history()
493
from bzrlib.log import show_changed_revisions
494
show_changed_revisions(br_to, old_rh, new_rh)
343
496
class cmd_branch(Command):
344
497
"""Create a new copy of a branch.
349
502
To retrieve the branch as of a particular revision, supply the --revision
350
503
parameter, as in "branch foo/bar -r 5".
505
--basis is to speed up branching from remote branches. When specified, it
506
copies all the file-contents, inventory and revision data from the basis
507
branch before copying anything from the remote branch.
352
509
takes_args = ['from_location', 'to_location?']
353
takes_options = ['revision']
510
takes_options = ['revision', 'basis', 'bound', 'unbound']
354
511
aliases = ['get', 'clone']
356
def run(self, from_location, to_location=None, revision=None):
357
from bzrlib.branch import copy_branch, find_cached_branch
513
def run(self, from_location, to_location=None, revision=None, basis=None,
514
bound=False, unbound=False):
515
from bzrlib.clone import copy_branch
360
517
from shutil import rmtree
361
cache_root = tempfile.mkdtemp()
365
elif len(revision) > 1:
366
raise BzrCommandError(
367
'bzr branch --revision takes exactly 1 revision value')
369
br_from = find_cached_branch(from_location, cache_root)
371
if e.errno == errno.ENOENT:
372
raise BzrCommandError('Source location "%s" does not'
373
' exist.' % to_location)
520
elif len(revision) > 1:
521
raise BzrCommandError(
522
'bzr branch --revision takes exactly 1 revision value')
523
if bound and unbound:
524
raise BzrCommandError('Cannot supply both bound and unbound at the same time')
526
br_from = Branch.open(from_location)
528
if e.errno == errno.ENOENT:
529
raise BzrCommandError('Source location "%s" does not'
530
' exist.' % to_location)
535
if basis is not None:
536
basis_branch = Branch.open_containing(basis)[0]
539
if len(revision) == 1 and revision[0] is not None:
540
revision_id = revision[0].in_history(br_from)[1]
376
543
if to_location is None:
377
544
to_location = os.path.basename(from_location.rstrip("/\\"))
547
name = os.path.basename(to_location) + '\n'
379
549
os.mkdir(to_location)
380
550
except OSError, e:
390
copy_branch(br_from, to_location, revision[0])
560
copy_branch(br_from, to_location, revision_id, basis_branch)
391
561
except bzrlib.errors.NoSuchRevision:
392
562
rmtree(to_location)
393
msg = "The branch %s has no revision %d." % (from_location, revision[0])
394
raise BzrCommandError(msg)
563
msg = "The branch %s has no revision %s." % (from_location, revision[0])
564
raise BzrCommandError(msg)
565
except bzrlib.errors.UnlistableBranch:
567
msg = "The branch %s cannot be used as a --basis" % (basis,)
568
raise BzrCommandError(msg)
569
branch = Branch.open(to_location)
571
name = StringIO(name)
572
branch.put_controlfile('branch-name', name)
399
579
class cmd_renames(Command):
400
580
"""Show list of renamed files.
402
TODO: Option to show renames between two historical versions.
404
TODO: Only show renames under dir, rather than in the whole branch.
582
# TODO: Option to show renames between two historical versions.
584
# TODO: Only show renames under dir, rather than in the whole branch.
406
585
takes_args = ['dir?']
408
588
def run(self, dir='.'):
589
b = Branch.open_containing(dir)[0]
410
590
old_inv = b.basis_tree().inventory
411
new_inv = b.read_working_inventory()
591
new_inv = b.working_tree().read_working_inventory()
413
593
renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
518
726
If files are listed, only the changes in those files are listed.
519
727
Otherwise, all changes for the tree are listed.
521
TODO: Allow diff across branches.
523
TODO: Option to use external diff command; could be GNU diff, wdiff,
526
TODO: Python difflib is not exactly the same as unidiff; should
527
either fix it up or prefer to use an external diff.
529
TODO: If a directory is given, diff everything under that.
531
TODO: Selected-file diff is inefficient and doesn't show you
534
TODO: This probably handles non-Unix newlines poorly.
734
# TODO: Allow diff across branches.
735
# TODO: Option to use external diff command; could be GNU diff, wdiff,
736
# or a graphical diff.
738
# TODO: Python difflib is not exactly the same as unidiff; should
739
# either fix it up or prefer to use an external diff.
741
# TODO: If a directory is given, diff everything under that.
743
# TODO: Selected-file diff is inefficient and doesn't show you
746
# TODO: This probably handles non-Unix newlines poorly.
542
748
takes_args = ['file*']
543
749
takes_options = ['revision', 'diff-options']
544
750
aliases = ['di', 'dif']
546
753
def run(self, revision=None, file_list=None, diff_options=None):
547
754
from bzrlib.diff import show_diff
550
b = find_branch(file_list[0])
551
file_list = [b.relpath(f) for f in file_list]
552
if file_list == ['']:
553
# just pointing to top-of-tree
756
b, file_list = inner_branch_files(file_list)
758
except NotBranchError:
759
if len(file_list) != 2:
760
raise BzrCommandError("Files are in different branches")
762
b, file1 = Branch.open_containing(file_list[0])
763
b2, file2 = Branch.open_containing(file_list[1])
764
if file1 != "" or file2 != "":
765
raise BzrCommandError("Files are in different branches")
558
767
if revision is not None:
769
raise BzrCommandError("Can't specify -r with two branches")
559
770
if len(revision) == 1:
560
show_diff(b, revision[0], specific_files=file_list,
561
external_diff_options=diff_options)
771
return show_diff(b, revision[0], specific_files=file_list,
772
external_diff_options=diff_options)
562
773
elif len(revision) == 2:
563
show_diff(b, revision[0], specific_files=file_list,
564
external_diff_options=diff_options,
565
revision2=revision[1])
774
return show_diff(b, revision[0], specific_files=file_list,
775
external_diff_options=diff_options,
776
revision2=revision[1])
567
778
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
569
show_diff(b, None, specific_files=file_list,
570
external_diff_options=diff_options)
780
return show_diff(b, None, specific_files=file_list,
781
external_diff_options=diff_options, b2=b2)
575
784
class cmd_deleted(Command):
576
785
"""List files deleted in the working tree.
578
TODO: Show files deleted since a previous revision, or between two revisions.
787
# TODO: Show files deleted since a previous revision, or
788
# between two revisions.
789
# TODO: Much more efficient way to do this: read in new
790
# directories with readdir, rather than stating each one. Same
791
# level of effort but possibly much less IO. (Or possibly not,
792
# if the directories are very large...)
580
794
def run(self, show_ids=False):
795
b = Branch.open_containing('.')[0]
582
796
old = b.basis_tree()
583
797
new = b.working_tree()
585
## TODO: Much more efficient way to do this: read in new
586
## directories with readdir, rather than stating each one. Same
587
## level of effort but possibly much less IO. (Or possibly not,
588
## if the directories are very large...)
590
798
for path, ie in old.inventory.iter_entries():
591
799
if not new.has_id(ie.file_id):
633
843
The root is the nearest enclosing directory with a .bzr control
635
845
takes_args = ['filename?']
636
847
def run(self, filename=None):
637
848
"""Print the branch root."""
638
b = find_branch(filename)
639
print getattr(b, 'base', None) or getattr(b, 'baseurl')
849
b = Branch.open_containing(filename)[0]
642
853
class cmd_log(Command):
643
854
"""Show log of this branch.
645
To request a range of logs, you can use the command -r begin:end
646
-r revision requests a specific revision, -r :end or -r begin: are
856
To request a range of logs, you can use the command -r begin..end
857
-r revision requests a specific revision, -r ..end or -r begin.. are
649
--message allows you to give a regular expression, which will be evaluated
650
so that only matching entries will be displayed.
652
TODO: Make --revision support uuid: and hash: [future tag:] notation.
861
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
656
863
takes_args = ['filename?']
657
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
658
'long', 'message', 'short',]
864
takes_options = [Option('forward',
865
help='show from oldest to newest'),
866
'timezone', 'verbose',
867
'show-ids', 'revision',
868
Option('line', help='format with one line per revision'),
871
help='show revisions whose message matches this regexp',
873
Option('short', help='use moderately short format'),
660
876
def run(self, filename=None, timezone='original',
729
951
A more user-friendly interface is "bzr log FILE"."""
731
953
takes_args = ["filename"]
732
955
def run(self, filename):
733
b = find_branch(filename)
734
inv = b.read_working_inventory()
735
file_id = inv.path2id(b.relpath(filename))
956
b, relpath = Branch.open_containing(filename)[0]
957
inv = b.working_tree().read_working_inventory()
958
file_id = inv.path2id(relpath)
736
959
for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
737
960
print "%6d %s" % (revno, what)
740
963
class cmd_ls(Command):
741
964
"""List files in a tree.
743
TODO: Take a revision or remote path and list that tree instead.
966
# TODO: Take a revision or remote path and list that tree instead.
746
def run(self, revision=None, verbose=False):
968
takes_options = ['verbose', 'revision',
969
Option('non-recursive',
970
help='don\'t recurse into sub-directories'),
972
help='Print all paths from the root of the branch.'),
973
Option('unknown', help='Print unknown files'),
974
Option('versioned', help='Print versioned files'),
975
Option('ignored', help='Print ignored files'),
977
Option('null', help='Null separate the files'),
980
def run(self, revision=None, verbose=False,
981
non_recursive=False, from_root=False,
982
unknown=False, versioned=False, ignored=False,
986
raise BzrCommandError('Cannot set both --verbose and --null')
987
all = not (unknown or versioned or ignored)
989
selection = {'I':ignored, '?':unknown, 'V':versioned}
991
b, relpath = Branch.open_containing('.')
748
996
if revision == None:
749
997
tree = b.working_tree()
751
tree = b.revision_tree(b.lookup_revision(revision))
753
for fp, fc, kind, fid in tree.list_files():
755
if kind == 'directory':
999
tree = b.revision_tree(revision[0].in_history(b).rev_id)
1000
for fp, fc, kind, fid, entry in tree.list_files():
1001
if fp.startswith(relpath):
1002
fp = fp[len(relpath):]
1003
if non_recursive and '/' in fp:
1005
if not all and not selection[fc]:
1008
kindch = entry.kind_character()
1009
print '%-8s %s%s' % (fc, fp, kindch)
1011
sys.stdout.write(fp)
1012
sys.stdout.write('\0')
762
print '%-8s %s%s' % (fc, fp, kindch)
768
1019
class cmd_unknowns(Command):
769
1020
"""List unknown files."""
771
1023
from bzrlib.osutils import quotefn
772
for f in find_branch('.').unknowns():
1024
for f in Branch.open_containing('.')[0].unknowns():
773
1025
print quotefn(f)
874
1130
is found exports to a directory (equivalent to --format=dir).
876
1132
Root may be the top directory for tar, tgz and tbz2 formats. If none
877
is given, the top directory will be the root name of the file."""
878
# TODO: list known exporters
1133
is given, the top directory will be the root name of the file.
1135
Note: export of tree with non-ascii filenames to zip is not supported.
1137
Supported formats Autodetected by extension
1138
----------------- -------------------------
1141
tbz2 .tar.bz2, .tbz2
879
1145
takes_args = ['dest']
880
1146
takes_options = ['revision', 'format', 'root']
881
1147
def run(self, dest, revision=None, format=None, root=None):
1149
from bzrlib.export import export
1150
b = Branch.open_containing('.')[0]
884
1151
if revision is None:
885
rev_id = b.last_patch()
1152
rev_id = b.last_revision()
887
1154
if len(revision) != 1:
888
1155
raise BzrError('bzr export --revision takes exactly 1 argument')
889
revno, rev_id = b.get_revision_info(revision[0])
1156
rev_id = revision[0].in_history(b).rev_id
890
1157
t = b.revision_tree(rev_id)
891
root, ext = os.path.splitext(dest)
895
elif ext in (".gz", ".tgz"):
897
elif ext in (".bz2", ".tbz2"):
901
t.export(dest, format, root)
1159
export(t, dest, format, root)
1160
except errors.NoSuchExportFormat, e:
1161
raise BzrCommandError('Unsupported export format: %s' % e.format)
904
1164
class cmd_cat(Command):
936
1198
A selected-file commit may fail in some cases where the committed
937
1199
tree would be invalid, such as trying to commit a file in a
938
1200
newly-added directory that is not itself committed.
940
TODO: Run hooks on tree to-be-committed, and after commit.
942
TODO: Strict commit that fails if there are unknown or deleted files.
1202
# TODO: Run hooks on tree to-be-committed, and after commit.
1204
# TODO: Strict commit that fails if there are deleted files.
1205
# (what does "deleted files" mean ??)
1207
# TODO: Give better message for -s, --summary, used by tla people
1209
# XXX: verbose currently does nothing
944
1211
takes_args = ['selected*']
945
takes_options = ['message', 'file', 'verbose', 'unchanged']
1212
takes_options = ['message', 'verbose',
1214
help='commit even if nothing has changed'),
1215
Option('file', type=str,
1217
help='file containing commit message'),
1219
help="refuse to commit if there are unknown "
1220
"files in the working tree."),
946
1222
aliases = ['ci', 'checkin']
948
# TODO: Give better message for -s, --summary, used by tla people
950
1224
def run(self, message=None, file=None, verbose=True, selected_list=None,
952
from bzrlib.errors import PointlessCommit
1225
unchanged=False, strict=False):
1226
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
953
1228
from bzrlib.msgeditor import edit_commit_message
954
1229
from bzrlib.status import show_status
955
1230
from cStringIO import StringIO
959
selected_list = [b.relpath(s) for s in selected_list]
961
if not message and not file:
1232
b, selected_list = branch_files(selected_list)
1233
if message is None and not file:
962
1234
catcher = StringIO()
963
1235
show_status(b, specific_files=selected_list,
964
1236
to_file=catcher)
965
1237
message = edit_commit_message(catcher.getvalue())
967
1239
if message is None:
968
1240
raise BzrCommandError("please specify a commit message"
969
1241
" with either --message or --file")
975
1247
message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1250
raise BzrCommandError("empty commit message specified")
978
b.commit(message, verbose=verbose,
979
specific_files=selected_list,
980
allow_pointless=unchanged)
1253
b.working_tree().commit(message, specific_files=selected_list,
1254
allow_pointless=unchanged, strict=strict)
981
1255
except PointlessCommit:
982
1256
# FIXME: This should really happen before the file is read in;
983
1257
# perhaps prepare the commit; get the message; then actually commit
984
1258
raise BzrCommandError("no changes to commit",
985
1259
["use --unchanged to commit anyhow"])
1260
except ConflictsInTree:
1261
raise BzrCommandError("Conflicts detected in working tree. "
1262
'Use "bzr conflicts" to list, "bzr resolve FILE" to resolve.')
1263
except StrictCommitFailed:
1264
raise BzrCommandError("Commit refused because there are unknown "
1265
"files in the working tree.")
1266
except errors.CannotInstallRevisions, e:
1267
raise BzrCommandError(e.msg)
988
1270
class cmd_check(Command):
1028
1307
The check command or bzr developers may sometimes advise you to run
1310
This version of this command upgrades from the full-text storage
1311
used by bzr 0.0.8 and earlier to the weave format (v5).
1031
1313
takes_args = ['dir?']
1033
1315
def run(self, dir='.'):
1034
1316
from bzrlib.upgrade import upgrade
1035
upgrade(find_branch(dir))
1039
1320
class cmd_whoami(Command):
1040
1321
"""Show bzr user id."""
1041
1322
takes_options = ['email']
1043
1325
def run(self, email=False):
1045
b = bzrlib.branch.find_branch('.')
1327
b = bzrlib.branch.Branch.open_containing('.')[0]
1328
config = bzrlib.config.BranchConfig(b)
1329
except NotBranchError:
1330
config = bzrlib.config.GlobalConfig()
1050
print bzrlib.osutils.user_email(b)
1052
print bzrlib.osutils.username(b)
1333
print config.user_email()
1335
print config.username()
1337
class cmd_nick(Command):
1339
Print or set the branch nickname.
1340
If unset, the tree root directory name is used as the nickname
1341
To print the current nickname, execute with no argument.
1343
takes_args = ['nickname?']
1344
def run(self, nickname=None):
1345
branch = Branch.open_containing('.')[0]
1346
if nickname is None:
1347
self.printme(branch)
1349
branch.nick = nickname
1352
def printme(self, branch):
1055
1355
class cmd_selftest(Command):
1056
"""Run internal test suite"""
1356
"""Run internal test suite.
1358
This creates temporary test directories in the working directory,
1359
but not existing data is affected. These directories are deleted
1360
if the tests pass, or left behind to help in debugging if they
1361
fail and --keep-output is specified.
1363
If arguments are given, they are regular expressions that say
1364
which tests should run.
1366
# TODO: --list should give a list of all available tests
1058
takes_options = ['verbose', 'pattern']
1059
def run(self, verbose=False, pattern=".*"):
1368
takes_args = ['testspecs*']
1369
takes_options = ['verbose',
1370
Option('one', help='stop when one test fails'),
1371
Option('keep-output',
1372
help='keep output directories when tests fail')
1375
def run(self, testspecs_list=None, verbose=False, one=False,
1060
1377
import bzrlib.ui
1061
1378
from bzrlib.selftest import selftest
1062
1379
# we don't want progress meters from the tests to go to the
1093
1417
class cmd_version(Command):
1094
1418
"""Show version of bzr."""
1098
1423
class cmd_rocks(Command):
1099
1424
"""Statement of optimism."""
1102
1428
print "it sure does!"
1105
1431
class cmd_find_merge_base(Command):
1106
1432
"""Find and print a base revision for merging two branches.
1108
TODO: Options to specify revisions on either side, as if
1109
merging only part of the history.
1434
# TODO: Options to specify revisions on either side, as if
1435
# merging only part of the history.
1111
1436
takes_args = ['branch', 'other']
1114
1440
def run(self, branch, other):
1115
1441
from bzrlib.revision import common_ancestor, MultipleRevisionSources
1117
branch1 = find_branch(branch)
1118
branch2 = find_branch(other)
1443
branch1 = Branch.open_containing(branch)[0]
1444
branch2 = Branch.open_containing(other)[0]
1120
1446
history_1 = branch1.revision_history()
1121
1447
history_2 = branch2.revision_history()
1123
last1 = branch1.last_patch()
1124
last2 = branch2.last_patch()
1449
last1 = branch1.last_revision()
1450
last2 = branch2.last_revision()
1126
1452
source = MultipleRevisionSources(branch1, branch2)
1170
1496
--force is given.
1172
1498
takes_args = ['branch?']
1173
takes_options = ['revision', 'force', 'merge-type']
1499
takes_options = ['revision', 'force', 'merge-type', 'reprocess',
1500
Option('show-base', help="Show base revision text in "
1175
def run(self, branch='.', revision=None, force=False,
1503
def run(self, branch=None, revision=None, force=False, merge_type=None,
1504
show_base=False, reprocess=False):
1177
1505
from bzrlib.merge import merge
1178
1506
from bzrlib.merge_core import ApplyMerge3
1179
1507
if merge_type is None:
1180
1508
merge_type = ApplyMerge3
1510
branch = Branch.open_containing('.')[0].get_parent()
1512
raise BzrCommandError("No merge location known or specified.")
1514
print "Using saved location: %s" % branch
1182
1515
if revision is None or len(revision) < 1:
1183
1516
base = [None, None]
1184
1517
other = [branch, -1]
1186
1519
if len(revision) == 1:
1187
other = [branch, revision[0]]
1188
1520
base = [None, None]
1521
other_branch = Branch.open_containing(branch)[0]
1522
revno = revision[0].in_history(other_branch).revno
1523
other = [branch, revno]
1190
1525
assert len(revision) == 2
1191
1526
if None in revision:
1192
1527
raise BzrCommandError(
1193
1528
"Merge doesn't permit that revision specifier.")
1194
base = [branch, revision[0]]
1195
other = [branch, revision[1]]
1529
b = Branch.open_containing(branch)[0]
1531
base = [branch, revision[0].in_history(b).revno]
1532
other = [branch, revision[1].in_history(b).revno]
1198
merge(other, base, check_clean=(not force), merge_type=merge_type)
1535
conflict_count = merge(other, base, check_clean=(not force),
1536
merge_type=merge_type, reprocess=reprocess,
1537
show_base=show_base)
1538
if conflict_count != 0:
1199
1542
except bzrlib.errors.AmbiguousBase, e:
1200
1543
m = ("sorry, bzr can't determine the right merge base yet\n"
1201
1544
"candidates are:\n "
1552
class cmd_remerge(Command):
1555
takes_args = ['file*']
1556
takes_options = ['merge-type', 'reprocess',
1557
Option('show-base', help="Show base revision text in "
1560
def run(self, file_list=None, merge_type=None, show_base=False,
1562
from bzrlib.merge import merge_inner, transform_tree
1563
from bzrlib.merge_core import ApplyMerge3
1564
if merge_type is None:
1565
merge_type = ApplyMerge3
1566
b, file_list = branch_files(file_list)
1569
pending_merges = b.working_tree().pending_merges()
1570
if len(pending_merges) != 1:
1571
raise BzrCommandError("Sorry, remerge only works after normal"
1572
+ " merges. Not cherrypicking or"
1574
this_tree = b.working_tree()
1575
base_revision = common_ancestor(b.last_revision(),
1576
pending_merges[0], b)
1577
base_tree = b.revision_tree(base_revision)
1578
other_tree = b.revision_tree(pending_merges[0])
1579
interesting_ids = None
1580
if file_list is not None:
1581
interesting_ids = set()
1582
for filename in file_list:
1583
file_id = this_tree.path2id(filename)
1584
interesting_ids.add(file_id)
1585
if this_tree.kind(file_id) != "directory":
1588
for name, ie in this_tree.inventory.iter_entries(file_id):
1589
interesting_ids.add(ie.file_id)
1590
transform_tree(this_tree, b.basis_tree(), interesting_ids)
1591
if file_list is None:
1592
restore_files = list(this_tree.iter_conflicts())
1594
restore_files = file_list
1595
for filename in restore_files:
1597
restore(this_tree.abspath(filename))
1598
except NotConflicted:
1600
conflicts = merge_inner(b, other_tree, base_tree,
1601
interesting_ids = interesting_ids,
1602
other_rev_id=pending_merges[0],
1603
merge_type=merge_type,
1604
show_base=show_base,
1605
reprocess=reprocess)
1209
1613
class cmd_revert(Command):
1210
1614
"""Reverse all changes since the last commit.
1268
1673
aliases = ['s-c']
1271
1677
def run(self, context=None):
1272
1678
import shellcomplete
1273
1679
shellcomplete.shellcomplete(context)
1682
class cmd_fetch(Command):
1683
"""Copy in history from another branch but don't merge it.
1685
This is an internal method used for pull and merge."""
1687
takes_args = ['from_branch', 'to_branch']
1688
def run(self, from_branch, to_branch):
1689
from bzrlib.fetch import Fetcher
1690
from bzrlib.branch import Branch
1691
from_b = Branch.open(from_branch)
1692
to_b = Branch.open(to_branch)
1697
Fetcher(to_b, from_b)
1276
1704
class cmd_missing(Command):
1277
1705
"""What is missing in this branch relative to other branch.
1707
# TODO: rewrite this in terms of ancestry so that it shows only
1279
1710
takes_args = ['remote?']
1280
1711
aliases = ['mis', 'miss']
1281
1712
# We don't have to add quiet to the list, because
1282
1713
# unknown options are parsed as booleans
1283
1714
takes_options = ['verbose', 'quiet']
1285
1717
def run(self, remote=None, verbose=False, quiet=False):
1286
1718
from bzrlib.errors import BzrCommandError
1287
1719
from bzrlib.missing import show_missing
1326
1758
print '\t', d.split('\n')[0]
1761
class cmd_testament(Command):
1762
"""Show testament (signing-form) of a revision."""
1763
takes_options = ['revision', 'long']
1764
takes_args = ['branch?']
1766
def run(self, branch='.', revision=None, long=False):
1767
from bzrlib.testament import Testament
1768
b = Branch.open_containing(branch)[0]
1771
if revision is None:
1772
rev_id = b.last_revision()
1774
rev_id = revision[0].in_history(b).rev_id
1775
t = Testament.from_revision(b, rev_id)
1777
sys.stdout.writelines(t.as_text_lines())
1779
sys.stdout.write(t.as_short_text())
1784
class cmd_annotate(Command):
1785
"""Show the origin of each line in a file.
1787
This prints out the given file with an annotation on the left side
1788
indicating which revision, author and date introduced the change.
1790
If the origin is the same for a run of consecutive lines, it is
1791
shown only at the top, unless the --all option is given.
1793
# TODO: annotate directories; showing when each file was last changed
1794
# TODO: annotate a previous version of a file
1795
# TODO: if the working copy is modified, show annotations on that
1796
# with new uncommitted lines marked
1797
aliases = ['blame', 'praise']
1798
takes_args = ['filename']
1799
takes_options = [Option('all', help='show annotations on all lines'),
1800
Option('long', help='show date in annotations'),
1804
def run(self, filename, all=False, long=False):
1805
from bzrlib.annotate import annotate_file
1806
b, relpath = Branch.open_containing(filename)
1809
tree = WorkingTree(b.base, b)
1810
tree = b.revision_tree(b.last_revision())
1811
file_id = tree.inventory.path2id(relpath)
1812
file_version = tree.inventory[file_id].revision
1813
annotate_file(b, file_version, file_id, long, all, sys.stdout)
1818
class cmd_re_sign(Command):
1819
"""Create a digital signature for an existing revision."""
1820
# TODO be able to replace existing ones.
1822
hidden = True # is this right ?
1823
takes_args = ['revision_id?']
1824
takes_options = ['revision']
1826
def run(self, revision_id=None, revision=None):
1827
import bzrlib.config as config
1828
import bzrlib.gpg as gpg
1829
if revision_id is not None and revision is not None:
1830
raise BzrCommandError('You can only supply one of revision_id or --revision')
1831
if revision_id is None and revision is None:
1832
raise BzrCommandError('You must supply either --revision or a revision_id')
1833
b = Branch.open_containing('.')[0]
1834
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1835
if revision_id is not None:
1836
b.sign_revision(revision_id, gpg_strategy)
1837
elif revision is not None:
1838
if len(revision) == 1:
1839
revno, rev_id = revision[0].in_history(b)
1840
b.sign_revision(rev_id, gpg_strategy)
1841
elif len(revision) == 2:
1842
# are they both on rh- if so we can walk between them
1843
# might be nice to have a range helper for arbitrary
1844
# revision paths. hmm.
1845
from_revno, from_revid = revision[0].in_history(b)
1846
to_revno, to_revid = revision[1].in_history(b)
1847
if to_revid is None:
1848
to_revno = b.revno()
1849
if from_revno is None or to_revno is None:
1850
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1851
for revno in range(from_revno, to_revno + 1):
1852
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1854
raise BzrCommandError('Please supply either one revision, or a range.')
1856
class cmd_bind(Command):
1857
"""Bind the current branch to its parent.
1859
After binding, commits must succeed on the parent branch
1860
before they can be done on the local one.
1863
takes_args = ['location?']
1866
def run(self, location=None):
1867
b, relpath = Branch.open_containing('.')
1868
if location is None:
1869
location = b.get_bound_location()
1870
if location is None:
1871
location = b.get_parent()
1872
if location is None:
1873
raise BzrCommandError('Branch has no parent,'
1874
' you must supply a bind location.')
1875
b_other = Branch.open(location)
1878
except DivergedBranches:
1879
raise BzrCommandError('These branches have diverged.'
1880
' Try merging, and then bind again.')
1882
class cmd_unbind(Command):
1883
"""Bind the current branch to its parent.
1885
After unbinding, the local branch is considered independent.
1892
b, relpath = Branch.open_containing('.')
1895
class cmd_update(Command):
1896
"""Update the local tree for checkouts and bound branches.
1899
br_local, relpath = Branch.open_containing('.')
1900
# TODO: Check here to see if this is a checkout
1901
bound_loc = br_local.get_bound_location()
1903
raise BzrCommandError('Branch %s is not a checkout or a bound branch,'
1904
' you probably want pull' % br_local.base)
1906
br_bound = Branch.open(bound_loc)
1908
br_local.working_tree().pull(br_bound, overwrite=False)
1909
except DivergedBranches:
1910
raise BzrCommandError("These branches have diverged."
1914
# these get imported and then picked up by the scan for cmd_*
1915
# TODO: Some more consistent way to split command definitions across files;
1916
# we do need to load at least some information about them to know of
1918
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore