141
wants_revision_history = True
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)
144
149
def from_string(spec):
155
160
return RevisionSpec(None, _internal=True)
162
assert isinstance(spec, basestring), \
163
"You should only supply strings not %s" % (type(spec),)
156
165
for spectype in SPEC_TYPES:
157
166
if spec.startswith(spectype.prefix):
158
167
trace.mutter('Returning RevisionSpec %s for %s',
193
202
def _match_on(self, branch, revs):
194
203
trace.mutter('Returning RevisionSpec._match_on: None')
195
return RevisionInfo(branch, None, None)
204
return RevisionInfo(branch, 0, None)
197
206
def _match_on_and_check(self, branch, revs):
198
207
info = self._match_on(branch, revs)
201
elif info == (None, None):
202
# special case - nothing supplied
210
elif info == (0, None):
211
# special case - the empty tree
204
213
elif self.prefix:
205
214
raise errors.InvalidRevisionSpec(self.user_spec, branch)
227
233
# will do what you expect.
228
234
in_store = in_history
229
235
in_branch = in_store
231
def as_revision_id(self, context_branch):
232
"""Return just the revision_id for this revisions spec.
234
Some revision specs require a context_branch to be able to determine
235
their value. Not all specs will make use of it.
237
return self._as_revision_id(context_branch)
239
def _as_revision_id(self, context_branch):
240
"""Implementation of as_revision_id()
242
Classes should override this function to provide appropriate
243
functionality. The default is to just call '.in_history().rev_id'
245
return self.in_history(context_branch).rev_id
247
def as_tree(self, context_branch):
248
"""Return the tree object for this revisions spec.
250
Some revision specs require a context_branch to be able to determine
251
the revision id and access the repository. Not all specs will make
254
return self._as_tree(context_branch)
256
def _as_tree(self, context_branch):
257
"""Implementation of as_tree().
259
Classes should override this function to provide appropriate
260
functionality. The default is to just call '.as_revision_id()'
261
and get the revision tree from context_branch's repository.
263
revision_id = self.as_revision_id(context_branch)
264
return context_branch.repository.revision_tree(revision_id)
266
237
def __repr__(self):
267
238
# this is mostly for helping with testing
268
239
return '<%s %s>' % (self.__class__.__name__,
307
278
your history is very long.
309
280
prefix = 'revno:'
310
wants_revision_history = False
312
282
def _match_on(self, branch, revs):
313
283
"""Lookup a revision by revision number"""
314
branch, revno, revision_id = self._lookup(branch, revs)
315
return RevisionInfo(branch, revno, revision_id)
317
def _lookup(self, branch, revs_or_none):
318
284
loc = self.spec.find(':')
320
286
revno_spec = self.spec
363
331
if len(revisions) != 1:
364
return branch, None, None
332
return RevisionInfo(branch, None, None)
366
334
# there is no traditional 'revno' for dotted-decimal revnos.
367
335
# so for API compatability we return None.
368
return branch, None, revisions[0]
336
return RevisionInfo(branch, None, revisions[0])
370
last_revno, last_revision_id = branch.last_revision_info()
372
339
# if get_rev_id supported negative revnos, there would not be a
373
340
# need for this special case.
374
if (-revno) >= last_revno:
341
if (-revno) >= len(revs):
377
revno = last_revno + revno + 1
344
revno = len(revs) + revno + 1
379
revision_id = branch.get_rev_id(revno, revs_or_none)
346
revision_id = branch.get_rev_id(revno, revs)
380
347
except errors.NoSuchRevision:
381
348
raise errors.InvalidRevisionSpec(self.user_spec, branch)
382
return branch, revno, revision_id
384
def _as_revision_id(self, context_branch):
385
# We would have the revno here, but we don't really care
386
branch, revno, revision_id = self._lookup(context_branch, None)
349
return RevisionInfo(branch, revno, revision_id)
389
351
def needs_branch(self):
390
352
return self.spec.find(':') == -1
423
384
revision_id = osutils.safe_revision_id(self.spec, warn=False)
424
385
return RevisionInfo.from_revision_id(branch, revision_id, revs)
426
def _as_revision_id(self, context_branch):
427
return osutils.safe_revision_id(self.spec, warn=False)
429
387
SPEC_TYPES.append(RevisionSpec_revid)
441
399
last:1 -> return the last revision
442
400
last:3 -> return the revision 2 before the end.
447
405
def _match_on(self, branch, revs):
448
revno, revision_id = self._revno_and_revision_id(branch, revs)
449
return RevisionInfo(branch, revno, revision_id)
451
def _revno_and_revision_id(self, context_branch, revs_or_none):
452
last_revno, last_revision_id = context_branch.last_revision_info()
454
406
if self.spec == '':
456
raise errors.NoCommits(context_branch)
457
return last_revno, last_revision_id
408
raise errors.NoCommits(branch)
409
return RevisionInfo(branch, len(revs), revs[-1])
460
412
offset = int(self.spec)
461
413
except ValueError, e:
462
raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
414
raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
465
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
417
raise errors.InvalidRevisionSpec(self.user_spec, branch,
466
418
'you must supply a positive value')
468
revno = last_revno - offset + 1
419
revno = len(revs) - offset + 1
470
revision_id = context_branch.get_rev_id(revno, revs_or_none)
421
revision_id = branch.get_rev_id(revno, revs)
471
422
except errors.NoSuchRevision:
472
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
473
return revno, revision_id
475
def _as_revision_id(self, context_branch):
476
# We compute the revno as part of the process, but we don't really care
478
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)
481
426
SPEC_TYPES.append(RevisionSpec_last)
487
432
help_txt = """Selects the parent of the revision specified.
489
Supply any revision spec to return the parent of that revision. This is
490
mostly useful when inspecting revisions that are not in the revision history
434
Supply any revision spec to return the parent of that revision.
493
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.
497
441
before:1913 -> Return the parent of revno 1913 (revno 1912)
498
442
before:revid:aaaa@bbbb-1234567890 -> return the parent of revision
499
443
aaaa@bbbb-1234567890
500
bzr diff -r before:1913..1913
501
-> Find the changes between revision 1913 and its parent (1912).
502
(What changes did revision 1913 introduce).
503
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)
506
449
prefix = 'before:'
532
475
return RevisionInfo(branch, revno, revision_id)
534
def _as_revision_id(self, context_branch):
535
base_revspec = RevisionSpec.from_string(self.spec)
536
base_revision_id = base_revspec.as_revision_id(context_branch)
537
if base_revision_id == revision.NULL_REVISION:
538
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
539
'cannot go before the null: revision')
540
context_repo = context_branch.repository
541
context_repo.lock_read()
543
parent_map = context_repo.get_parent_map([base_revision_id])
545
context_repo.unlock()
546
if base_revision_id not in parent_map:
547
# Ghost, or unknown revision id
548
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
549
'cannot find the matching revision')
550
parents = parent_map[base_revision_id]
552
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
553
'No parents for revision.')
556
477
SPEC_TYPES.append(RevisionSpec_before)
711
629
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
712
630
return self._find_revision_info(branch, self.spec)
714
def _as_revision_id(self, context_branch):
715
return self._find_revision_id(context_branch, self.spec)
718
633
def _find_revision_info(branch, other_location):
719
revision_id = RevisionSpec_ancestor._find_revision_id(branch,
722
revno = branch.revision_id_to_revno(revision_id)
723
except errors.NoSuchRevision:
725
return RevisionInfo(branch, revno, revision_id)
728
def _find_revision_id(branch, other_location):
729
634
from bzrlib.branch import Branch
733
revision_a = revision.ensure_null(branch.last_revision())
734
if revision_a == revision.NULL_REVISION:
735
raise errors.NoCommits(branch)
736
other_branch = Branch.open(other_location)
737
other_branch.lock_read()
739
revision_b = revision.ensure_null(other_branch.last_revision())
740
if revision_b == revision.NULL_REVISION:
741
raise errors.NoCommits(other_branch)
742
graph = branch.repository.get_graph(other_branch.repository)
743
rev_id = graph.find_unique_lca(revision_a, revision_b)
745
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)
746
651
if rev_id == revision.NULL_REVISION:
747
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)
753
660
SPEC_TYPES.append(RevisionSpec_ancestor)
779
686
except errors.NoSuchRevision:
781
688
return RevisionInfo(branch, revno, revision_b)
783
def _as_revision_id(self, context_branch):
784
from bzrlib.branch import Branch
785
other_branch = Branch.open(self.spec)
786
last_revision = other_branch.last_revision()
787
last_revision = revision.ensure_null(last_revision)
788
context_branch.fetch(other_branch, last_revision)
789
if last_revision == revision.NULL_REVISION:
790
raise errors.NoCommits(other_branch)
793
def _as_tree(self, context_branch):
794
from bzrlib.branch import Branch
795
other_branch = Branch.open(self.spec)
796
last_revision = other_branch.last_revision()
797
last_revision = revision.ensure_null(last_revision)
798
if last_revision == revision.NULL_REVISION:
799
raise errors.NoCommits(other_branch)
800
return other_branch.repository.revision_tree(last_revision)
802
690
SPEC_TYPES.append(RevisionSpec_branch)
810
698
Diffing against this shows all the changes that were made in this branch,
811
699
and is a good predictor of what merge will do. The submit branch is
812
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
813
701
is specified, the parent branch is used instead.
815
703
The common ancestor is the last revision that existed in both
824
712
prefix = 'submit:'
826
def _get_submit_location(self, branch):
714
def _match_on(self, branch, revs):
715
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
827
716
submit_location = branch.get_submit_branch()
828
717
location_type = 'submit branch'
829
718
if submit_location is None:
832
721
if submit_location is None:
833
722
raise errors.NoSubmitBranch(branch)
834
723
trace.note('Using %s %s', location_type, submit_location)
835
return submit_location
837
def _match_on(self, branch, revs):
838
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
839
return self._find_revision_info(branch,
840
self._get_submit_location(branch))
842
def _as_revision_id(self, context_branch):
843
return self._find_revision_id(context_branch,
844
self._get_submit_location(context_branch))
724
return self._find_revision_info(branch, submit_location)
847
727
SPEC_TYPES.append(RevisionSpec_submit)