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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
20
 
from bzrlib.lazy_import import lazy_import
 
21
 
lazy_import(globals(), """
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
26
22
from bzrlib import (
 
 
122
119
    help_txt = """A parsed revision specification.
 
124
 
    A revision specification is a string, which may be unambiguous about
 
125
 
    what it represents by giving a prefix like 'date:' or 'revid:' etc,
 
126
 
    or it may have no prefix, in which case it's tried against several
 
127
 
    specifier types in sequence to determine what the user meant.
 
 
121
    A revision specification can be an integer, in which case it is
 
 
122
    assumed to be a revno (though this will translate negative values
 
 
123
    into positive ones); or it can be a string, in which case it is
 
 
124
    parsed for something like 'date:' or 'revid:' etc.
 
129
126
    Revision specs are an UI element, and they have been moved out
 
130
127
    of the branch class to leave "back-end" classes unaware of such
 
 
139
 
    wants_revision_history = True
 
140
 
    dwim_catchable_exceptions = (errors.InvalidRevisionSpec,)
 
141
 
    """Exceptions that RevisionSpec_dwim._match_on will catch.
 
143
 
    If the revspec is part of ``dwim_revspecs``, it may be tried with an
 
144
 
    invalid revspec and raises some exception. The exceptions mentioned here
 
145
 
    will not be reported to the user but simply ignored without stopping the
 
 
137
    def __new__(cls, spec, _internal=False):
 
 
139
            return object.__new__(cls, spec, _internal=_internal)
 
 
141
        symbol_versioning.warn('Creating a RevisionSpec directly has'
 
 
142
                               ' been deprecated in version 0.11. Use'
 
 
143
                               ' RevisionSpec.from_string()'
 
 
145
                               DeprecationWarning, stacklevel=2)
 
 
146
        return RevisionSpec.from_string(spec)
 
150
149
    def from_string(spec):
 
 
161
160
            return RevisionSpec(None, _internal=True)
 
162
 
        match = revspec_registry.get_prefix(spec)
 
163
 
        if match is not None:
 
164
 
            spectype, specsuffix = match
 
165
 
            trace.mutter('Returning RevisionSpec %s for %s',
 
166
 
                         spectype.__name__, spec)
 
167
 
            return spectype(spec, _internal=True)
 
 
162
        assert isinstance(spec, basestring), \
 
 
163
            "You should only supply strings not %s" % (type(spec),)
 
 
165
        for spectype in SPEC_TYPES:
 
 
166
            if spec.startswith(spectype.prefix):
 
 
167
                trace.mutter('Returning RevisionSpec %s for %s',
 
 
168
                             spectype.__name__, spec)
 
 
169
                return spectype(spec, _internal=True)
 
169
 
            for spectype in SPEC_TYPES:
 
170
 
                if spec.startswith(spectype.prefix):
 
171
 
                    trace.mutter('Returning RevisionSpec %s for %s',
 
172
 
                                 spectype.__name__, spec)
 
173
 
                    return spectype(spec, _internal=True)
 
174
 
            # Otherwise treat it as a DWIM, build the RevisionSpec object and
 
175
 
            # wait for _match_on to be called.
 
176
 
            return RevisionSpec_dwim(spec, _internal=True)
 
 
171
            # RevisionSpec_revno is special cased, because it is the only
 
 
172
            # one that directly handles plain integers
 
 
173
            # TODO: This should not be special cased rather it should be
 
 
174
            # a method invocation on spectype.canparse()
 
 
176
            if _revno_regex is None:
 
 
177
                _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
 
 
178
            if _revno_regex.match(spec) is not None:
 
 
179
                return RevisionSpec_revno(spec, _internal=True)
 
 
181
            raise errors.NoSuchRevisionSpec(spec)
 
178
183
    def __init__(self, spec, _internal=False):
 
179
184
        """Create a RevisionSpec referring to the Null revision.
 
 
196
202
    def _match_on(self, branch, revs):
 
197
203
        trace.mutter('Returning RevisionSpec._match_on: None')
 
198
 
        return RevisionInfo(branch, None, None)
 
 
204
        return RevisionInfo(branch, 0, None)
 
200
206
    def _match_on_and_check(self, branch, revs):
 
201
207
        info = self._match_on(branch, revs)
 
204
 
        elif info == (None, None):
 
205
 
            # special case - nothing supplied
 
 
210
        elif info == (0, None):
 
 
211
            # special case - the empty tree
 
207
213
        elif self.prefix:
 
208
214
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
 
230
233
    # will do what you expect.
 
231
234
    in_store = in_history
 
232
235
    in_branch = in_store
 
234
 
    def as_revision_id(self, context_branch):
 
235
 
        """Return just the revision_id for this revisions spec.
 
237
 
        Some revision specs require a context_branch to be able to determine
 
238
 
        their value. Not all specs will make use of it.
 
240
 
        return self._as_revision_id(context_branch)
 
242
 
    def _as_revision_id(self, context_branch):
 
243
 
        """Implementation of as_revision_id()
 
245
 
        Classes should override this function to provide appropriate
 
246
 
        functionality. The default is to just call '.in_history().rev_id'
 
248
 
        return self.in_history(context_branch).rev_id
 
250
 
    def as_tree(self, context_branch):
 
251
 
        """Return the tree object for this revisions spec.
 
253
 
        Some revision specs require a context_branch to be able to determine
 
254
 
        the revision id and access the repository. Not all specs will make
 
257
 
        return self._as_tree(context_branch)
 
259
 
    def _as_tree(self, context_branch):
 
260
 
        """Implementation of as_tree().
 
262
 
        Classes should override this function to provide appropriate
 
263
 
        functionality. The default is to just call '.as_revision_id()'
 
264
 
        and get the revision tree from context_branch's repository.
 
266
 
        revision_id = self.as_revision_id(context_branch)
 
267
 
        return context_branch.repository.revision_tree(revision_id)
 
269
237
    def __repr__(self):
 
270
238
        # this is mostly for helping with testing
 
271
239
        return '<%s %s>' % (self.__class__.__name__,
 
274
242
    def needs_branch(self):
 
275
243
        """Whether this revision spec needs a branch.
 
 
291
 
class RevisionSpec_dwim(RevisionSpec):
 
292
 
    """Provides a DWIMish revision specifier lookup.
 
294
 
    Note that this does not go in the revspec_registry because by definition
 
295
 
    there is no prefix to identify it.  It's solely called from
 
296
 
    RevisionSpec.from_string() because the DWIMification happen when _match_on
 
297
 
    is called so the string describing the revision is kept here until needed.
 
301
 
    # We don't need to build the revision history ourself, that's delegated to
 
302
 
    # each revspec we try.
 
303
 
    wants_revision_history = False
 
305
 
    def _try_spectype(self, rstype, branch):
 
306
 
        rs = rstype(self.spec, _internal=True)
 
307
 
        # Hit in_history to find out if it exists, or we need to try the
 
309
 
        return rs.in_history(branch)
 
311
 
    def _match_on(self, branch, revs):
 
312
 
        """Run the lookup and see what we can get."""
 
314
 
        # First, see if it's a revno
 
316
 
        if _revno_regex is None:
 
317
 
            _revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
 
318
 
        if _revno_regex.match(self.spec) is not None:
 
320
 
                return self._try_spectype(RevisionSpec_revno, branch)
 
321
 
            except RevisionSpec_revno.dwim_catchable_exceptions:
 
324
 
        # Next see what has been registered
 
325
 
        for rs_class in dwim_revspecs:
 
327
 
                return self._try_spectype(rs_class, branch)
 
328
 
            except rs_class.dwim_catchable_exceptions:
 
331
 
        # Well, I dunno what it is. Note that we don't try to keep track of the
 
332
 
        # first of last exception raised during the DWIM tries as none seems
 
334
 
        raise errors.InvalidRevisionSpec(self.spec, branch)
 
337
259
class RevisionSpec_revno(RevisionSpec):
 
338
260
    """Selects a revision using a number."""
 
340
262
    help_txt = """Selects a revision using a number.
 
342
264
    Use an integer to specify a revision in the history of the branch.
 
343
 
    Optionally a branch can be specified.  A negative number will count
 
344
 
    from the end of the branch (-1 is the last revision, -2 the previous
 
345
 
    one). If the negative number is larger than the branch's history, the
 
346
 
    first revision is returned.
 
 
265
    Optionally a branch can be specified. The 'revno:' prefix is optional.
 
 
266
    A negative number will count from the end of the branch (-1 is the
 
 
267
    last revision, -2 the previous one). If the negative number is larger
 
 
268
    than the branch's history, the first revision is returned.
 
349
 
      revno:1                   -> return the first revision of this branch
 
 
271
      revno:1                   -> return the first revision
 
350
272
      revno:3:/path/to/branch   -> return the 3rd revision of
 
351
273
                                   the branch '/path/to/branch'
 
352
274
      revno:-1                  -> The last revision in a branch.
 
 
356
278
                                   your history is very long.
 
358
280
    prefix = 'revno:'
 
359
 
    wants_revision_history = False
 
361
282
    def _match_on(self, branch, revs):
 
362
283
        """Lookup a revision by revision number"""
 
363
 
        branch, revno, revision_id = self._lookup(branch, revs)
 
364
 
        return RevisionInfo(branch, revno, revision_id)
 
366
 
    def _lookup(self, branch, revs_or_none):
 
367
284
        loc = self.spec.find(':')
 
369
286
            revno_spec = self.spec
 
 
398
315
            # the branch object.
 
399
316
            from bzrlib.branch import Branch
 
400
317
            branch = Branch.open(branch_spec)
 
 
318
            # Need to use a new revision history
 
 
319
            # because we are using a specific branch
 
 
320
            revs = branch.revision_history()
 
405
 
                revision_id = branch.dotted_revno_to_revision_id(match_revno,
 
407
 
            except errors.NoSuchRevision:
 
408
 
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
 
325
                revision_id_to_revno = branch.get_revision_id_to_revno_map()
 
 
326
                revisions = [revision_id for revision_id, revno
 
 
327
                             in revision_id_to_revno.iteritems()
 
 
328
                             if revno == match_revno]
 
 
331
            if len(revisions) != 1:
 
 
332
                return RevisionInfo(branch, None, None)
 
410
334
                # there is no traditional 'revno' for dotted-decimal revnos.
 
411
335
                # so for  API compatability we return None.
 
412
 
                return branch, None, revision_id
 
 
336
                return RevisionInfo(branch, None, revisions[0])
 
414
 
            last_revno, last_revision_id = branch.last_revision_info()
 
416
339
                # if get_rev_id supported negative revnos, there would not be a
 
417
340
                # need for this special case.
 
418
 
                if (-revno) >= last_revno:
 
 
341
                if (-revno) >= len(revs):
 
421
 
                    revno = last_revno + revno + 1
 
 
344
                    revno = len(revs) + revno + 1
 
423
 
                revision_id = branch.get_rev_id(revno, revs_or_none)
 
 
346
                revision_id = branch.get_rev_id(revno, revs)
 
424
347
            except errors.NoSuchRevision:
 
425
348
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
426
 
        return branch, revno, revision_id
 
428
 
    def _as_revision_id(self, context_branch):
 
429
 
        # We would have the revno here, but we don't really care
 
430
 
        branch, revno, revision_id = self._lookup(context_branch, None)
 
 
349
        return RevisionInfo(branch, revno, revision_id)
 
433
351
    def needs_branch(self):
 
434
352
        return self.spec.find(':') == -1
 
 
450
369
    help_txt = """Selects a revision using the revision id.
 
452
371
    Supply a specific revision id, that can be used to specify any
 
453
 
    revision id in the ancestry of the branch.
 
 
372
    revision id in the ancestry of the branch. 
 
454
373
    Including merges, and pending merges.
 
457
376
      revid:aaaa@bbbb-123456789 -> Select revision 'aaaa@bbbb-123456789'
 
460
378
    prefix = 'revid:'
 
462
380
    def _match_on(self, branch, revs):
 
 
466
384
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
 
467
385
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
 
469
 
    def _as_revision_id(self, context_branch):
 
470
 
        return osutils.safe_revision_id(self.spec, warn=False)
 
 
387
SPEC_TYPES.append(RevisionSpec_revid)
 
474
390
class RevisionSpec_last(RevisionSpec):
 
 
483
399
      last:1        -> return the last revision
 
484
400
      last:3        -> return the revision 2 before the end.
 
489
405
    def _match_on(self, branch, revs):
 
490
 
        revno, revision_id = self._revno_and_revision_id(branch, revs)
 
491
 
        return RevisionInfo(branch, revno, revision_id)
 
493
 
    def _revno_and_revision_id(self, context_branch, revs_or_none):
 
494
 
        last_revno, last_revision_id = context_branch.last_revision_info()
 
496
406
        if self.spec == '':
 
498
 
                raise errors.NoCommits(context_branch)
 
499
 
            return last_revno, last_revision_id
 
 
408
                raise errors.NoCommits(branch)
 
 
409
            return RevisionInfo(branch, len(revs), revs[-1])
 
502
412
            offset = int(self.spec)
 
503
413
        except ValueError, e:
 
504
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
 
 
414
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
 
507
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
 
417
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
 
508
418
                                             'you must supply a positive value')
 
510
 
        revno = last_revno - offset + 1
 
 
419
        revno = len(revs) - offset + 1
 
512
 
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
 
 
421
            revision_id = branch.get_rev_id(revno, revs)
 
513
422
        except errors.NoSuchRevision:
 
514
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
515
 
        return revno, revision_id
 
517
 
    def _as_revision_id(self, context_branch):
 
518
 
        # We compute the revno as part of the process, but we don't really care
 
520
 
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
 
 
423
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
 
424
        return RevisionInfo(branch, revno, revision_id)
 
 
426
SPEC_TYPES.append(RevisionSpec_last)
 
525
429
class RevisionSpec_before(RevisionSpec):
 
 
528
432
    help_txt = """Selects the parent of the revision specified.
 
530
 
    Supply any revision spec to return the parent of that revision.  This is
 
531
 
    mostly useful when inspecting revisions that are not in the revision history
 
 
434
    Supply any revision spec to return the parent of that revision.
 
534
435
    It is an error to request the parent of the null revision (before:0).
 
 
436
    This is mostly useful when inspecting revisions that are not in the
 
 
437
    revision history of a branch.
 
538
441
      before:1913    -> Return the parent of revno 1913 (revno 1912)
 
539
442
      before:revid:aaaa@bbbb-1234567890  -> return the parent of revision
 
540
443
                                            aaaa@bbbb-1234567890
 
541
 
      bzr diff -r before:1913..1913
 
542
 
            -> Find the changes between revision 1913 and its parent (1912).
 
543
 
               (What changes did revision 1913 introduce).
 
544
 
               This is equivalent to:  bzr diff -c 1913
 
 
444
      bzr diff -r before:revid:aaaa..revid:aaaa
 
 
445
            -> Find the changes between revision 'aaaa' and its parent.
 
 
446
               (what changes did 'aaaa' introduce)
 
547
449
    prefix = 'before:'
 
549
451
    def _match_on(self, branch, revs):
 
550
452
        r = RevisionSpec.from_string(self.spec)._match_on(branch, revs)
 
 
573
475
        return RevisionInfo(branch, revno, revision_id)
 
575
 
    def _as_revision_id(self, context_branch):
 
576
 
        base_revspec = RevisionSpec.from_string(self.spec)
 
577
 
        base_revision_id = base_revspec.as_revision_id(context_branch)
 
578
 
        if base_revision_id == revision.NULL_REVISION:
 
579
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
580
 
                                         'cannot go before the null: revision')
 
581
 
        context_repo = context_branch.repository
 
582
 
        context_repo.lock_read()
 
584
 
            parent_map = context_repo.get_parent_map([base_revision_id])
 
586
 
            context_repo.unlock()
 
587
 
        if base_revision_id not in parent_map:
 
588
 
            # Ghost, or unknown revision id
 
589
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
590
 
                'cannot find the matching revision')
 
591
 
        parents = parent_map[base_revision_id]
 
593
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
594
 
                'No parents for revision.')
 
 
477
SPEC_TYPES.append(RevisionSpec_before)
 
599
480
class RevisionSpec_tag(RevisionSpec):
 
 
650
528
    One way to display all the changes since yesterday would be::
 
652
 
        bzr log -r date:yesterday..
 
 
530
        bzr log -r date:yesterday..-1
 
656
534
      date:yesterday            -> select the first revision since yesterday
 
657
535
      date:2006-08-14,17:10:14  -> select the first revision after
 
658
536
                                   August 14th, 2006 at 5:10pm.
 
661
539
    _date_re = re.compile(
 
662
540
            r'(?P<date>(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d))?'
 
 
750
629
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
751
630
        return self._find_revision_info(branch, self.spec)
 
753
 
    def _as_revision_id(self, context_branch):
 
754
 
        return self._find_revision_id(context_branch, self.spec)
 
757
633
    def _find_revision_info(branch, other_location):
 
758
 
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
 
761
 
            revno = branch.revision_id_to_revno(revision_id)
 
762
 
        except errors.NoSuchRevision:
 
764
 
        return RevisionInfo(branch, revno, revision_id)
 
767
 
    def _find_revision_id(branch, other_location):
 
768
634
        from bzrlib.branch import Branch
 
772
 
            revision_a = revision.ensure_null(branch.last_revision())
 
773
 
            if revision_a == revision.NULL_REVISION:
 
774
 
                raise errors.NoCommits(branch)
 
775
 
            if other_location == '':
 
776
 
                other_location = branch.get_parent()
 
777
 
            other_branch = Branch.open(other_location)
 
778
 
            other_branch.lock_read()
 
780
 
                revision_b = revision.ensure_null(other_branch.last_revision())
 
781
 
                if revision_b == revision.NULL_REVISION:
 
782
 
                    raise errors.NoCommits(other_branch)
 
783
 
                graph = branch.repository.get_graph(other_branch.repository)
 
784
 
                rev_id = graph.find_unique_lca(revision_a, revision_b)
 
786
 
                other_branch.unlock()
 
 
636
        other_branch = Branch.open(other_location)
 
 
637
        revision_a = branch.last_revision()
 
 
638
        revision_b = other_branch.last_revision()
 
 
639
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
 
 
640
            if r in (None, revision.NULL_REVISION):
 
 
641
                raise errors.NoCommits(b)
 
 
642
        revision_source = revision.MultipleRevisionSources(
 
 
643
                branch.repository, other_branch.repository)
 
 
644
        graph = branch.repository.get_graph(other_branch.repository)
 
 
645
        revision_a = revision.ensure_null(revision_a)
 
 
646
        revision_b = revision.ensure_null(revision_b)
 
 
647
        if revision.NULL_REVISION in (revision_a, revision_b):
 
 
648
            rev_id = revision.NULL_REVISION
 
 
650
            rev_id = graph.find_unique_lca(revision_a, revision_b)
 
787
651
            if rev_id == revision.NULL_REVISION:
 
788
652
                raise errors.NoCommonAncestor(revision_a, revision_b)
 
 
654
            revno = branch.revision_id_to_revno(rev_id)
 
 
655
        except errors.NoSuchRevision:
 
 
657
        return RevisionInfo(branch, revno, rev_id)
 
 
660
SPEC_TYPES.append(RevisionSpec_ancestor)
 
796
663
class RevisionSpec_branch(RevisionSpec):
 
 
820
686
        except errors.NoSuchRevision:
 
822
688
        return RevisionInfo(branch, revno, revision_b)
 
824
 
    def _as_revision_id(self, context_branch):
 
825
 
        from bzrlib.branch import Branch
 
826
 
        other_branch = Branch.open(self.spec)
 
827
 
        last_revision = other_branch.last_revision()
 
828
 
        last_revision = revision.ensure_null(last_revision)
 
829
 
        context_branch.fetch(other_branch, last_revision)
 
830
 
        if last_revision == revision.NULL_REVISION:
 
831
 
            raise errors.NoCommits(other_branch)
 
834
 
    def _as_tree(self, context_branch):
 
835
 
        from bzrlib.branch import Branch
 
836
 
        other_branch = Branch.open(self.spec)
 
837
 
        last_revision = other_branch.last_revision()
 
838
 
        last_revision = revision.ensure_null(last_revision)
 
839
 
        if last_revision == revision.NULL_REVISION:
 
840
 
            raise errors.NoCommits(other_branch)
 
841
 
        return other_branch.repository.revision_tree(last_revision)
 
 
690
SPEC_TYPES.append(RevisionSpec_branch)
 
845
693
class RevisionSpec_submit(RevisionSpec_ancestor):
 
 
850
698
    Diffing against this shows all the changes that were made in this branch,
 
851
699
    and is a good predictor of what merge will do.  The submit branch is
 
852
 
    used by the bundle and merge directive commands.  If no submit branch
 
 
700
    used by the bundle and merge directive comands.  If no submit branch
 
853
701
    is specified, the parent branch is used instead.
 
855
703
    The common ancestor is the last revision that existed in both
 
 
864
712
    prefix = 'submit:'
 
866
 
    def _get_submit_location(self, branch):
 
 
714
    def _match_on(self, branch, revs):
 
 
715
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
867
716
        submit_location = branch.get_submit_branch()
 
868
717
        location_type = 'submit branch'
 
869
718
        if submit_location is None:
 
 
872
721
        if submit_location is None:
 
873
722
            raise errors.NoSubmitBranch(branch)
 
874
723
        trace.note('Using %s %s', location_type, submit_location)
 
875
 
        return submit_location
 
877
 
    def _match_on(self, branch, revs):
 
878
 
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
879
 
        return self._find_revision_info(branch,
 
880
 
            self._get_submit_location(branch))
 
882
 
    def _as_revision_id(self, context_branch):
 
883
 
        return self._find_revision_id(context_branch,
 
884
 
            self._get_submit_location(context_branch))
 
887
 
# The order in which we want to DWIM a revision spec without any prefix.
 
888
 
# revno is always tried first and isn't listed here, this is used by
 
889
 
# RevisionSpec_dwim._match_on
 
891
 
    RevisionSpec_tag, # Let's try for a tag
 
892
 
    RevisionSpec_revid, # Maybe it's a revid?
 
893
 
    RevisionSpec_date, # Perhaps a date?
 
894
 
    RevisionSpec_branch, # OK, last try, maybe it's a branch
 
898
 
revspec_registry = registry.Registry()
 
899
 
def _register_revspec(revspec):
 
900
 
    revspec_registry.register(revspec.prefix, revspec)
 
902
 
_register_revspec(RevisionSpec_revno)
 
903
 
_register_revspec(RevisionSpec_revid)
 
904
 
_register_revspec(RevisionSpec_last)
 
905
 
_register_revspec(RevisionSpec_before)
 
906
 
_register_revspec(RevisionSpec_tag)
 
907
 
_register_revspec(RevisionSpec_date)
 
908
 
_register_revspec(RevisionSpec_ancestor)
 
909
 
_register_revspec(RevisionSpec_branch)
 
910
 
_register_revspec(RevisionSpec_submit)
 
912
 
# classes in this list should have a "prefix" attribute, against which
 
913
 
# string specs are matched
 
914
 
SPEC_TYPES = symbol_versioning.deprecated_list(
 
915
 
    symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])
 
 
724
        return self._find_revision_info(branch, submit_location)
 
 
727
SPEC_TYPES.append(RevisionSpec_submit)