1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005 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
94
93
return '<bzrlib.revisionspec.RevisionInfo object %s, %s for %r>' % (
95
94
self.revno, self.rev_id, self.branch)
98
def from_revision_id(branch, revision_id, revs):
99
"""Construct a RevisionInfo given just the id.
101
Use this if you don't know or care what the revno is.
104
revno = revs.index(revision_id) + 1
107
return RevisionInfo(branch, revno, revision_id)
110
97
# classes in this list should have a "prefix" attribute, against which
111
98
# string specs are matched
322
309
branch.lock_read()
324
revision_id_to_revno = branch.get_revision_id_to_revno_map()
325
revisions = [revision_id for revision_id, revno
326
in revision_id_to_revno.iteritems()
327
if revno == match_revno]
311
last_rev = branch.last_revision()
312
merge_sorted_revisions = tsort.merge_sort(
313
branch.repository.get_revision_graph(last_rev),
317
return item[3] == match_revno
318
revisions = filter(match, merge_sorted_revisions)
330
321
if len(revisions) != 1:
333
324
# there is no traditional 'revno' for dotted-decimal revnos.
334
325
# so for API compatability we return None.
335
return RevisionInfo(branch, None, revisions[0])
326
return RevisionInfo(branch, None, revisions[0][1])
338
# if get_rev_id supported negative revnos, there would not be a
339
# need for this special case.
340
329
if (-revno) >= len(revs):
376
365
prefix = 'revid:'
378
367
def _match_on(self, branch, revs):
379
# self.spec comes straight from parsing the command line arguments,
380
# so we expect it to be a Unicode string. Switch it to the internal
382
revision_id = osutils.safe_revision_id(self.spec, warn=False)
383
return RevisionInfo.from_revision_id(branch, revision_id, revs)
369
revno = revs.index(self.spec) + 1
372
return RevisionInfo(branch, revno, self.spec)
385
374
SPEC_TYPES.append(RevisionSpec_revid)
476
465
class RevisionSpec_tag(RevisionSpec):
477
"""Select a revision identified by tag name"""
479
help_txt = """Selects a revision identified by a tag name.
481
Tags are stored in the branch and created by the 'tag' command.
466
"""To be implemented."""
468
help_txt = """To be implemented."""
486
472
def _match_on(self, branch, revs):
487
# Can raise tags not supported, NoSuchTag, etc
488
return RevisionInfo.from_revision_id(branch,
489
branch.tags.lookup_tag(self.spec),
473
raise errors.InvalidRevisionSpec(self.user_spec, branch,
474
'tag: namespace registered,'
475
' but not implemented')
492
477
SPEC_TYPES.append(RevisionSpec_tag)
619
604
prefix = 'ancestor:'
621
606
def _match_on(self, branch, revs):
607
from bzrlib.branch import Branch
622
609
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
623
return self._find_revision_info(branch, self.spec)
626
def _find_revision_info(branch, other_location):
627
from bzrlib.branch import Branch
629
other_branch = Branch.open(other_location)
610
other_branch = Branch.open(self.spec)
630
611
revision_a = branch.last_revision()
631
612
revision_b = other_branch.last_revision()
632
613
for r, b in ((revision_a, branch), (revision_b, other_branch)):
634
615
raise errors.NoCommits(b)
635
616
revision_source = revision.MultipleRevisionSources(
636
617
branch.repository, other_branch.repository)
637
graph = branch.repository.get_graph(other_branch.repository)
638
revision_a = revision.ensure_null(revision_a)
639
revision_b = revision.ensure_null(revision_b)
640
if revision.NULL_REVISION in (revision_a, revision_b):
641
rev_id = revision.NULL_REVISION
643
rev_id = graph.find_unique_lca(revision_a, revision_b)
644
if rev_id == revision.NULL_REVISION:
645
raise errors.NoCommonAncestor(revision_a, revision_b)
618
rev_id = revision.common_ancestor(revision_a, revision_b,
647
621
revno = branch.revision_id_to_revno(rev_id)
648
622
except errors.NoSuchRevision:
650
624
return RevisionInfo(branch, revno, rev_id)
653
626
SPEC_TYPES.append(RevisionSpec_ancestor)
680
653
return RevisionInfo(branch, revno, revision_b)
682
655
SPEC_TYPES.append(RevisionSpec_branch)
685
class RevisionSpec_submit(RevisionSpec_ancestor):
686
"""Selects a common ancestor with a submit branch."""
688
help_txt = """Selects a common ancestor with the submit branch.
690
Diffing against this shows all the changes that were made in this branch,
691
and is a good predictor of what merge will do. The submit branch is
692
used by the bundle and merge directive comands. If no submit branch
693
is specified, the parent branch is used instead.
695
The common ancestor is the last revision that existed in both
696
branches. Usually this is the branch point, but it could also be
697
a revision that was merged.
700
$ bzr diff -r submit:
705
def _match_on(self, branch, revs):
706
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
707
submit_location = branch.get_submit_branch()
708
location_type = 'submit branch'
709
if submit_location is None:
710
submit_location = branch.get_parent()
711
location_type = 'parent branch'
712
if submit_location is None:
713
raise errors.NoSubmitBranch(branch)
714
trace.note('Using %s %s', location_type, submit_location)
715
return self._find_revision_info(branch, submit_location)
718
SPEC_TYPES.append(RevisionSpec_submit)