1
# Copyright (C) 2005 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 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
93
94
return '<bzrlib.revisionspec.RevisionInfo object %s, %s for %r>' % (
94
95
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)
97
110
# classes in this list should have a "prefix" attribute, against which
98
111
# string specs are matched
309
322
branch.lock_read()
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)
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]
321
330
if len(revisions) != 1:
324
333
# there is no traditional 'revno' for dotted-decimal revnos.
325
334
# so for API compatability we return None.
326
return RevisionInfo(branch, None, revisions[0][1])
335
return RevisionInfo(branch, None, revisions[0])
338
# if get_rev_id supported negative revnos, there would not be a
339
# need for this special case.
329
340
if (-revno) >= len(revs):
365
376
prefix = 'revid:'
367
378
def _match_on(self, branch, revs):
369
revno = revs.index(self.spec) + 1
372
return RevisionInfo(branch, revno, self.spec)
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)
374
385
SPEC_TYPES.append(RevisionSpec_revid)
465
476
class RevisionSpec_tag(RevisionSpec):
466
"""To be implemented."""
468
help_txt = """To be implemented."""
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.
472
486
def _match_on(self, branch, revs):
473
raise errors.InvalidRevisionSpec(self.user_spec, branch,
474
'tag: namespace registered,'
475
' but not implemented')
487
# Can raise tags not supported, NoSuchTag, etc
488
return RevisionInfo.from_revision_id(branch,
489
branch.tags.lookup_tag(self.spec),
477
492
SPEC_TYPES.append(RevisionSpec_tag)
604
619
prefix = 'ancestor:'
606
621
def _match_on(self, branch, revs):
622
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):
607
627
from bzrlib.branch import Branch
609
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
610
other_branch = Branch.open(self.spec)
629
other_branch = Branch.open(other_location)
611
630
revision_a = branch.last_revision()
612
631
revision_b = other_branch.last_revision()
613
632
for r, b in ((revision_a, branch), (revision_b, other_branch)):
653
673
return RevisionInfo(branch, revno, revision_b)
655
675
SPEC_TYPES.append(RevisionSpec_branch)
678
class RevisionSpec_submit(RevisionSpec_ancestor):
679
"""Selects a common ancestor with a submit branch."""
681
help_txt = """Selects a common ancestor with the submit branch.
683
Diffing against this shows all the changes that were made in this branch,
684
and is a good predictor of what merge will do. The submit branch is
685
used by the bundle and merge directive comands. If no submit branch
686
is specified, the parent branch is used instead.
688
The common ancestor is the last revision that existed in both
689
branches. Usually this is the branch point, but it could also be
690
a revision that was merged.
693
$ bzr diff -r submit:
698
def _match_on(self, branch, revs):
699
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
700
submit_location = branch.get_submit_branch()
701
location_type = 'submit branch'
702
if submit_location is None:
703
submit_location = branch.get_parent()
704
location_type = 'parent branch'
705
if submit_location is None:
706
raise errors.NoSubmitBranch(branch)
707
trace.note('Using %s %s', location_type, submit_location)
708
return self._find_revision_info(branch, submit_location)
711
SPEC_TYPES.append(RevisionSpec_submit)