87
87
if file_list is None or len(file_list) == 0:
88
88
return WorkingTree.open_containing(default_branch)[0], file_list
89
89
tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
90
return tree, safe_relpath_files(tree, file_list)
93
def safe_relpath_files(tree, file_list):
94
"""Convert file_list into a list of relpaths in tree.
96
:param tree: A tree to operate on.
97
:param file_list: A list of user provided paths or None.
98
:return: A list of relative paths.
99
:raises errors.PathNotChild: When a provided path is in a different tree
102
if file_list is None:
105
91
for filename in file_list:
107
93
new_list.append(tree.relpath(osutils.dereference_path(filename)))
108
94
except errors.PathNotChild:
109
95
raise errors.FileInWrongBranch(tree.branch, filename)
99
@symbol_versioning.deprecated_function(symbol_versioning.zero_fifteen)
100
def get_format_type(typestring):
101
"""Parse and return a format specifier."""
102
# Have to use BzrDirMetaFormat1 directly, so that
103
# RepositoryFormat.set_default_format works
104
if typestring == "default":
105
return bzrdir.BzrDirMetaFormat1()
107
return bzrdir.format_registry.make_bzrdir(typestring)
109
msg = 'Unknown bzr format "%s". See "bzr help formats".' % typestring
110
raise errors.BzrCommandError(msg)
113
113
# TODO: Make sure no commands unconditionally use the working directory as a
179
177
def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
versioned=False, no_pending=False):
181
179
from bzrlib.status import show_tree_status
183
181
if revision and len(revision) > 2:
184
182
raise errors.BzrCommandError('bzr status --revision takes exactly'
185
183
' one or two revision specifiers')
187
tree, relfile_list = tree_files(file_list)
188
# Avoid asking for specific files when that is not needed.
189
if relfile_list == ['']:
191
# Don't disable pending merges for full trees other than '.'.
192
if file_list == ['.']:
194
# A specific path within a tree was given.
195
elif relfile_list is not None:
185
tree, file_list = tree_files(file_list)
197
187
show_tree_status(tree, show_ids=show_ids,
198
specific_files=relfile_list, revision=revision,
199
to_file=self.outf, short=short, versioned=versioned,
200
show_pending=(not no_pending))
188
specific_files=file_list, revision=revision,
189
to_file=self.outf, short=short, versioned=versioned)
203
192
class cmd_cat_revision(Command):
669
624
mergeable.get_merge_request(branch_to.repository)
670
625
branch_from = branch_to
672
branch_from = Branch.open(location,
673
possible_transports=possible_transports)
627
branch_from = Branch.open_from_transport(location_transport)
675
629
if branch_to.get_parent() is None or remember:
676
630
branch_to.set_parent(branch_from.base)
678
632
if revision is not None:
679
633
if len(revision) == 1:
680
revision_id = revision[0].as_revision_id(branch_from)
634
revision_id = revision[0].in_history(branch_from).rev_id
682
636
raise errors.BzrCommandError(
683
637
'bzr pull --revision takes one value.')
685
branch_to.lock_write()
687
if tree_to is not None:
688
change_reporter = delta._ChangeReporter(
689
unversioned_filter=tree_to.is_ignored)
690
result = tree_to.pull(branch_from, overwrite, revision_id,
692
possible_transports=possible_transports)
694
result = branch_to.pull(branch_from, overwrite, revision_id)
640
old_rh = branch_to.revision_history()
641
if tree_to is not None:
642
change_reporter = delta._ChangeReporter(
643
unversioned_filter=tree_to.is_ignored)
644
result = tree_to.pull(branch_from, overwrite, revision_id,
646
possible_transports=possible_transports)
648
result = branch_to.pull(branch_from, overwrite, revision_id)
696
result.report(self.outf)
697
if verbose and result.old_revid != result.new_revid:
699
branch_to.repository.iter_reverse_revision_history(
702
new_rh = branch_to.revision_history()
703
log.show_changed_revisions(branch_to, old_rh, new_rh,
650
result.report(self.outf)
652
new_rh = branch_to.revision_history()
653
log.show_changed_revisions(branch_to, old_rh, new_rh,
709
657
class cmd_push(Command):
748
696
' directory exists, but does not already'
749
697
' have a control directory. This flag will'
750
698
' allow push to proceed.'),
752
help='Create a stacked branch that references the public location '
753
'of the parent branch.'),
755
help='Create a stacked branch that refers to another branch '
756
'for the commit history. Only the work not present in the '
757
'referenced branch is included in the branch created.',
760
700
takes_args = ['location?']
761
701
encoding_type = 'replace'
763
703
def run(self, location=None, remember=False, overwrite=False,
764
create_prefix=False, verbose=False, revision=None,
765
use_existing_dir=False, directory=None, stacked_on=None,
767
from bzrlib.push import _show_push_branch
769
# Get the source branch and revision_id
704
create_prefix=False, verbose=False,
705
use_existing_dir=False,
707
# FIXME: Way too big! Put this into a function called from the
770
709
if directory is None:
772
711
br_from = Branch.open_containing(directory)[0]
773
if revision is not None:
774
if len(revision) == 1:
775
revision_id = revision[0].in_history(br_from).rev_id
777
raise errors.BzrCommandError(
778
'bzr push --revision takes one value.')
780
revision_id = br_from.last_revision()
782
# Get the stacked_on branch, if any
783
if stacked_on is not None:
784
stacked_on = urlutils.normalize_url(stacked_on)
786
parent_url = br_from.get_parent()
788
parent = Branch.open(parent_url)
789
stacked_on = parent.get_public_branch()
791
# I considered excluding non-http url's here, thus forcing
792
# 'public' branches only, but that only works for some
793
# users, so it's best to just depend on the user spotting an
794
# error by the feedback given to them. RBC 20080227.
795
stacked_on = parent_url
797
raise errors.BzrCommandError(
798
"Could not determine branch to refer to.")
800
# Get the destination location
712
stored_loc = br_from.get_push_location()
801
713
if location is None:
802
stored_loc = br_from.get_push_location()
803
714
if stored_loc is None:
804
raise errors.BzrCommandError(
805
"No push location known or specified.")
715
raise errors.BzrCommandError("No push location known or specified.")
807
717
display_url = urlutils.unescape_for_display(stored_loc,
808
718
self.outf.encoding)
809
self.outf.write("Using saved push location: %s\n" % display_url)
719
self.outf.write("Using saved location: %s\n" % display_url)
810
720
location = stored_loc
812
_show_push_branch(br_from, revision_id, location, self.outf,
813
verbose=verbose, overwrite=overwrite, remember=remember,
814
stacked_on=stacked_on, create_prefix=create_prefix,
815
use_existing_dir=use_existing_dir)
722
to_transport = transport.get_transport(location)
724
br_to = repository_to = dir_to = None
726
dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
727
except errors.NotBranchError:
728
pass # Didn't find anything
730
# If we can open a branch, use its direct repository, otherwise see
731
# if there is a repository without a branch.
733
br_to = dir_to.open_branch()
734
except errors.NotBranchError:
735
# Didn't find a branch, can we find a repository?
737
repository_to = dir_to.find_repository()
738
except errors.NoRepositoryPresent:
741
# Found a branch, so we must have found a repository
742
repository_to = br_to.repository
747
# The destination doesn't exist; create it.
748
# XXX: Refactor the create_prefix/no_create_prefix code into a
749
# common helper function
751
to_transport.mkdir('.')
752
except errors.FileExists:
753
if not use_existing_dir:
754
raise errors.BzrCommandError("Target directory %s"
755
" already exists, but does not have a valid .bzr"
756
" directory. Supply --use-existing-dir to push"
757
" there anyway." % location)
758
except errors.NoSuchFile:
759
if not create_prefix:
760
raise errors.BzrCommandError("Parent directory of %s"
762
"\nYou may supply --create-prefix to create all"
763
" leading parent directories."
765
_create_prefix(to_transport)
767
# Now the target directory exists, but doesn't have a .bzr
768
# directory. So we need to create it, along with any work to create
769
# all of the dependent branches, etc.
770
dir_to = br_from.bzrdir.clone_on_transport(to_transport,
771
revision_id=br_from.last_revision())
772
br_to = dir_to.open_branch()
773
# TODO: Some more useful message about what was copied
774
note('Created new branch.')
775
# We successfully created the target, remember it
776
if br_from.get_push_location() is None or remember:
777
br_from.set_push_location(br_to.base)
778
elif repository_to is None:
779
# we have a bzrdir but no branch or repository
780
# XXX: Figure out what to do other than complain.
781
raise errors.BzrCommandError("At %s you have a valid .bzr control"
782
" directory, but not a branch or repository. This is an"
783
" unsupported configuration. Please move the target directory"
784
" out of the way and try again."
787
# We have a repository but no branch, copy the revisions, and then
789
last_revision_id = br_from.last_revision()
790
repository_to.fetch(br_from.repository,
791
revision_id=last_revision_id)
792
br_to = br_from.clone(dir_to, revision_id=last_revision_id)
793
note('Created new branch.')
794
if br_from.get_push_location() is None or remember:
795
br_from.set_push_location(br_to.base)
796
else: # We have a valid to branch
797
# We were able to connect to the remote location, so remember it
798
# we don't need to successfully push because of possible divergence.
799
if br_from.get_push_location() is None or remember:
800
br_from.set_push_location(br_to.base)
802
old_rh = br_to.revision_history()
805
tree_to = dir_to.open_workingtree()
806
except errors.NotLocalUrl:
807
warning("This transport does not update the working "
808
"tree of: %s. See 'bzr help working-trees' for "
809
"more information." % br_to.base)
810
push_result = br_from.push(br_to, overwrite)
811
except errors.NoWorkingTree:
812
push_result = br_from.push(br_to, overwrite)
816
push_result = br_from.push(tree_to.branch, overwrite)
820
except errors.DivergedBranches:
821
raise errors.BzrCommandError('These branches have diverged.'
822
' Try using "merge" and then "push".')
823
if push_result is not None:
824
push_result.report(self.outf)
826
new_rh = br_to.revision_history()
829
from bzrlib.log import show_changed_revisions
830
show_changed_revisions(br_to, old_rh, new_rh,
833
# we probably did a clone rather than a push, so a message was
818
838
class cmd_branch(Command):
875
891
# preserve whatever source format we have.
876
892
dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
877
possible_transports=[to_transport],
878
accelerator_tree=accelerator_tree,
879
hardlink=hardlink, stacked=stacked)
893
possible_transports=[to_transport])
880
894
branch = dir.open_branch()
881
895
except errors.NoSuchRevision:
882
896
to_transport.delete_tree('.')
883
msg = "The branch %s has no revision %s." % (from_location,
897
msg = "The branch %s has no revision %s." % (from_location, revision[0])
885
898
raise errors.BzrCommandError(msg)
900
branch.control_files.put_utf8('branch-name', name)
886
901
_merge_tags_if_possible(br_from, branch)
887
# If the source branch is stacked, the new branch may
888
# be stacked whether we asked for that explicitly or not.
889
# We therefore need a try/except here and not just 'if stacked:'
891
note('Created new stacked branch referring to %s.' %
892
branch.get_stacked_on_url())
893
except (errors.NotStacked, errors.UnstackableBranchFormat,
894
errors.UnstackableRepositoryFormat), e:
895
note('Branched %d revision(s).' % branch.revno())
902
note('Branched %d revision(s).' % branch.revno())
1073
1071
noise_level = 0
1074
1072
from bzrlib.info import show_bzrdir_info
1075
1073
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1076
verbose=noise_level, outfile=self.outf)
1074
verbose=noise_level)
1079
1077
class cmd_remove(Command):
1080
1078
"""Remove files or directories.
1082
This makes bzr stop tracking changes to the specified files. bzr will delete
1083
them if they can easily be recovered using revert. If no options or
1084
parameters are given bzr will scan for files that are being tracked by bzr
1085
but missing in your tree and stop tracking them for you.
1080
This makes bzr stop tracking changes to the specified files and
1081
delete them if they can easily be recovered using revert.
1083
You can specify one or more files, and/or --new. If you specify --new,
1084
only 'added' files will be removed. If you specify both, then new files
1085
in the specified directories will be removed. If the directories are
1086
also new, they will also be removed.
1087
1088
takes_args = ['file*']
1088
1089
takes_options = ['verbose',
1089
Option('new', help='Only remove files that have never been committed.'),
1090
Option('new', help='Remove newly-added files.'),
1090
1091
RegistryOption.from_kwargs('file-deletion-strategy',
1091
1092
'The file deletion mode to be used.',
1092
1093
title='Deletion Strategy', value_switches=True, enum_switch=False,
1105
1106
if file_list is not None:
1106
1107
file_list = [f for f in file_list]
1109
raise errors.BzrCommandError('Specify one or more files to'
1110
' remove, or use --new.')
1110
# Heuristics should probably all move into tree.remove_smart or
1113
added = tree.changes_from(tree.basis_tree(),
1114
specific_files=file_list).added
1115
file_list = sorted([f[0] for f in added], reverse=True)
1116
if len(file_list) == 0:
1117
raise errors.BzrCommandError('No matching files.')
1118
elif file_list is None:
1119
# missing files show up in iter_changes(basis) as
1120
# versioned-with-no-kind.
1122
for change in tree.iter_changes(tree.basis_tree()):
1123
# Find paths in the working tree that have no kind:
1124
if change[1][1] is not None and change[6][1] is None:
1125
missing.append(change[1][1])
1126
file_list = sorted(missing, reverse=True)
1127
file_deletion_strategy = 'keep'
1128
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1129
keep_files=file_deletion_strategy=='keep',
1130
force=file_deletion_strategy=='force')
1113
added = tree.changes_from(tree.basis_tree(),
1114
specific_files=file_list).added
1115
file_list = sorted([f[0] for f in added], reverse=True)
1116
if len(file_list) == 0:
1117
raise errors.BzrCommandError('No matching files.')
1118
tree.remove(file_list, verbose=verbose, to_file=self.outf,
1119
keep_files=file_deletion_strategy=='keep',
1120
force=file_deletion_strategy=='force')
1135
1123
class cmd_file_id(Command):
1501
1459
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1502
1460
' one or two revision specifiers')
1504
old_tree, new_tree, specific_files, extra_trees = \
1505
_get_trees_to_diff(file_list, revision, old, new)
1506
return show_diff_trees(old_tree, new_tree, sys.stdout,
1507
specific_files=specific_files,
1508
external_diff_options=diff_options,
1509
old_label=old_label, new_label=new_label,
1510
extra_trees=extra_trees, using=using)
1463
tree1, file_list = internal_tree_files(file_list)
1467
except errors.FileInWrongBranch:
1468
if len(file_list) != 2:
1469
raise errors.BzrCommandError("Files are in different branches")
1471
tree1, file1 = WorkingTree.open_containing(file_list[0])
1472
tree2, file2 = WorkingTree.open_containing(file_list[1])
1473
if file1 != "" or file2 != "":
1474
# FIXME diff those two files. rbc 20051123
1475
raise errors.BzrCommandError("Files are in different branches")
1477
except errors.NotBranchError:
1478
if (revision is not None and len(revision) == 2
1479
and not revision[0].needs_branch()
1480
and not revision[1].needs_branch()):
1481
# If both revision specs include a branch, we can
1482
# diff them without needing a local working tree
1483
tree1, tree2 = None, None
1487
if tree2 is not None:
1488
if revision is not None:
1489
# FIXME: but there should be a clean way to diff between
1490
# non-default versions of two trees, it's not hard to do
1492
raise errors.BzrCommandError(
1493
"Sorry, diffing arbitrary revisions across branches "
1494
"is not implemented yet")
1495
return show_diff_trees(tree1, tree2, sys.stdout,
1496
specific_files=file_list,
1497
external_diff_options=diff_options,
1498
old_label=old_label, new_label=new_label)
1500
return diff_cmd_helper(tree1, file_list, diff_options,
1501
revision_specs=revision,
1502
old_label=old_label, new_label=new_label)
1513
1505
class cmd_deleted(Command):
2343
2335
class cmd_check(Command):
2344
"""Validate working tree structure, branch consistency and repository history.
2346
This command checks various invariants about branch and repository storage
2347
to detect data corruption or bzr bugs.
2349
The working tree and branch checks will only give output if a problem is
2350
detected. The output fields of the repository check are:
2352
revisions: This is just the number of revisions checked. It doesn't
2354
versionedfiles: This is just the number of versionedfiles checked. It
2355
doesn't indicate a problem.
2356
unreferenced ancestors: Texts that are ancestors of other texts, but
2357
are not properly referenced by the revision ancestry. This is a
2358
subtle problem that Bazaar can work around.
2359
unique file texts: This is the total number of unique file contents
2360
seen in the checked revisions. It does not indicate a problem.
2361
repeated file texts: This is the total number of repeated texts seen
2362
in the checked revisions. Texts can be repeated when their file
2363
entries are modified, but the file contents are not. It does not
2366
If no restrictions are specified, all Bazaar data that is found at the given
2367
location will be checked.
2371
Check the tree and branch at 'foo'::
2373
bzr check --tree --branch foo
2375
Check only the repository at 'bar'::
2377
bzr check --repo bar
2379
Check everything at 'baz'::
2336
"""Validate consistency of branch history.
2338
This command checks various invariants about the branch storage to
2339
detect data corruption or bzr bugs.
2384
2342
_see_also = ['reconcile']
2385
takes_args = ['path?']
2386
takes_options = ['verbose',
2387
Option('branch', help="Check the branch related to the"
2388
" current directory."),
2389
Option('repo', help="Check the repository related to the"
2390
" current directory."),
2391
Option('tree', help="Check the working tree related to"
2392
" the current directory.")]
2343
takes_args = ['branch?']
2344
takes_options = ['verbose']
2394
def run(self, path=None, verbose=False, branch=False, repo=False,
2396
from bzrlib.check import check_dwim
2399
if not branch and not repo and not tree:
2400
branch = repo = tree = True
2401
check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
2346
def run(self, branch=None, verbose=False):
2347
from bzrlib.check import check
2349
tree = WorkingTree.open_containing()[0]
2350
branch = tree.branch
2352
branch = Branch.open(branch)
2353
check(branch, verbose)
2404
2356
class cmd_upgrade(Command):
2498
2450
print branch.nick
2501
class cmd_alias(Command):
2502
"""Set/unset and display aliases.
2505
Show the current aliases::
2509
Show the alias specified for 'll'::
2513
Set an alias for 'll'::
2515
bzr alias ll="log --line -r-10..-1"
2517
To remove an alias for 'll'::
2519
bzr alias --remove ll
2522
takes_args = ['name?']
2524
Option('remove', help='Remove the alias.'),
2527
def run(self, name=None, remove=False):
2529
self.remove_alias(name)
2531
self.print_aliases()
2533
equal_pos = name.find('=')
2535
self.print_alias(name)
2537
self.set_alias(name[:equal_pos], name[equal_pos+1:])
2539
def remove_alias(self, alias_name):
2540
if alias_name is None:
2541
raise errors.BzrCommandError(
2542
'bzr alias --remove expects an alias to remove.')
2543
# If alias is not found, print something like:
2544
# unalias: foo: not found
2545
c = config.GlobalConfig()
2546
c.unset_alias(alias_name)
2549
def print_aliases(self):
2550
"""Print out the defined aliases in a similar format to bash."""
2551
aliases = config.GlobalConfig().get_aliases()
2552
for key, value in sorted(aliases.iteritems()):
2553
self.outf.write('bzr alias %s="%s"\n' % (key, value))
2556
def print_alias(self, alias_name):
2557
from bzrlib.commands import get_alias
2558
alias = get_alias(alias_name)
2560
self.outf.write("bzr alias: %s: not found\n" % alias_name)
2563
'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
2565
def set_alias(self, alias_name, alias_command):
2566
"""Save the alias in the global config."""
2567
c = config.GlobalConfig()
2568
c.set_alias(alias_name, alias_command)
2571
2453
class cmd_selftest(Command):
2572
2454
"""Run internal test suite.
2778
2639
branch1 = Branch.open_containing(branch)[0]
2779
2640
branch2 = Branch.open_containing(other)[0]
2784
last1 = ensure_null(branch1.last_revision())
2785
last2 = ensure_null(branch2.last_revision())
2787
graph = branch1.repository.get_graph(branch2.repository)
2788
base_rev_id = graph.find_unique_lca(last1, last2)
2790
print 'merge base is revision %s' % base_rev_id
2642
last1 = ensure_null(branch1.last_revision())
2643
last2 = ensure_null(branch2.last_revision())
2645
graph = branch1.repository.get_graph(branch2.repository)
2646
base_rev_id = graph.find_unique_lca(last1, last2)
2648
print 'merge base is revision %s' % base_rev_id
2797
2651
class cmd_merge(Command):
2798
2652
"""Perform a three-way merge.
2800
The source of the merge can be specified either in the form of a branch,
2801
or in the form of a path to a file containing a merge directive generated
2802
with bzr send. If neither is specified, the default is the upstream branch
2803
or the branch most recently merged using --remember.
2805
When merging a branch, by default the tip will be merged. To pick a different
2806
revision, pass --revision. If you specify two values, the first will be used as
2807
BASE and the second one as OTHER. Merging individual revisions, or a subset of
2808
available revisions, like this is commonly referred to as "cherrypicking".
2810
Revision numbers are always relative to the branch being merged.
2654
The branch is the branch you will merge from. By default, it will merge
2655
the latest revision. If you specify a revision, that revision will be
2656
merged. If you specify two revisions, the first will be used as a BASE,
2657
and the second one as OTHER. Revision numbers are always relative to the
2812
2660
By default, bzr will try to merge in all new work from the other
2813
2661
branch, automatically determining an appropriate base. If this
3049
2876
``revision`` and ``index`` must be supplied.)
3051
2878
Otherwise, the ``location`` parameter is used. If it is None, then the
3052
``submit`` or ``parent`` location is used, and a note is printed.
2879
``parent`` location is used, and a note is printed.
3054
2881
:param tree: The working tree to select a branch for merging into
3055
2882
:param location: The location entered by the user
3056
2883
:param revision: The revision parameter to the command
3057
2884
:param index: The index to use for the revision parameter. Negative
3058
2885
indices are permitted.
3059
:return: (selected_location, user_location). The default location
3060
will be the user-entered location.
2886
:return: (selected_location, default_location). The default location
2887
will be the user-entered location, if any, or else the remembered
3062
2890
if (revision is not None and index is not None
3063
2891
and revision[index] is not None):
3064
2892
branch = revision[index].get_branch()
3065
2893
if branch is not None:
3066
return branch, branch
3067
if user_location is None:
3068
location = self._get_remembered(tree, 'Merging from')
3070
location = user_location
3071
return location, user_location
2894
return branch, location
2895
location = self._get_remembered_parent(tree, location, 'Merging from')
2896
return location, location
3073
def _get_remembered(self, tree, verb_string):
2898
# TODO: move up to common parent; this isn't merge-specific anymore.
2899
def _get_remembered_parent(self, tree, supplied_location, verb_string):
3074
2900
"""Use tree.branch's parent if none was supplied.
3076
2902
Report if the remembered location was used.
3078
stored_location = tree.branch.get_submit_branch()
3079
stored_location_type = "submit"
3080
if stored_location is None:
3081
stored_location = tree.branch.get_parent()
3082
stored_location_type = "parent"
2904
if supplied_location is not None:
2905
return supplied_location
2906
stored_location = tree.branch.get_parent()
3083
2907
mutter("%s", stored_location)
3084
2908
if stored_location is None:
3085
2909
raise errors.BzrCommandError("No location specified or remembered")
3086
display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3087
note(u"%s remembered %s location %s", verb_string,
3088
stored_location_type, display_url)
2910
display_url = urlutils.unescape_for_display(stored_location,
2912
self.outf.write("%s remembered location %s\n" % (verb_string,
3089
2914
return stored_location
3584
3366
takes_options = ['revision']
3586
3368
def run(self, revision_id_list=None, revision=None):
3369
import bzrlib.gpg as gpg
3587
3370
if revision_id_list is not None and revision is not None:
3588
3371
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3589
3372
if revision_id_list is None and revision is None:
3590
3373
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3591
3374
b = WorkingTree.open_containing(u'.')[0].branch
3594
return self._run(b, revision_id_list, revision)
3598
def _run(self, b, revision_id_list, revision):
3599
import bzrlib.gpg as gpg
3600
3375
gpg_strategy = gpg.GPGStrategy(b.get_config())
3601
3376
if revision_id_list is not None:
3602
b.repository.start_write_group()
3604
for revision_id in revision_id_list:
3605
b.repository.sign_revision(revision_id, gpg_strategy)
3607
b.repository.abort_write_group()
3610
b.repository.commit_write_group()
3377
for revision_id in revision_id_list:
3378
b.repository.sign_revision(revision_id, gpg_strategy)
3611
3379
elif revision is not None:
3612
3380
if len(revision) == 1:
3613
3381
revno, rev_id = revision[0].in_history(b)
3614
b.repository.start_write_group()
3616
b.repository.sign_revision(rev_id, gpg_strategy)
3618
b.repository.abort_write_group()
3621
b.repository.commit_write_group()
3382
b.repository.sign_revision(rev_id, gpg_strategy)
3622
3383
elif len(revision) == 2:
3623
3384
# are they both on rh- if so we can walk between them
3624
3385
# might be nice to have a range helper for arbitrary
4115
3842
for that mirror.
4117
3844
Mail is sent using your preferred mail program. This should be transparent
4118
on Windows (it uses MAPI). On Linux, it requires the xdg-email utility.
4119
If the preferred client can't be found (or used), your editor will be used.
3845
on Windows (it uses MAPI). On *nix, it requires the xdg-email utility. If
3846
the preferred client can't be found (or used), your editor will be used.
4121
3848
To use a specific mail program, set the mail_client configuration option.
4122
3849
(For Thunderbird 1.5, this works around some bugs.) Supported values for
4123
3850
specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4124
generic options are "default", "editor", "emacsclient", "mapi", and
4125
"xdg-email". Plugins may also add supported clients.
3851
generic options are "default", "editor", "mapi", and "xdg-email".
4127
3853
If mail is being sent, a to address is required. This can be supplied
4128
either on the commandline, by setting the submit_to configuration
4129
option in the branch itself or the child_submit_to configuration option
4130
in the submit branch.
3854
either on the commandline, or by setting the submit_to configuration
4132
3857
Two formats are currently supported: "4" uses revision bundle format 4 and
4133
3858
merge directive format 2. It is significantly faster and smaller than
4134
3859
older formats. It is compatible with Bazaar 0.19 and later. It is the
4135
3860
default. "0.9" uses revision bundle format 0.9 and merge directive
4136
3861
format 1. It is compatible with Bazaar 0.12 - 0.18.
4138
Merge directives are applied using the merge command or the pull command.
4141
3864
encoding_type = 'exact'
4143
_see_also = ['merge', 'pull']
3866
_see_also = ['merge']
4145
3868
takes_args = ['submit_branch?', 'public_branch?']
4180
3901
def _run(self, submit_branch, revision, public_branch, remember, format,
4181
3902
no_bundle, no_patch, output, from_, mail_to, message):
4182
3903
from bzrlib.revision import NULL_REVISION
4183
branch = Branch.open_containing(from_)[0]
4184
3904
if output is None:
4185
3905
outfile = StringIO()
4186
3906
elif output == '-':
4187
3907
outfile = self.outf
4189
3909
outfile = open(output, 'wb')
4190
# we may need to write data into branch's repository to calculate
3911
branch = Branch.open_containing(from_)[0]
4194
3912
if output is None:
4195
3913
config = branch.get_config()
4196
3914
if mail_to is None:
4197
3915
mail_to = config.get_user_option('submit_to')
3917
raise errors.BzrCommandError('No mail-to address'
4198
3919
mail_client = config.get_mail_client()
4199
3920
if remember and submit_branch is None:
4200
3921
raise errors.BzrCommandError(
4201
3922
'--remember requires a branch to be specified.')
4202
3923
stored_submit_branch = branch.get_submit_branch()
4203
remembered_submit_branch = None
3924
remembered_submit_branch = False
4204
3925
if submit_branch is None:
4205
3926
submit_branch = stored_submit_branch
4206
remembered_submit_branch = "submit"
3927
remembered_submit_branch = True
4208
3929
if stored_submit_branch is None or remember:
4209
3930
branch.set_submit_branch(submit_branch)
4210
3931
if submit_branch is None:
4211
3932
submit_branch = branch.get_parent()
4212
remembered_submit_branch = "parent"
3933
remembered_submit_branch = True
4213
3934
if submit_branch is None:
4214
3935
raise errors.BzrCommandError('No submit branch known or'
4216
if remembered_submit_branch is not None:
4217
note('Using saved %s location "%s" to determine what '
4218
'changes to submit.', remembered_submit_branch,
4222
submit_config = Branch.open(submit_branch).get_config()
4223
mail_to = submit_config.get_user_option("child_submit_to")
3937
if remembered_submit_branch:
3938
note('Using saved location: %s', submit_branch)
4225
3940
stored_public_branch = branch.get_public_branch()
4226
3941
if public_branch is None:
4431
4141
short_name='d',
4434
RegistryOption.from_kwargs('sort',
4435
'Sort tags by different criteria.', title='Sorting',
4436
alpha='Sort tags lexicographically (default).',
4437
time='Sort tags chronologically.',
4442
4146
@display_command
4448
4150
branch, relpath = Branch.open_containing(directory)
4449
tags = branch.tags.get_tag_dict().items()
4454
elif sort == 'time':
4456
for tag, revid in tags:
4458
revobj = branch.repository.get_revision(revid)
4459
except errors.NoSuchRevision:
4460
timestamp = sys.maxint # place them at the end
4462
timestamp = revobj.timestamp
4463
timestamps[revid] = timestamp
4464
tags.sort(key=lambda x: timestamps[x[1]])
4466
# [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
4467
revno_map = branch.get_revision_id_to_revno_map()
4468
tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
4469
for tag, revid in tags ]
4470
for tag, revspec in tags:
4471
self.outf.write('%-20s %s\n' % (tag, revspec))
4151
for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
4152
self.outf.write('%-20s %s\n' % (tag_name, target))
4474
4155
class cmd_reconfigure(Command):
4520
4192
elif target_type == 'checkout':
4521
4193
reconfiguration = reconfigure.Reconfigure.to_checkout(directory,
4523
elif target_type == 'lightweight-checkout':
4524
reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
4526
elif target_type == 'use-shared':
4527
reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
4528
elif target_type == 'standalone':
4529
reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
4530
4195
reconfiguration.apply(force)
4533
class cmd_switch(Command):
4534
"""Set the branch of a checkout and update.
4536
For lightweight checkouts, this changes the branch being referenced.
4537
For heavyweight checkouts, this checks that there are no local commits
4538
versus the current bound branch, then it makes the local branch a mirror
4539
of the new location and binds to it.
4541
In both cases, the working tree is updated and uncommitted changes
4542
are merged. The user can commit or revert these as they desire.
4544
Pending merges need to be committed or reverted before using switch.
4546
The path to the branch to switch to can be specified relative to the parent
4547
directory of the current branch. For example, if you are currently in a
4548
checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4552
takes_args = ['to_location']
4553
takes_options = [Option('force',
4554
help='Switch even if local commits will be lost.')
4557
def run(self, to_location, force=False):
4558
from bzrlib import switch
4560
control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
4562
to_branch = Branch.open(to_location)
4563
except errors.NotBranchError:
4564
to_branch = Branch.open(
4565
control_dir.open_branch().base + '../' + to_location)
4566
switch.switch(control_dir, to_branch, force)
4567
note('Switched to branch: %s',
4568
urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4571
class cmd_hooks(Command):
4572
"""Show a branch's currently registered hooks.
4576
takes_args = ['path?']
4578
def run(self, path=None):
4581
branch_hooks = Branch.open(path).hooks
4582
for hook_type in branch_hooks:
4583
hooks = branch_hooks[hook_type]
4584
self.outf.write("%s:\n" % (hook_type,))
4587
self.outf.write(" %s\n" %
4588
(branch_hooks.get_hook_name(hook),))
4590
self.outf.write(" <no hooks installed>\n")
4593
4198
def _create_prefix(cur_transport):
4594
4199
needed = [cur_transport]
4595
4200
# Recurse upwards until we can create a directory successfully