1
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
41
from bzrlib.branch import Branch, BranchReferenceFormat
27
from bzrlib import (bundle, branch, bzrdir, errors, osutils, ui, config,
29
42
from bzrlib.bundle import read_bundle_from_url
30
43
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
44
from bzrlib.conflicts import ConflictList
31
45
from bzrlib.commands import Command, display_command
32
46
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError,
33
47
NotBranchError, DivergedBranches, NotConflicted,
40
54
from bzrlib.revisionspec import RevisionSpec
41
55
from bzrlib.trace import mutter, note, log_error, warning, is_quiet, info
42
56
from bzrlib.transport.local import LocalTransport
43
import bzrlib.urlutils as urlutils
44
57
from bzrlib.workingtree import WorkingTree
373
386
encoding_type = 'replace'
375
388
def run(self, names_list):
389
if names_list is None:
376
392
if len(names_list) < 2:
377
393
raise BzrCommandError("missing file argument")
378
394
tree, rel_names = tree_files(names_list)
511
527
create_prefix=False, verbose=False):
512
528
# FIXME: Way too big! Put this into a function called from the
514
from bzrlib.transport import get_transport
516
531
br_from = Branch.open_containing('.')[0]
517
532
stored_loc = br_from.get_push_location()
524
539
self.outf.write("Using saved location: %s\n" % display_url)
525
540
location = stored_loc
527
transport = get_transport(location)
528
location_url = transport.base
542
to_transport = transport.get_transport(location)
543
location_url = to_transport.base
533
548
br_to = dir_to.open_branch()
534
549
except NotBranchError:
535
550
# create a branch.
536
transport = transport.clone('..')
551
to_transport = to_transport.clone('..')
537
552
if not create_prefix:
539
relurl = transport.relpath(location_url)
554
relurl = to_transport.relpath(location_url)
540
555
mutter('creating directory %s => %s', location_url, relurl)
541
transport.mkdir(relurl)
556
to_transport.mkdir(relurl)
542
557
except NoSuchFile:
543
558
raise BzrCommandError("Parent directory of %s "
544
559
"does not exist." % location)
546
current = transport.base
547
needed = [(transport, transport.relpath(location_url))]
561
current = to_transport.base
562
needed = [(to_transport, to_transport.relpath(location_url))]
550
transport, relpath = needed[-1]
551
transport.mkdir(relpath)
565
to_transport, relpath = needed[-1]
566
to_transport.mkdir(relpath)
553
568
except NoSuchFile:
554
new_transport = transport.clone('..')
569
new_transport = to_transport.clone('..')
555
570
needed.append((new_transport,
556
new_transport.relpath(transport.base)))
557
if new_transport.base == transport.base:
571
new_transport.relpath(to_transport.base)))
572
if new_transport.base == to_transport.base:
558
573
raise BzrCommandError("Could not create "
560
575
dir_to = br_from.bzrdir.clone(location_url,
613
628
aliases = ['get', 'clone']
615
630
def run(self, from_location, to_location=None, revision=None, basis=None):
616
from bzrlib.transport import get_transport
617
631
if revision is None:
618
632
revision = [None]
619
633
elif len(revision) > 1:
748
762
old_format = bzrdir.BzrDirFormat.get_default_format()
749
763
bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
752
checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
753
branch.BranchReferenceFormat().initialize(checkout, source)
755
checkout_branch = bzrdir.BzrDir.create_branch_convenience(
756
to_location, force_new_tree=False)
757
checkout = checkout_branch.bzrdir
758
checkout_branch.bind(source)
759
if revision_id is not None:
760
rh = checkout_branch.revision_history()
761
checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
762
checkout.create_workingtree(revision_id)
765
source.create_checkout(to_location, revision_id, lightweight)
764
767
bzrdir.BzrDirFormat.set_default_format(old_format)
795
798
'bzr revert' instead of 'bzr commit' after the update.
797
800
takes_args = ['dir?']
799
803
def run(self, dir='.'):
800
804
tree = WorkingTree.open_containing(dir)[0]
801
805
tree.lock_write()
806
existing_pending_merges = tree.pending_merges()
803
if tree.last_revision() == tree.branch.last_revision():
808
last_rev = tree.last_revision()
809
if last_rev == tree.branch.last_revision():
804
810
# may be up to date, check master too.
805
811
master = tree.branch.get_master_branch()
806
if master is None or master.last_revision == tree.last_revision():
807
note("Tree is up to date.")
812
if master is None or last_rev == master.last_revision():
813
revno = tree.branch.revision_id_to_revno(last_rev)
814
note("Tree is up to date at revision %d." % (revno,))
809
816
conflicts = tree.update()
810
note('Updated to revision %d.' %
811
(tree.branch.revision_id_to_revno(tree.last_revision()),))
817
revno = tree.branch.revision_id_to_revno(tree.last_revision())
818
note('Updated to revision %d.' % (revno,))
819
if tree.pending_merges() != existing_pending_merges:
820
note('Your local commits will now show as pending merges with '
821
"'bzr status', and can be committed with 'bzr commit'.")
812
822
if conflicts != 0:
859
869
raise BzrCommandError('Specify one or more files to remove, or'
862
from bzrlib.delta import compare_trees
863
added = [compare_trees(tree.basis_tree(), tree,
864
specific_files=file_list).added]
865
file_list = sorted([f[0] for f in added[0]], reverse=True)
872
added = tree.changes_from(tree.basis_tree(),
873
specific_files=file_list).added
874
file_list = sorted([f[0] for f in added], reverse=True)
866
875
if len(file_list) == 0:
867
876
raise BzrCommandError('No matching files.')
868
877
tree.remove(file_list, verbose=verbose, to_file=self.outf)
1009
1018
format = get_format_type('default')
1010
1019
if location is None:
1011
1020
location = u'.'
1013
# The path has to exist to initialize a
1014
# branch inside of it.
1015
# Just using os.mkdir, since I don't
1016
# believe that we want to create a bunch of
1017
# locations if the user supplies an extended path
1018
if not os.path.exists(location):
1022
to_transport = transport.get_transport(location)
1024
# The path has to exist to initialize a
1025
# branch inside of it.
1026
# Just using os.mkdir, since I don't
1027
# believe that we want to create a bunch of
1028
# locations if the user supplies an extended path
1029
# TODO: create-prefix
1031
to_transport.mkdir('.')
1032
except errors.FileExists:
1021
1036
existing_bzrdir = bzrdir.BzrDir.open(location)
1022
1037
except NotBranchError:
1024
1039
bzrdir.BzrDir.create_branch_convenience(location, format=format)
1026
1041
if existing_bzrdir.has_branch():
1027
if existing_bzrdir.has_workingtree():
1028
raise errors.AlreadyBranchError(location)
1030
raise errors.BranchExistsWithoutWorkingTree(location)
1042
if (isinstance(to_transport, LocalTransport)
1043
and not existing_bzrdir.has_workingtree()):
1044
raise errors.BranchExistsWithoutWorkingTree(location)
1045
raise errors.AlreadyBranchError(location)
1032
1047
existing_bzrdir.create_branch()
1033
1048
existing_bzrdir.create_workingtree()
1059
1074
' a working tree')]
1060
1075
aliases = ["init-repo"]
1061
1076
def run(self, location, format=None, trees=False):
1062
from bzrlib.transport import get_transport
1063
1077
if format is None:
1064
1078
format = get_format_type('default')
1065
transport = get_transport(location)
1066
if not transport.has('.'):
1068
newdir = format.initialize_on_transport(transport)
1080
if location is None:
1083
to_transport = transport.get_transport(location)
1085
to_transport.mkdir('.')
1086
except errors.FileExists:
1089
newdir = format.initialize_on_transport(to_transport)
1069
1090
repo = newdir.create_repository(shared=True)
1070
1091
repo.set_make_working_trees(trees)
1073
1094
class cmd_diff(Command):
1074
"""Show differences in working tree.
1095
"""Show differences in the working tree or between revisions.
1076
1097
If files are listed, only the changes in those files are listed.
1077
1098
Otherwise, all changes for the tree are listed.
1105
Shows the difference in the working tree versus the last commit
1107
Difference between the working tree and revision 1
1085
1108
bzr diff -r1..2
1109
Difference between revision 2 and revision 1
1086
1110
bzr diff --diff-prefix old/:new/
1111
Same as 'bzr diff' but prefix paths with old/ and new/
1087
1112
bzr diff bzr.mine bzr.dev
1113
Show the differences between the two working trees
1115
Show just the differences for 'foo.c'
1090
1117
# TODO: Option to use external diff command; could be GNU diff, wdiff,
1091
1118
# or a graphical diff.
1135
1162
# FIXME diff those two files. rbc 20051123
1136
1163
raise BzrCommandError("Files are in different branches")
1137
1164
file_list = None
1165
except NotBranchError:
1166
if (revision is not None and len(revision) == 2
1167
and not revision[0].needs_branch()
1168
and not revision[1].needs_branch()):
1169
# If both revision specs include a branch, we can
1170
# diff them without needing a local working tree
1171
tree1, tree2 = None, None
1138
1174
if revision is not None:
1139
1175
if tree2 is not None:
1140
1176
raise BzrCommandError("Can't specify -r with two branches")
1189
1225
@display_command
1191
from bzrlib.delta import compare_trees
1193
1227
tree = WorkingTree.open_containing(u'.')[0]
1194
td = compare_trees(tree.basis_tree(), tree)
1228
td = tree.changes_from(tree.basis_tree())
1196
1229
for path, id, kind, text_modified, meta_modified in td.modified:
1197
1230
self.outf.write(path + '\n')
1453
1486
bzr ignore '*.class'
1455
1488
# TODO: Complain if the filename is absolute
1456
takes_args = ['name_pattern']
1489
takes_args = ['name_pattern?']
1491
Option('old-default-rules',
1492
help='Out the ignore rules bzr < 0.9 always used.')
1458
def run(self, name_pattern):
1495
def run(self, name_pattern=None, old_default_rules=None):
1459
1496
from bzrlib.atomicfile import AtomicFile
1497
if old_default_rules is not None:
1498
# dump the rules and exit
1499
for pattern in ignores.OLD_DEFAULTS:
1502
if name_pattern is None:
1503
raise BzrCommandError("ignore requires a NAME_PATTERN")
1462
1504
tree, relpath = WorkingTree.open_containing(u'.')
1463
1505
ifn = tree.abspath('.bzrignore')
1465
1506
if os.path.exists(ifn):
1466
1507
f = open(ifn, 'rt')
1552
1593
takes_args = ['dest']
1553
1594
takes_options = ['revision', 'format', 'root']
1554
1595
def run(self, dest, revision=None, format=None, root=None):
1556
1596
from bzrlib.export import export
1557
1597
tree = WorkingTree.open_containing(u'.')[0]
1558
1598
b = tree.branch
1708
1748
raise BzrCommandError("Commit refused because there are unknown "
1709
1749
"files in the working tree.")
1710
1750
except errors.BoundBranchOutOfDate, e:
1711
raise BzrCommandError(str(e)
1712
+ ' Either unbind, update, or'
1713
' pass --local to commit.')
1751
raise BzrCommandError(str(e) + "\n"
1752
'To commit to master branch, run update and then commit.\n'
1753
'You can also pass --local to commit to continue working '
1716
1756
class cmd_check(Command):
1717
1757
"""Validate consistency of branch history.
1779
1819
class cmd_whoami(Command):
1780
"""Show bzr user id."""
1781
takes_options = ['email']
1820
"""Show or set bzr user id.
1824
bzr whoami 'Frank Chu <fchu@example.com>'
1826
takes_options = [ Option('email',
1827
help='display email address only'),
1829
help='set identity for the current branch instead of '
1832
takes_args = ['name?']
1833
encoding_type = 'replace'
1783
1835
@display_command
1784
def run(self, email=False):
1836
def run(self, email=False, branch=False, name=None):
1838
# use branch if we're inside one; otherwise global config
1840
c = Branch.open_containing('.')[0].get_config()
1841
except NotBranchError:
1842
c = config.GlobalConfig()
1844
self.outf.write(c.user_email() + '\n')
1846
self.outf.write(c.username() + '\n')
1849
# display a warning if an email address isn't included in the given name.
1786
c = WorkingTree.open_containing(u'.')[0].branch.get_config()
1787
except NotBranchError:
1851
config.extract_email_address(name)
1853
warning('"%s" does not seem to contain an email address. '
1854
'This is allowed, but not recommended.', name)
1856
# use global config unless --branch given
1858
c = Branch.open_containing('.')[0].get_config()
1788
1860
c = config.GlobalConfig()
1790
print c.user_email()
1861
c.set_user_option('email', name)
1795
1864
class cmd_nick(Command):
1864
1933
Option('lsprof-timed',
1865
1934
help='generate lsprof output for benchmarked'
1866
1935
' sections of code.'),
1936
Option('cache-dir', type=str,
1937
help='a directory to cache intermediate'
1938
' benchmark steps'),
1869
1941
def run(self, testspecs_list=None, verbose=None, one=False,
1870
1942
keep_output=False, transport=None, benchmark=None,
1943
lsprof_timed=None, cache_dir=None):
1872
1944
import bzrlib.ui
1873
1945
from bzrlib.tests import selftest
1874
1946
import bzrlib.benchmarks as benchmarks
1947
from bzrlib.benchmarks import tree_creator
1949
if cache_dir is not None:
1950
tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
1875
1951
# we don't want progress meters from the tests to go to the
1876
1952
# real output; and we don't want log messages cluttering up
1877
1953
# the real logs.
1963
2039
class cmd_version(Command):
1964
2040
"""Show version of bzr."""
1965
2042
@display_command
1969
2047
class cmd_rocks(Command):
1970
2048
"""Statement of optimism."""
1972
2052
@display_command
1974
2054
print "it sure does!"
1977
2057
class cmd_find_merge_base(Command):
1978
"""Find and print a base revision for merging two branches.
2058
"""Find and print a base revision for merging two branches."""
1980
2059
# TODO: Options to specify revisions on either side, as if
1981
2060
# merging only part of the history.
1982
2061
takes_args = ['branch', 'other']
2047
2126
takes_args = ['branch?']
2048
2127
takes_options = ['revision', 'force', 'merge-type', 'reprocess', 'remember',
2049
2128
Option('show-base', help="Show base revision text in "
2130
Option('uncommitted', help='Apply uncommitted changes'
2131
' from a working copy, instead of branch changes')]
2052
2133
def help(self):
2053
2134
from merge import merge_type_help
2055
2136
return getdoc(self) + '\n' + merge_type_help()
2057
2138
def run(self, branch=None, revision=None, force=False, merge_type=None,
2058
show_base=False, reprocess=False, remember=False):
2139
show_base=False, reprocess=False, remember=False,
2059
2141
if merge_type is None:
2060
2142
merge_type = Merge3Merger
2077
2159
branch = self._get_remembered_parent(tree, branch, 'Merging from')
2079
2161
if revision is None or len(revision) < 1:
2081
other = [branch, -1]
2164
other = [branch, None]
2167
other = [branch, -1]
2082
2168
other_branch, path = Branch.open_containing(branch)
2171
raise BzrCommandError('Cannot use --uncommitted and --revision'
2172
' at the same time.')
2084
2173
if len(revision) == 1:
2085
2174
base = [None, None]
2086
2175
other_branch, path = Branch.open_containing(branch)
2185
2274
pending_merges = tree.pending_merges()
2186
2275
if len(pending_merges) != 1:
2187
2276
raise BzrCommandError("Sorry, remerge only works after normal"
2188
+ " merges. Not cherrypicking or"
2277
" merges. Not cherrypicking or"
2190
2279
repository = tree.branch.repository
2191
2280
base_revision = common_ancestor(tree.branch.last_revision(),
2192
2281
pending_merges[0], repository)
2193
2282
base_tree = repository.revision_tree(base_revision)
2194
2283
other_tree = repository.revision_tree(pending_merges[0])
2195
2284
interesting_ids = None
2286
conflicts = tree.conflicts()
2196
2287
if file_list is not None:
2197
2288
interesting_ids = set()
2198
2289
for filename in file_list:
2206
2297
for name, ie in tree.inventory.iter_entries(file_id):
2207
2298
interesting_ids.add(ie.file_id)
2299
new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
2208
2300
transform_tree(tree, tree.basis_tree(), interesting_ids)
2301
tree.set_conflicts(ConflictList(new_conflicts))
2209
2302
if file_list is None:
2210
2303
restore_files = list(tree.iter_conflicts())
2215
2308
restore(tree.abspath(filename))
2216
2309
except NotConflicted:
2218
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2220
interesting_ids = interesting_ids,
2221
other_rev_id=pending_merges[0],
2222
merge_type=merge_type,
2223
show_base=show_base,
2224
reprocess=reprocess)
2311
conflicts = merge_inner(tree.branch, other_tree, base_tree,
2313
interesting_ids=interesting_ids,
2314
other_rev_id=pending_merges[0],
2315
merge_type=merge_type,
2316
show_base=show_base,
2317
reprocess=reprocess)
2227
2320
if conflicts > 0:
2428
encoding_type = 'replace'
2336
2431
def run(self, other_branch=None, reverse=False, mine_only=False,
2337
2432
theirs_only=False, log_format=None, long=False, short=False, line=False,
2338
2433
show_ids=False, verbose=False):
2343
2438
if other_branch is None:
2344
2439
other_branch = parent
2345
2440
if other_branch is None:
2346
raise BzrCommandError("No missing location known or specified.")
2441
raise BzrCommandError("No peer location known or specified.")
2347
2442
print "Using last location: " + local_branch.get_parent()
2348
2443
remote_branch = Branch.open(other_branch)
2349
2444
if remote_branch.base == local_branch.base:
2357
2452
default = local_branch.get_config().log_format()
2358
2453
log_format = get_log_format(long=long, short=short,
2359
2454
line=line, default=default)
2360
lf = log_formatter(log_format, sys.stdout,
2455
lf = log_formatter(log_format,
2361
2457
show_ids=show_ids,
2362
2458
show_timezone='original')
2363
2459
if reverse is False:
2584
2680
takes_args = ['location?']
2587
def run(self, location=None,
2683
def run(self, location=None,
2588
2684
dry_run=False, verbose=False,
2589
2685
revision=None, force=False):
2590
from bzrlib.log import log_formatter
2686
from bzrlib.log import log_formatter, show_log
2592
2688
from bzrlib.uncommit import uncommit
2602
2698
b = control.open_branch()
2604
2701
if revision is None:
2605
2702
revno = b.revno()
2606
rev_id = b.last_revision()
2608
revno, rev_id = revision[0].in_history(b)
2704
# 'bzr uncommit -r 10' actually means uncommit
2705
# so that the final tree is at revno 10.
2706
# but bzrlib.uncommit.uncommit() actually uncommits
2707
# the revisions that are supplied.
2708
# So we need to offset it by one
2709
revno = revision[0].in_history(b).revno+1
2711
if revno <= b.revno():
2712
rev_id = b.get_rev_id(revno)
2609
2713
if rev_id is None:
2610
print 'No revisions to uncommit.'
2612
for r in range(revno, b.revno()+1):
2613
rev_id = b.get_rev_id(r)
2614
lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
2615
lf.show(r, b.repository.get_revision(rev_id), None)
2714
self.outf.write('No revisions to uncommit.\n')
2717
lf = log_formatter('short',
2719
show_timezone='original')
2724
direction='forward',
2725
start_revision=revno,
2726
end_revision=b.revno())
2618
2729
print 'Dry-run, pretending to remove the above revisions.'