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:
91
105
for filename in file_list:
93
107
new_list.append(tree.relpath(osutils.dereference_path(filename)))
94
108
except errors.PathNotChild:
95
109
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
177
179
def run(self, show_ids=False, file_list=None, revision=None, short=False,
180
versioned=False, no_pending=False):
179
181
from bzrlib.status import show_tree_status
181
183
if revision and len(revision) > 2:
182
184
raise errors.BzrCommandError('bzr status --revision takes exactly'
183
185
' one or two revision specifiers')
185
tree, file_list = tree_files(file_list)
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:
187
197
show_tree_status(tree, show_ids=show_ids,
188
specific_files=file_list, revision=revision,
189
to_file=self.outf, short=short, versioned=versioned)
198
specific_files=relfile_list, revision=revision,
199
to_file=self.outf, short=short, versioned=versioned,
200
show_pending=(not no_pending))
192
203
class cmd_cat_revision(Command):
624
669
mergeable.get_merge_request(branch_to.repository)
625
670
branch_from = branch_to
627
branch_from = Branch.open_from_transport(location_transport)
672
branch_from = Branch.open(location,
673
possible_transports=possible_transports)
629
675
if branch_to.get_parent() is None or remember:
630
676
branch_to.set_parent(branch_from.base)
632
678
if revision is not None:
633
679
if len(revision) == 1:
634
revision_id = revision[0].in_history(branch_from).rev_id
680
revision_id = revision[0].as_revision_id(branch_from)
636
682
raise errors.BzrCommandError(
637
683
'bzr pull --revision takes one value.')
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)
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)
650
result.report(self.outf)
652
new_rh = branch_to.revision_history()
653
log.show_changed_revisions(branch_to, old_rh, new_rh,
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,
657
709
class cmd_push(Command):
696
748
' directory exists, but does not already'
697
749
' have a control directory. This flag will'
698
750
' 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.',
700
760
takes_args = ['location?']
701
761
encoding_type = 'replace'
703
763
def run(self, location=None, remember=False, overwrite=False,
704
create_prefix=False, verbose=False,
705
use_existing_dir=False,
707
# FIXME: Way too big! Put this into a function called from the
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
709
770
if directory is None:
711
772
br_from = Branch.open_containing(directory)[0]
712
stored_loc = br_from.get_push_location()
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
713
801
if location is None:
802
stored_loc = br_from.get_push_location()
714
803
if stored_loc is None:
715
raise errors.BzrCommandError("No push location known or specified.")
804
raise errors.BzrCommandError(
805
"No push location known or specified.")
717
807
display_url = urlutils.unescape_for_display(stored_loc,
718
808
self.outf.encoding)
719
self.outf.write("Using saved location: %s\n" % display_url)
809
self.outf.write("Using saved push location: %s\n" % display_url)
720
810
location = stored_loc
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
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)
838
818
class cmd_branch(Command):
891
875
# preserve whatever source format we have.
892
876
dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
893
possible_transports=[to_transport])
877
possible_transports=[to_transport],
878
accelerator_tree=accelerator_tree,
879
hardlink=hardlink, stacked=stacked)
894
880
branch = dir.open_branch()
895
881
except errors.NoSuchRevision:
896
882
to_transport.delete_tree('.')
897
msg = "The branch %s has no revision %s." % (from_location, revision[0])
883
msg = "The branch %s has no revision %s." % (from_location,
898
885
raise errors.BzrCommandError(msg)
900
branch.control_files.put_utf8('branch-name', name)
901
886
_merge_tags_if_possible(br_from, branch)
902
note('Branched %d revision(s).' % branch.revno())
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())
1071
1073
noise_level = 0
1072
1074
from bzrlib.info import show_bzrdir_info
1073
1075
show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
1074
verbose=noise_level)
1076
verbose=noise_level, outfile=self.outf)
1077
1079
class cmd_remove(Command):
1078
1080
"""Remove files or directories.
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.
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.
1088
1087
takes_args = ['file*']
1089
1088
takes_options = ['verbose',
1090
Option('new', help='Remove newly-added files.'),
1089
Option('new', help='Only remove files that have never been committed.'),
1091
1090
RegistryOption.from_kwargs('file-deletion-strategy',
1092
1091
'The file deletion mode to be used.',
1093
1092
title='Deletion Strategy', value_switches=True, enum_switch=False,
1106
1105
if file_list is not None:
1107
1106
file_list = [f for f in file_list]
1109
raise errors.BzrCommandError('Specify one or more files to'
1110
' remove, or use --new.')
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')
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')
1123
1135
class cmd_file_id(Command):
1459
1501
raise errors.BzrCommandError('bzr diff --revision takes exactly'
1460
1502
' one or two revision specifiers')
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)
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)
1505
1513
class cmd_deleted(Command):
2353
2362
in the checked revisions. Texts can be repeated when their file
2354
2363
entries are modified, but the file contents are not. It does not
2355
2364
indicate a problem.
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'::
2358
2384
_see_also = ['reconcile']
2359
takes_args = ['branch?']
2360
takes_options = ['verbose']
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.")]
2362
def run(self, branch=None, verbose=False):
2363
from bzrlib.check import check
2365
branch = Branch.open_containing('.')[0]
2367
branch = Branch.open(branch)
2368
check(branch, 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)
2371
2404
class cmd_upgrade(Command):
2465
2498
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)
2468
2571
class cmd_selftest(Command):
2469
2572
"""Run internal test suite.
2654
2778
branch1 = Branch.open_containing(branch)[0]
2655
2779
branch2 = Branch.open_containing(other)[0]
2657
last1 = ensure_null(branch1.last_revision())
2658
last2 = ensure_null(branch2.last_revision())
2660
graph = branch1.repository.get_graph(branch2.repository)
2661
base_rev_id = graph.find_unique_lca(last1, last2)
2663
print 'merge base is revision %s' % base_rev_id
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
2666
2797
class cmd_merge(Command):
2667
2798
"""Perform a three-way merge.
2669
The branch is the branch you will merge from. By default, it will merge
2670
the latest revision. If you specify a revision, that revision will be
2671
merged. If you specify two revisions, the first will be used as a BASE,
2672
and the second one as OTHER. Revision numbers are always relative to the
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.
2675
2812
By default, bzr will try to merge in all new work from the other
2676
2813
branch, automatically determining an appropriate base. If this
2891
3049
``revision`` and ``index`` must be supplied.)
2893
3051
Otherwise, the ``location`` parameter is used. If it is None, then the
2894
``parent`` location is used, and a note is printed.
3052
``submit`` or ``parent`` location is used, and a note is printed.
2896
3054
:param tree: The working tree to select a branch for merging into
2897
3055
:param location: The location entered by the user
2898
3056
:param revision: The revision parameter to the command
2899
3057
:param index: The index to use for the revision parameter. Negative
2900
3058
indices are permitted.
2901
:return: (selected_location, default_location). The default location
2902
will be the user-entered location, if any, or else the remembered
3059
:return: (selected_location, user_location). The default location
3060
will be the user-entered location.
2905
3062
if (revision is not None and index is not None
2906
3063
and revision[index] is not None):
2907
3064
branch = revision[index].get_branch()
2908
3065
if branch is not None:
2909
return branch, location
2910
location = self._get_remembered_parent(tree, location, 'Merging from')
2911
return location, location
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
2913
# TODO: move up to common parent; this isn't merge-specific anymore.
2914
def _get_remembered_parent(self, tree, supplied_location, verb_string):
3073
def _get_remembered(self, tree, verb_string):
2915
3074
"""Use tree.branch's parent if none was supplied.
2917
3076
Report if the remembered location was used.
2919
if supplied_location is not None:
2920
return supplied_location
2921
stored_location = tree.branch.get_parent()
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"
2922
3083
mutter("%s", stored_location)
2923
3084
if stored_location is None:
2924
3085
raise errors.BzrCommandError("No location specified or remembered")
2925
display_url = urlutils.unescape_for_display(stored_location,
2927
self.outf.write("%s remembered location %s\n" % (verb_string,
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)
2929
3089
return stored_location
3389
3584
takes_options = ['revision']
3391
3586
def run(self, revision_id_list=None, revision=None):
3392
import bzrlib.gpg as gpg
3393
3587
if revision_id_list is not None and revision is not None:
3394
3588
raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
3395
3589
if revision_id_list is None and revision is None:
3396
3590
raise errors.BzrCommandError('You must supply either --revision or a revision_id')
3397
3591
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
3398
3600
gpg_strategy = gpg.GPGStrategy(b.get_config())
3399
3601
if revision_id_list is not None:
3400
for revision_id in revision_id_list:
3401
b.repository.sign_revision(revision_id, gpg_strategy)
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()
3402
3611
elif revision is not None:
3403
3612
if len(revision) == 1:
3404
3613
revno, rev_id = revision[0].in_history(b)
3405
b.repository.sign_revision(rev_id, gpg_strategy)
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()
3406
3622
elif len(revision) == 2:
3407
3623
# are they both on rh- if so we can walk between them
3408
3624
# might be nice to have a range helper for arbitrary
3865
4115
for that mirror.
3867
4117
Mail is sent using your preferred mail program. This should be transparent
3868
on Windows (it uses MAPI). On *nix, it requires the xdg-email utility. If
3869
the preferred client can't be found (or used), your editor will be used.
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.
3871
4121
To use a specific mail program, set the mail_client configuration option.
3872
4122
(For Thunderbird 1.5, this works around some bugs.) Supported values for
3873
4123
specific clients are "evolution", "kmail", "mutt", and "thunderbird";
3874
generic options are "default", "editor", "mapi", and "xdg-email".
4124
generic options are "default", "editor", "emacsclient", "mapi", and
4125
"xdg-email". Plugins may also add supported clients.
3876
4127
If mail is being sent, a to address is required. This can be supplied
3877
either on the commandline, or by setting the submit_to configuration
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.
3880
4132
Two formats are currently supported: "4" uses revision bundle format 4 and
3881
4133
merge directive format 2. It is significantly faster and smaller than
3882
4134
older formats. It is compatible with Bazaar 0.19 and later. It is the
3883
4135
default. "0.9" uses revision bundle format 0.9 and merge directive
3884
4136
format 1. It is compatible with Bazaar 0.12 - 0.18.
4138
Merge directives are applied using the merge command or the pull command.
3887
4141
encoding_type = 'exact'
3889
_see_also = ['merge']
4143
_see_also = ['merge', 'pull']
3891
4145
takes_args = ['submit_branch?', 'public_branch?']
3924
4180
def _run(self, submit_branch, revision, public_branch, remember, format,
3925
4181
no_bundle, no_patch, output, from_, mail_to, message):
3926
4182
from bzrlib.revision import NULL_REVISION
4183
branch = Branch.open_containing(from_)[0]
3927
4184
if output is None:
3928
4185
outfile = StringIO()
3929
4186
elif output == '-':
3930
4187
outfile = self.outf
3932
4189
outfile = open(output, 'wb')
4190
# we may need to write data into branch's repository to calculate
3934
branch = Branch.open_containing(from_)[0]
3935
4194
if output is None:
3936
4195
config = branch.get_config()
3937
4196
if mail_to is None:
3938
4197
mail_to = config.get_user_option('submit_to')
3940
raise errors.BzrCommandError('No mail-to address'
3942
4198
mail_client = config.get_mail_client()
3943
4199
if remember and submit_branch is None:
3944
4200
raise errors.BzrCommandError(
3945
4201
'--remember requires a branch to be specified.')
3946
4202
stored_submit_branch = branch.get_submit_branch()
3947
remembered_submit_branch = False
4203
remembered_submit_branch = None
3948
4204
if submit_branch is None:
3949
4205
submit_branch = stored_submit_branch
3950
remembered_submit_branch = True
4206
remembered_submit_branch = "submit"
3952
4208
if stored_submit_branch is None or remember:
3953
4209
branch.set_submit_branch(submit_branch)
3954
4210
if submit_branch is None:
3955
4211
submit_branch = branch.get_parent()
3956
remembered_submit_branch = True
4212
remembered_submit_branch = "parent"
3957
4213
if submit_branch is None:
3958
4214
raise errors.BzrCommandError('No submit branch known or'
3960
if remembered_submit_branch:
3961
note('Using saved location: %s', submit_branch)
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")
3963
4225
stored_public_branch = branch.get_public_branch()
3964
4226
if public_branch is None:
4164
4431
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.',
4169
4442
@display_command
4173
4448
branch, relpath = Branch.open_containing(directory)
4174
for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
4175
self.outf.write('%-20s %s\n' % (tag_name, target))
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))
4178
4474
class cmd_reconfigure(Command):
4215
4520
elif target_type == 'checkout':
4216
4521
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)
4218
4530
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")
4221
4593
def _create_prefix(cur_transport):
4222
4594
needed = [cur_transport]
4223
4595
# Recurse upwards until we can create a directory successfully