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
23
from bzrlib.trace import mutter, note, log_error, warning
24
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
25
from bzrlib.errors import DivergedBranches
26
from bzrlib.branch import Branch
26
27
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, FileInWrongBranch)
34
from bzrlib.option import Option
35
from bzrlib.revisionspec import RevisionSpec
37
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
from bzrlib.workingtree import WorkingTree
41
def tree_files(file_list, default_branch='.'):
43
return internal_tree_files(file_list, default_branch)
44
except FileInWrongBranch, e:
45
raise BzrCommandError("%s is not in the same branch as %s" %
46
(e.path, file_list[0]))
48
def internal_tree_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 WorkingTree.open_containing(default_branch)[0], file_list
56
tree = WorkingTree.open_containing(file_list[0])[0]
58
for filename in file_list:
60
new_list.append(tree.relpath(filename))
61
except NotBranchError:
62
raise FileInWrongBranch(tree.branch, filename)
66
# TODO: Make sure no commands unconditionally use the working directory as a
67
# branch. If a filename argument is used, the first of them should be used to
68
# specify the branch. (Perhaps this can be factored out into some kind of
69
# Argument class, representing a file in a branch, where the first occurrence
28
from bzrlib.commands import Command
72
31
class cmd_status(Command):
73
32
"""Display status summary.
108
67
If a revision argument is given, the status is calculated against
109
68
that revision, or between two revisions if two are provided.
112
# TODO: --no-recurse, --recurse options
70
# XXX: FIXME: bzr status should accept a -r option to show changes
71
# relative to a revision, or between revisions
114
73
takes_args = ['file*']
115
takes_options = ['all', 'show-ids', 'revision']
74
takes_options = ['all', 'show-ids']
116
75
aliases = ['st', 'stat']
119
77
def run(self, all=False, show_ids=False, file_list=None, revision=None):
120
tree, file_list = tree_files(file_list)
79
b = Branch.open_containing(file_list[0])
80
file_list = [b.relpath(x) for x in file_list]
81
# special case: only one path was given and it's the root
86
b = Branch.open_containing('.')
122
88
from bzrlib.status import show_status
123
show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
89
show_status(b, show_unchanged=all, show_ids=show_ids,
124
90
specific_files=file_list, revision=revision)
135
101
takes_args = ['revision_id?']
136
102
takes_options = ['revision']
139
104
def run(self, revision_id=None, revision=None):
105
from bzrlib.revisionspec import RevisionSpec
141
107
if revision_id is not None and revision is not None:
142
108
raise BzrCommandError('You can only supply one of revision_id or --revision')
143
109
if revision_id is None and revision is None:
144
110
raise BzrCommandError('You must supply either --revision or a revision_id')
145
b = WorkingTree.open_containing('.')[0].branch
111
b = Branch.open_containing('.')
146
112
if revision_id is not None:
147
sys.stdout.write(b.get_revision_xml(revision_id))
113
sys.stdout.write(b.get_revision_xml_file(revision_id).read())
148
114
elif revision is not None:
149
115
for rev in revision:
151
117
raise BzrCommandError('You cannot specify a NULL revision.')
152
118
revno, rev_id = rev.in_history(b)
153
sys.stdout.write(b.get_revision_xml(rev_id))
119
sys.stdout.write(b.get_revision_xml_file(rev_id).read())
156
122
class cmd_revno(Command):
157
123
"""Show current revision number.
159
125
This is equal to the number of revisions on this branch."""
162
print Branch.open_containing('.')[0].revno()
127
print Branch.open_containing('.').revno()
165
130
class cmd_revision_info(Command):
245
213
takes_args = ['filename']
249
216
def run(self, filename):
250
tree, relpath = WorkingTree.open_containing(filename)
217
print Branch.open_containing(filename).relpath(filename)
254
221
class cmd_inventory(Command):
255
"""Show inventory of the current working copy or a revision.
257
It is possible to limit the output to a particular entry
258
type using the --kind option. For example; --kind file.
260
takes_options = ['revision', 'show-ids', 'kind']
222
"""Show inventory of the current working copy or a revision."""
223
takes_options = ['revision', 'show-ids']
263
def run(self, revision=None, show_ids=False, kind=None):
264
if kind and kind not in ['file', 'directory', 'symlink']:
265
raise BzrCommandError('invalid kind specified')
266
tree = WorkingTree.open_containing('.')[0]
225
def run(self, revision=None, show_ids=False):
226
b = Branch.open_containing('.')
267
227
if revision is None:
268
inv = tree.read_working_inventory()
228
inv = b.read_working_inventory()
270
230
if len(revision) > 1:
271
231
raise BzrCommandError('bzr inventory --revision takes'
272
232
' exactly one revision identifier')
273
inv = tree.branch.get_revision_inventory(
274
revision[0].in_history(tree.branch).rev_id)
233
inv = b.get_revision_inventory(revision[0].in_history(b).rev_id)
276
235
for path, entry in inv.entries():
277
if kind and kind != entry.kind:
280
237
print '%-50s %s' % (path, entry.file_id)
335
294
def run(self, names_list):
336
295
if len(names_list) < 2:
337
296
raise BzrCommandError("missing file argument")
338
tree, rel_names = tree_files(names_list)
297
b = Branch.open_containing(names_list[0])
299
rel_names = [b.relpath(x) for x in names_list]
340
301
if os.path.isdir(names_list[-1]):
341
302
# move into existing directory
342
for pair in tree.move(rel_names[:-1], rel_names[-1]):
303
for pair in b.move(rel_names[:-1], rel_names[-1]):
343
304
print "%s => %s" % pair
345
306
if len(names_list) != 2:
346
307
raise BzrCommandError('to mv multiple files the destination '
347
308
'must be a versioned directory')
348
tree.rename_one(rel_names[0], rel_names[1])
309
b.rename_one(rel_names[0], rel_names[1])
349
310
print "%s => %s" % (rel_names[0], rel_names[1])
352
315
class cmd_pull(Command):
353
316
"""Pull any changes from another branch into the current one.
355
If there is no default location set, the first pull will set it. After
356
that, you can omit the location to use the default. To change the
357
default, use --remember.
318
If the location is omitted, the last-used location will be used.
319
Both the revision history and the working directory will be
359
322
This command only works on branches that have not diverged. Branches are
360
323
considered diverged if both branches have had commits without first
361
324
pulling from the other.
363
326
If branches have diverged, you can use 'bzr merge' to pull the text changes
364
from one into the other. Once one branch has merged, the other should
365
be able to pull it again.
367
If you want to forget your local changes and just update your branch to
368
match the remote one, use --overwrite.
327
from one into the other.
370
takes_options = ['remember', 'overwrite', 'verbose']
329
takes_options = ['remember']
371
330
takes_args = ['location?']
373
def run(self, location=None, remember=False, overwrite=False, verbose=False):
332
def run(self, location=None, remember=False):
374
333
from bzrlib.merge import merge
375
335
from shutil import rmtree
377
# FIXME: too much stuff is in the command class
378
tree_to = WorkingTree.open_containing('.')[0]
379
stored_loc = tree_to.branch.get_parent()
338
br_to = Branch.open_containing('.')
339
stored_loc = br_to.get_parent()
380
340
if location is None:
381
341
if stored_loc is None:
382
342
raise BzrCommandError("No pull location known or specified.")
384
344
print "Using saved location: %s" % stored_loc
385
345
location = stored_loc
346
cache_root = tempfile.mkdtemp()
386
347
br_from = Branch.open(location)
387
br_to = tree_to.branch
389
old_rh = br_to.revision_history()
390
count = tree_to.pull(br_from, overwrite)
391
except DivergedBranches:
392
# FIXME: Just make DivergedBranches display the right message
394
raise BzrCommandError("These branches have diverged."
396
if br_to.get_parent() is None or remember:
397
br_to.set_parent(location)
398
note('%d revision(s) pulled.', count)
400
new_rh = tree_to.branch.revision_history()
403
from bzrlib.log import show_changed_revisions
404
show_changed_revisions(tree_to.branch, old_rh, new_rh)
407
class cmd_push(Command):
408
"""Push this branch into another branch.
410
The remote branch will not have its working tree populated because this
411
is both expensive, and may not be supported on the remote file system.
413
Some smart servers or protocols *may* put the working tree in place.
415
If there is no default push location set, the first push will set it.
416
After that, you can omit the location to use the default. To change the
417
default, use --remember.
419
This command only works on branches that have not diverged. Branches are
420
considered diverged if the branch being pushed to is not an older version
423
If branches have diverged, you can use 'bzr push --overwrite' to replace
424
the other branch completely.
426
If you want to ensure you have the different changes in the other branch,
427
do a merge (see bzr help merge) from the other branch, and commit that
428
before doing a 'push --overwrite'.
430
takes_options = ['remember', 'overwrite',
431
Option('create-prefix',
432
help='Create the path leading up to the branch '
433
'if it does not already exist')]
434
takes_args = ['location?']
436
def run(self, location=None, remember=False, overwrite=False,
437
create_prefix=False, verbose=False):
438
# FIXME: Way too big! Put this into a function called from the
441
from shutil import rmtree
442
from bzrlib.transport import get_transport
444
tree_from = WorkingTree.open_containing('.')[0]
445
br_from = tree_from.branch
446
stored_loc = tree_from.branch.get_push_location()
448
if stored_loc is None:
449
raise BzrCommandError("No push location known or specified.")
451
print "Using saved location: %s" % stored_loc
452
location = stored_loc
454
br_to = Branch.open(location)
455
except NotBranchError:
457
transport = get_transport(location).clone('..')
458
if not create_prefix:
460
transport.mkdir(transport.relpath(location))
462
raise BzrCommandError("Parent directory of %s "
463
"does not exist." % location)
465
current = transport.base
466
needed = [(transport, transport.relpath(location))]
469
transport, relpath = needed[-1]
470
transport.mkdir(relpath)
473
new_transport = transport.clone('..')
474
needed.append((new_transport,
475
new_transport.relpath(transport.base)))
476
if new_transport.base == transport.base:
477
raise BzrCommandError("Could not creeate "
479
br_to = Branch.initialize(location)
481
old_rh = br_to.revision_history()
482
count = 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)
488
note('%d revision(s) pushed.' % (count,))
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)
350
br_from.setup_caching(cache_root)
351
location = br_from.base
352
old_revno = br_to.revno()
353
old_revision_history = br_to.revision_history()
355
br_to.update_revisions(br_from)
356
except DivergedBranches:
357
raise BzrCommandError("These branches have diverged."
359
new_revision_history = br_to.revision_history()
360
if new_revision_history != old_revision_history:
361
merge(('.', -1), ('.', old_revno), check_clean=False)
362
if stored_loc is None or remember:
363
br_to.set_parent(location)
497
370
class cmd_branch(Command):
736
592
takes_options = ['revision', 'diff-options']
737
593
aliases = ['di', 'dif']
740
595
def run(self, revision=None, file_list=None, diff_options=None):
741
596
from bzrlib.diff import show_diff
743
tree, file_list = internal_tree_files(file_list)
746
except FileInWrongBranch:
747
if len(file_list) != 2:
748
raise BzrCommandError("Files are in different branches")
750
b, file1 = Branch.open_containing(file_list[0])
751
b2, file2 = Branch.open_containing(file_list[1])
752
if file1 != "" or file2 != "":
753
# FIXME diff those two files. rbc 20051123
754
raise BzrCommandError("Files are in different branches")
599
b = Branch.open_containing(file_list[0])
600
file_list = [b.relpath(f) for f in file_list]
601
if file_list == ['']:
602
# just pointing to top-of-tree
605
b = Branch.open_containing('.')
756
607
if revision is not None:
758
raise BzrCommandError("Can't specify -r with two branches")
759
608
if len(revision) == 1:
760
return show_diff(tree.branch, revision[0], specific_files=file_list,
761
external_diff_options=diff_options)
609
show_diff(b, revision[0], specific_files=file_list,
610
external_diff_options=diff_options)
762
611
elif len(revision) == 2:
763
return show_diff(tree.branch, revision[0], specific_files=file_list,
764
external_diff_options=diff_options,
765
revision2=revision[1])
612
show_diff(b, revision[0], specific_files=file_list,
613
external_diff_options=diff_options,
614
revision2=revision[1])
767
616
raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
770
return show_diff(b, None, specific_files=file_list,
771
external_diff_options=diff_options, b2=b2)
773
return show_diff(tree.branch, None, specific_files=file_list,
774
external_diff_options=diff_options)
618
show_diff(b, None, specific_files=file_list,
619
external_diff_options=diff_options)
777
624
class cmd_deleted(Command):
834
680
The root is the nearest enclosing directory with a .bzr control
836
682
takes_args = ['filename?']
838
683
def run(self, filename=None):
839
684
"""Print the branch root."""
840
tree = WorkingTree.open_containing(filename)[0]
685
b = Branch.open_containing(filename)
844
689
class cmd_log(Command):
845
690
"""Show log of this branch.
847
To request a range of logs, you can use the command -r begin..end
848
-r revision requests a specific revision, -r ..end or -r begin.. are
692
To request a range of logs, you can use the command -r begin:end
693
-r revision requests a specific revision, -r :end or -r begin: are
696
--message allows you to give a regular expression, which will be evaluated
697
so that only matching entries will be displayed.
852
700
# TODO: Make --revision support uuid: and hash: [future tag:] notation.
854
702
takes_args = ['filename?']
855
takes_options = [Option('forward',
856
help='show from oldest to newest'),
857
'timezone', 'verbose',
858
'show-ids', 'revision',
859
Option('line', help='format with one line per revision'),
862
help='show revisions whose message matches this regexp',
864
Option('short', help='use moderately short format'),
703
takes_options = ['forward', 'timezone', 'verbose', 'show-ids', 'revision',
704
'long', 'message', 'short',]
867
706
def run(self, filename=None, timezone='original',
968
789
# TODO: Take a revision or remote path and list that tree instead.
970
takes_options = ['verbose', 'revision',
971
Option('non-recursive',
972
help='don\'t recurse into sub-directories'),
974
help='Print all paths from the root of the branch.'),
975
Option('unknown', help='Print unknown files'),
976
Option('versioned', help='Print versioned files'),
977
Option('ignored', help='Print ignored files'),
979
Option('null', help='Null separate the files'),
982
def run(self, revision=None, verbose=False,
983
non_recursive=False, from_root=False,
984
unknown=False, versioned=False, ignored=False,
988
raise BzrCommandError('Cannot set both --verbose and --null')
989
all = not (unknown or versioned or ignored)
991
selection = {'I':ignored, '?':unknown, 'V':versioned}
993
tree, relpath = WorkingTree.open_containing('.')
998
if revision is not None:
999
tree = tree.branch.revision_tree(
1000
revision[0].in_history(tree.branch).rev_id)
791
def run(self, revision=None, verbose=False):
792
b = Branch.open_containing('.')
794
tree = b.working_tree()
796
tree = b.revision_tree(revision.in_history(b).rev_id)
1001
797
for fp, fc, kind, fid, entry in tree.list_files():
1002
if fp.startswith(relpath):
1003
fp = fp[len(relpath):]
1004
if non_recursive and '/' in fp:
1006
if not all and not selection[fc]:
1009
kindch = entry.kind_character()
1010
print '%-8s %s%s' % (fc, fp, kindch)
1012
sys.stdout.write(fp)
1013
sys.stdout.write('\0')
799
kindch = entry.kind_character()
800
print '%-8s %s%s' % (fc, fp, kindch)
1019
806
class cmd_unknowns(Command):
1020
807
"""List unknown files."""
1023
809
from bzrlib.osutils import quotefn
1024
for f in WorkingTree.open_containing('.')[0].unknowns():
810
for f in Branch.open_containing('.').unknowns():
1025
811
print quotefn(f)
1028
815
class cmd_ignore(Command):
1029
816
"""Ignore a command or pattern.
1128
914
is found exports to a directory (equivalent to --format=dir).
1130
916
Root may be the top directory for tar, tgz and tbz2 formats. If none
1131
is given, the top directory will be the root name of the file.
1133
Note: export of tree with non-ascii filenames to zip is not supported.
1135
Supported formats Autodetected by extension
1136
----------------- -------------------------
1139
tbz2 .tar.bz2, .tbz2
917
is given, the top directory will be the root name of the file."""
918
# TODO: list known exporters
1143
919
takes_args = ['dest']
1144
920
takes_options = ['revision', 'format', 'root']
1145
921
def run(self, dest, revision=None, format=None, root=None):
1147
from bzrlib.export import export
1148
tree = WorkingTree.open_containing('.')[0]
923
b = Branch.open_containing('.')
1150
924
if revision is None:
1151
# should be tree.last_revision FIXME
1152
925
rev_id = b.last_revision()
1154
927
if len(revision) != 1:
1155
928
raise BzrError('bzr export --revision takes exactly 1 argument')
1156
929
rev_id = revision[0].in_history(b).rev_id
1157
930
t = b.revision_tree(rev_id)
1159
export(t, dest, format, root)
1160
except errors.NoSuchExportFormat, e:
1161
raise BzrCommandError('Unsupported export format: %s' % e.format)
931
arg_root, ext = os.path.splitext(os.path.basename(dest))
932
if ext in ('.gz', '.bz2'):
933
new_root, new_ext = os.path.splitext(arg_root)
934
if new_ext == '.tar':
942
elif ext in (".tar.gz", ".tgz"):
944
elif ext in (".tar.bz2", ".tbz2"):
948
t.export(dest, format, root)
1164
951
class cmd_cat(Command):
1209
987
# TODO: Run hooks on tree to-be-committed, and after commit.
1211
# TODO: Strict commit that fails if there are deleted files.
1212
# (what does "deleted files" mean ??)
989
# TODO: Strict commit that fails if there are unknown or deleted files.
1214
990
# TODO: Give better message for -s, --summary, used by tla people
1216
992
# XXX: verbose currently does nothing
1218
994
takes_args = ['selected*']
1219
takes_options = ['message', 'verbose',
1221
help='commit even if nothing has changed'),
1222
Option('file', type=str,
1224
help='file containing commit message'),
1226
help="refuse to commit if there are unknown "
1227
"files in the working tree."),
995
takes_options = ['message', 'file', 'verbose', 'unchanged']
1229
996
aliases = ['ci', 'checkin']
1231
998
def run(self, message=None, file=None, verbose=True, selected_list=None,
1232
unchanged=False, strict=False):
1233
from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1000
from bzrlib.errors import PointlessCommit, ConflictsInTree
1235
1001
from bzrlib.msgeditor import edit_commit_message
1236
1002
from bzrlib.status import show_status
1237
1003
from cStringIO import StringIO
1239
tree, selected_list = tree_files(selected_list)
1005
b = Branch.open_containing('.')
1007
selected_list = [b.relpath(s) for s in selected_list]
1240
1010
if message is None and not file:
1241
1011
catcher = StringIO()
1242
show_status(tree.branch, specific_files=selected_list,
1012
show_status(b, specific_files=selected_list,
1243
1013
to_file=catcher)
1244
1014
message = edit_commit_message(catcher.getvalue())
1558
class cmd_remerge(Command):
1561
takes_args = ['file*']
1562
takes_options = ['merge-type', 'reprocess',
1563
Option('show-base', help="Show base revision text in "
1566
def run(self, file_list=None, merge_type=None, show_base=False,
1568
from bzrlib.merge import merge_inner, transform_tree
1569
from bzrlib.merge_core import ApplyMerge3
1570
if merge_type is None:
1571
merge_type = ApplyMerge3
1572
tree, file_list = tree_files(file_list)
1575
pending_merges = tree.pending_merges()
1576
if len(pending_merges) != 1:
1577
raise BzrCommandError("Sorry, remerge only works after normal"
1578
+ " merges. Not cherrypicking or"
1580
base_revision = common_ancestor(tree.branch.last_revision(),
1581
pending_merges[0], tree.branch)
1582
base_tree = tree.branch.revision_tree(base_revision)
1583
other_tree = tree.branch.revision_tree(pending_merges[0])
1584
interesting_ids = None
1585
if file_list is not None:
1586
interesting_ids = set()
1587
for filename in file_list:
1588
file_id = tree.path2id(filename)
1589
interesting_ids.add(file_id)
1590
if tree.kind(file_id) != "directory":
1593
for name, ie in tree.inventory.iter_entries(file_id):
1594
interesting_ids.add(ie.file_id)
1595
transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
1596
if file_list is None:
1597
restore_files = list(tree.iter_conflicts())
1599
restore_files = file_list
1600
for filename in restore_files:
1602
restore(tree.abspath(filename))
1603
except NotConflicted:
1605
conflicts = merge_inner(tree.branch, other_tree, base_tree,
1606
interesting_ids = interesting_ids,
1607
other_rev_id=pending_merges[0],
1608
merge_type=merge_type,
1609
show_base=show_base,
1610
reprocess=reprocess)
1618
1285
class cmd_revert(Command):
1619
1286
"""Reverse all changes since the last commit.
1627
1294
aliases = ['merge-revert']
1629
1296
def run(self, revision=None, no_backup=False, file_list=None):
1630
from bzrlib.merge import merge_inner
1297
from bzrlib.merge import merge
1631
1298
from bzrlib.commands import parse_spec
1632
1300
if file_list is not None:
1633
1301
if len(file_list) == 0:
1634
1302
raise BzrCommandError("No files specified")
1637
1303
if revision is None:
1639
tree = WorkingTree.open_containing('.')[0]
1640
# FIXME should be tree.last_revision
1641
rev_id = tree.branch.last_revision()
1642
1305
elif len(revision) != 1:
1643
1306
raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1645
tree, file_list = tree_files(file_list)
1646
rev_id = revision[0].in_history(tree.branch).rev_id
1647
tree.revert(file_list, tree.branch.revision_tree(rev_id),
1308
b = Branch.open_containing('.')
1309
revno = revision[0].in_history(b).revno
1310
merge(('.', revno), parse_spec('.'),
1313
backup_files=not no_backup,
1314
file_list=file_list)
1316
Branch.open_containing('.').set_pending_merges([])
1651
1319
class cmd_assert_fail(Command):
1716
1375
takes_args = ['remote?']
1717
1376
aliases = ['mis', 'miss']
1718
takes_options = ['verbose']
1377
# We don't have to add quiet to the list, because
1378
# unknown options are parsed as booleans
1379
takes_options = ['verbose', 'quiet']
1721
def run(self, remote=None, verbose=False):
1381
def run(self, remote=None, verbose=False, quiet=False):
1722
1382
from bzrlib.errors import BzrCommandError
1723
1383
from bzrlib.missing import show_missing
1725
if verbose and is_quiet():
1385
if verbose and quiet:
1726
1386
raise BzrCommandError('Cannot pass both quiet and verbose')
1728
tree = WorkingTree.open_containing('.')[0]
1729
parent = tree.branch.get_parent()
1388
b = Branch.open_containing('.')
1389
parent = b.get_parent()
1730
1390
if remote is None:
1731
1391
if parent is None:
1732
1392
raise BzrCommandError("No missing location known or specified.")
1735
1395
print "Using last location: %s" % parent
1736
1396
remote = parent
1737
1397
elif parent is None:
1738
1398
# We only update parent if it did not exist, missing
1739
1399
# should not change the parent
1740
tree.branch.set_parent(remote)
1741
br_remote = Branch.open_containing(remote)[0]
1742
return show_missing(tree.branch, br_remote, verbose=verbose,
1400
b.set_parent(remote)
1401
br_remote = Branch.open_containing(remote)
1402
return show_missing(b, br_remote, verbose=verbose, quiet=quiet)
1746
1405
class cmd_plugins(Command):
1747
1406
"""List plugins"""
1751
1409
import bzrlib.plugin
1752
1410
from inspect import getdoc
1789
1446
class cmd_annotate(Command):
1790
1447
"""Show the origin of each line in a file.
1792
This prints out the given file with an annotation on the left side
1793
indicating which revision, author and date introduced the change.
1795
If the origin is the same for a run of consecutive lines, it is
1796
shown only at the top, unless the --all option is given.
1449
This prints out the given file with an annotation on the
1450
left side indicating which revision, author and date introduced the
1798
1453
# TODO: annotate directories; showing when each file was last changed
1799
1454
# TODO: annotate a previous version of a file
1800
# TODO: if the working copy is modified, show annotations on that
1801
# with new uncommitted lines marked
1802
1455
aliases = ['blame', 'praise']
1803
1456
takes_args = ['filename']
1804
takes_options = [Option('all', help='show annotations on all lines'),
1805
Option('long', help='show date in annotations'),
1809
def run(self, filename, all=False, long=False):
1458
def run(self, filename):
1810
1459
from bzrlib.annotate import annotate_file
1811
tree, relpath = WorkingTree.open_containing(filename)
1812
branch = tree.branch
1460
b = Branch.open_containing(filename)
1815
file_id = tree.inventory.path2id(relpath)
1816
tree = branch.revision_tree(branch.last_revision())
1463
rp = b.relpath(filename)
1464
tree = b.revision_tree(b.last_revision())
1465
file_id = tree.inventory.path2id(rp)
1817
1466
file_version = tree.inventory[file_id].revision
1818
annotate_file(branch, file_version, file_id, long, all, sys.stdout)
1467
annotate_file(b, file_version, file_id, sys.stdout)
1823
class cmd_re_sign(Command):
1824
"""Create a digital signature for an existing revision."""
1825
# TODO be able to replace existing ones.
1827
hidden = True # is this right ?
1828
takes_args = ['revision_id?']
1829
takes_options = ['revision']
1831
def run(self, revision_id=None, revision=None):
1832
import bzrlib.config as config
1833
import bzrlib.gpg as gpg
1834
if revision_id is not None and revision is not None:
1835
raise BzrCommandError('You can only supply one of revision_id or --revision')
1836
if revision_id is None and revision is None:
1837
raise BzrCommandError('You must supply either --revision or a revision_id')
1838
b = WorkingTree.open_containing('.')[0].branch
1839
gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1840
if revision_id is not None:
1841
b.sign_revision(revision_id, gpg_strategy)
1842
elif revision is not None:
1843
if len(revision) == 1:
1844
revno, rev_id = revision[0].in_history(b)
1845
b.sign_revision(rev_id, gpg_strategy)
1846
elif len(revision) == 2:
1847
# are they both on rh- if so we can walk between them
1848
# might be nice to have a range helper for arbitrary
1849
# revision paths. hmm.
1850
from_revno, from_revid = revision[0].in_history(b)
1851
to_revno, to_revid = revision[1].in_history(b)
1852
if to_revid is None:
1853
to_revno = b.revno()
1854
if from_revno is None or to_revno is None:
1855
raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
1856
for revno in range(from_revno, to_revno + 1):
1857
b.sign_revision(b.get_rev_id(revno), gpg_strategy)
1859
raise BzrCommandError('Please supply either one revision, or a range.')
1862
class cmd_uncommit(bzrlib.commands.Command):
1863
"""Remove the last committed revision.
1865
By supplying the --all flag, it will not only remove the entry
1866
from revision_history, but also remove all of the entries in the
1869
--verbose will print out what is being removed.
1870
--dry-run will go through all the motions, but not actually
1873
In the future, uncommit will create a changeset, which can then
1876
takes_options = ['all', 'verbose', 'revision',
1877
Option('dry-run', help='Don\'t actually make changes'),
1878
Option('force', help='Say yes to all questions.')]
1879
takes_args = ['location?']
1882
def run(self, location=None, all=False,
1883
dry_run=False, verbose=False,
1884
revision=None, force=False):
1885
from bzrlib.branch import Branch
1886
from bzrlib.log import log_formatter
1888
from bzrlib.uncommit import uncommit
1890
if location is None:
1892
b, relpath = Branch.open_containing(location)
1894
if revision is None:
1896
rev_id = b.last_revision()
1898
revno, rev_id = revision[0].in_history(b)
1900
print 'No revisions to uncommit.'
1902
for r in range(revno, b.revno()+1):
1903
rev_id = b.get_rev_id(r)
1904
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
1905
lf.show(r, b.get_revision(rev_id), None)
1908
print 'Dry-run, pretending to remove the above revisions.'
1910
val = raw_input('Press <enter> to continue')
1912
print 'The above revision(s) will be removed.'
1914
val = raw_input('Are you sure [y/N]? ')
1915
if val.lower() not in ('y', 'yes'):
1919
uncommit(b, remove_files=all,
1920
dry_run=dry_run, verbose=verbose,
1924
1471
# these get imported and then picked up by the scan for cmd_*
1925
1472
# TODO: Some more consistent way to split command definitions across files;
1926
1473
# we do need to load at least some information about them to know of
1928
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
1475
from bzrlib.conflicts import cmd_resolve, cmd_conflicts