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
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
18
"""Foreign branch utilities."""
21
from bzrlib.branch import Branch
21
from bzrlib.branch import (
22
25
from bzrlib.commands import Command, Option
23
26
from bzrlib.repository import Repository
24
27
from bzrlib.revision import Revision
245
249
self.get_revision(revision_id))
252
class ForeignBranch(Branch):
253
"""Branch that exists in a foreign version control system."""
255
def __init__(self, mapping):
256
self.mapping = mapping
257
super(ForeignBranch, self).__init__()
260
def update_workingtree_fileids(wt, target_tree):
261
"""Update the file ids in a working tree based on another tree.
263
:param wt: Working tree in which to update file ids
264
:param target_tree: Tree to retrieve new file ids from, based on path
266
tt = transform.TreeTransform(wt)
268
for f, p, c, v, d, n, k, e in target_tree.iter_changes(wt):
269
if v == (True, False):
270
trans_id = tt.trans_id_tree_path(p[0])
271
tt.unversion_file(trans_id)
272
elif v == (False, True):
273
trans_id = tt.trans_id_tree_path(p[1])
274
tt.version_file(f, trans_id)
278
if len(wt.get_parent_ids()) == 1:
279
wt.set_parent_trees([(target_tree.get_revision_id(), target_tree)])
281
wt.set_last_revision(target_tree.get_revision_id())
284
class cmd_dpush(Command):
285
"""Push into a different VCS without any custom bzr metadata.
287
This will afterwards rebase the local branch on the remote
288
branch unless the --no-rebase option is used, in which case
289
the two branches will be out of sync after the push.
292
takes_args = ['location?']
293
takes_options = ['remember', Option('directory',
294
help='Branch to push from, '
295
'rather than the one containing the working directory.',
299
Option('no-rebase', help="Do not rebase after push.")]
301
def run(self, location=None, remember=False, directory=None,
303
from bzrlib import urlutils
304
from bzrlib.bzrdir import BzrDir
305
from bzrlib.errors import BzrCommandError, NoWorkingTree
306
from bzrlib.trace import info
307
from bzrlib.workingtree import WorkingTree
309
if directory is None:
312
source_wt = WorkingTree.open_containing(directory)[0]
313
source_branch = source_wt.branch
314
except NoWorkingTree:
315
source_branch = Branch.open(directory)
317
stored_loc = source_branch.get_push_location()
319
if stored_loc is None:
320
raise BzrCommandError("No push location known or specified.")
322
display_url = urlutils.unescape_for_display(stored_loc,
324
self.outf.write("Using saved location: %s\n" % display_url)
325
location = stored_loc
327
bzrdir = BzrDir.open(location)
328
target_branch = bzrdir.open_branch()
329
target_branch.lock_write()
332
revid_map = source_branch.lossy_push(target_branch)
333
except errors.LossyPushToSameVCS:
334
raise BzrCommandError("%r and %r are in the same VCS, lossy "
335
"push not necessary. Please use regular push." %
336
(source_branch, target_branch))
337
# We successfully created the target, remember it
338
if source_branch.get_push_location() is None or remember:
339
source_branch.set_push_location(target_branch.base)
341
old_last_revid = source_branch.last_revision()
342
source_branch.pull(target_branch, overwrite=True)
343
new_last_revid = source_branch.last_revision()
344
if source_wt is not None and old_last_revid != new_last_revid:
345
source_wt.lock_write()
347
target = source_wt.branch.repository.revision_tree(
349
update_workingtree_fileids(source_wt, target)
353
target_branch.unlock()
356
class InterToForeignBranch(InterBranch):
358
def lossy_push(self, stop_revision=None):
359
"""Push deltas into another branch.
361
:note: This does not, like push, retain the revision ids from
362
the source branch and will, rather than adding bzr-specific
363
metadata, push only those semantics of the revision that can be
364
natively represented by this branch' VCS.
366
:param target: Target branch
367
:param stop_revision: Revision to push, defaults to last revision.
368
:return: Dictionary mapping revision ids from the target branch
369
to new revision ids in the target branch, for each
370
revision that was pushed.
372
raise NotImplementedError(self.lossy_push)