##// END OF EJS Templates
filectx.parents: enforce changeid of parent to be in own changectx ancestors...
Pierre-Yves David -
r23702:c4892478 default
parent child Browse files
Show More
@@ -22,6 +22,40 b' propertycache = util.propertycache'
22 # dirty in the working copy.
22 # dirty in the working copy.
23 _newnode = '!' * 21
23 _newnode = '!' * 21
24
24
25 def _adjustlinkrev(repo, path, filelog, fnode, srcrev):
26 """return the first ancestor of <srcrev> introducting <fnode>
27
28 If the linkrev of the file revision does not point to an ancestor of
29 srcrev, we'll walk down the ancestors until we find one introducing this
30 file revision.
31
32 :repo: a localrepository object (used to access changelog and manifest)
33 :path: the file path
34 :fnode: the nodeid of the file revision
35 :filelog: the filelog of this path
36 :srcrev: the changeset revision we search ancestors from
37 """
38 cl = repo.unfiltered().changelog
39 ma = repo.manifest
40 # fetch the linkrev
41 fr = filelog.rev(fnode)
42 lkr = filelog.linkrev(fr)
43 # check if this linkrev is an ancestor of srcrev
44 anc = cl.ancestors([srcrev], lkr)
45 if lkr not in anc:
46 for a in anc:
47 ac = cl.read(a) # get changeset data (we avoid object creation).
48 if path in ac[3]: # checking the 'files' field.
49 # The file has been touched, check if the content is similar
50 # to the one we search for.
51 if fnode == ma.readdelta(ac[0]).get(path):
52 return a
53 # In theory, we should never get out of that loop without a result. But
54 # if manifest uses a buggy file revision (not children of the one it
55 # replaces) we could. Such a buggy situation will likely result is crash
56 # somewhere else at to some point.
57 return lkr
58
25 class basectx(object):
59 class basectx(object):
26 """A basectx object represents the common logic for its children:
60 """A basectx object represents the common logic for its children:
27 changectx: read-only context that is already present in the repo,
61 changectx: read-only context that is already present in the repo,
@@ -739,7 +773,7 b' class basefilectx(object):'
739 parents = self._filelog.parents(self._filenode)
773 parents = self._filelog.parents(self._filenode)
740 pl = [(_path, node, fl) for node in parents if node != nullid]
774 pl = [(_path, node, fl) for node in parents if node != nullid]
741
775
742 r = self._filelog.renamed(self._filenode)
776 r = fl.renamed(self._filenode)
743 if r:
777 if r:
744 # - In the simple rename case, both parent are nullid, pl is empty.
778 # - In the simple rename case, both parent are nullid, pl is empty.
745 # - In case of merge, only one of the parent is null id and should
779 # - In case of merge, only one of the parent is null id and should
@@ -751,7 +785,19 b' class basefilectx(object):'
751 # first nullid parent with rename information.
785 # first nullid parent with rename information.
752 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
786 pl.insert(0, (r[0], r[1], self._repo.file(r[0])))
753
787
754 return [filectx(self._repo, p, fileid=n, filelog=l) for p, n, l in pl]
788 ret = []
789 for path, fnode, l in pl:
790 if '_changeid' in vars(self) or '_changectx' in vars(self):
791 # If self is associated with a changeset (probably explicitly
792 # fed), ensure the created filectx is associated with a
793 # changeset that is an ancestor of self.changectx.
794 rev = _adjustlinkrev(self._repo, path, l, fnode, self.rev())
795 fctx = filectx(self._repo, path, fileid=fnode, filelog=l,
796 changeid=rev)
797 else:
798 fctx = filectx(self._repo, path, fileid=fnode, filelog=l)
799 ret.append(fctx)
800 return ret
755
801
756 def p1(self):
802 def p1(self):
757 return self.parents()[0]
803 return self.parents()[0]
@@ -451,3 +451,63 b' Annotate with --ignore-blank-lines (simi'
451 1: b b
451 1: b b
452
452
453 $ cd ..
453 $ cd ..
454
455 Annotate with linkrev pointing to another branch
456 ------------------------------------------------
457
458 create history with a filerev whose linkrev points to another branch
459
460 $ hg init branchedlinkrev
461 $ cd branchedlinkrev
462 $ echo A > a
463 $ hg commit -Am 'contentA'
464 adding a
465 $ echo B >> a
466 $ hg commit -m 'contentB'
467 $ hg up --rev 'desc(contentA)'
468 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 $ echo unrelated > unrelated
470 $ hg commit -Am 'unrelated'
471 adding unrelated
472 created new head
473 $ hg graft -r 'desc(contentB)'
474 grafting 1:fd27c222e3e6 "contentB"
475 $ echo C >> a
476 $ hg commit -m 'contentC'
477 $ hg log -G
478 @ changeset: 4:072f1e8df249
479 | tag: tip
480 | user: test
481 | date: Thu Jan 01 00:00:00 1970 +0000
482 | summary: contentC
483 |
484 o changeset: 3:ff38df03cc4b
485 | user: test
486 | date: Thu Jan 01 00:00:00 1970 +0000
487 | summary: contentB
488 |
489 o changeset: 2:62aaf3f6fc06
490 | parent: 0:f0932f74827e
491 | user: test
492 | date: Thu Jan 01 00:00:00 1970 +0000
493 | summary: unrelated
494 |
495 | o changeset: 1:fd27c222e3e6
496 |/ user: test
497 | date: Thu Jan 01 00:00:00 1970 +0000
498 | summary: contentB
499 |
500 o changeset: 0:f0932f74827e
501 user: test
502 date: Thu Jan 01 00:00:00 1970 +0000
503 summary: contentA
504
505
506 Annotate should list ancestor of starting revision only
507
508 $ hg annotate a
509 0: A
510 3: B
511 4: C
512
513 $ cd ..
@@ -1564,3 +1564,96 b' hg log -f dir across branches'
1564 o a
1564 o a
1565
1565
1566 $ cd ..
1566 $ cd ..
1567
1568 hg log -f with linkrev pointing to another branch
1569 -------------------------------------------------
1570
1571 create history with a filerev whose linkrev points to another branch
1572
1573 $ hg init branchedlinkrev
1574 $ cd branchedlinkrev
1575 $ echo 1 > a
1576 $ hg commit -Am 'content1'
1577 adding a
1578 $ echo 2 > a
1579 $ hg commit -m 'content2'
1580 $ hg up --rev 'desc(content1)'
1581 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1582 $ echo unrelated > unrelated
1583 $ hg commit -Am 'unrelated'
1584 adding unrelated
1585 created new head
1586 $ hg graft -r 'desc(content2)'
1587 grafting 1:2294ae80ad84 "content2"
1588 $ echo 3 > a
1589 $ hg commit -m 'content3'
1590 $ hg log -G
1591 @ changeset: 4:50b9b36e9c5d
1592 | tag: tip
1593 | user: test
1594 | date: Thu Jan 01 00:00:00 1970 +0000
1595 | summary: content3
1596 |
1597 o changeset: 3:15b2327059e5
1598 | user: test
1599 | date: Thu Jan 01 00:00:00 1970 +0000
1600 | summary: content2
1601 |
1602 o changeset: 2:2029acd1168c
1603 | parent: 0:ae0a3c9f9e95
1604 | user: test
1605 | date: Thu Jan 01 00:00:00 1970 +0000
1606 | summary: unrelated
1607 |
1608 | o changeset: 1:2294ae80ad84
1609 |/ user: test
1610 | date: Thu Jan 01 00:00:00 1970 +0000
1611 | summary: content2
1612 |
1613 o changeset: 0:ae0a3c9f9e95
1614 user: test
1615 date: Thu Jan 01 00:00:00 1970 +0000
1616 summary: content1
1617
1618
1619 log -f on the file should list the graft result.
1620
1621 $ hg log -Gf a
1622 @ changeset: 4:50b9b36e9c5d
1623 | tag: tip
1624 | user: test
1625 | date: Thu Jan 01 00:00:00 1970 +0000
1626 | summary: content3
1627 |
1628 o changeset: 3:15b2327059e5
1629 | user: test
1630 | date: Thu Jan 01 00:00:00 1970 +0000
1631 | summary: content2
1632 |
1633 o changeset: 0:ae0a3c9f9e95
1634 user: test
1635 date: Thu Jan 01 00:00:00 1970 +0000
1636 summary: content1
1637
1638
1639 plain log lists the original version
1640 (XXX we should probably list both)
1641
1642 $ hg log -G a
1643 @ changeset: 4:50b9b36e9c5d
1644 | tag: tip
1645 | user: test
1646 | date: Thu Jan 01 00:00:00 1970 +0000
1647 | summary: content3
1648 |
1649 | o changeset: 1:2294ae80ad84
1650 |/ user: test
1651 | date: Thu Jan 01 00:00:00 1970 +0000
1652 | summary: content2
1653 |
1654 o changeset: 0:ae0a3c9f9e95
1655 user: test
1656 date: Thu Jan 01 00:00:00 1970 +0000
1657 summary: content1
1658
1659 $ cd ..
@@ -1605,3 +1605,65 b" test for case where we didn't look suffi"
1605 -
1605 -
1606 +f
1606 +f
1607 $ cd ..
1607 $ cd ..
1608
1609 Additional tricky linkrev case
1610 ------------------------------
1611
1612 If the first file revision after the diff base has a linkrev pointing to a
1613 changeset on another branch with a revision lower that the diff base, we can
1614 jump past the copy detection limit and fail to detect the rename.
1615
1616 $ hg init diffstoplinkrev
1617 $ cd diffstoplinkrev
1618
1619 $ touch f
1620 $ hg ci -Aqm 'empty f'
1621
1622 Make a simple change
1623
1624 $ echo change > f
1625 $ hg ci -m 'change f'
1626
1627 Make a second branch, we use a named branch to create a simple commit
1628 that does not touch f.
1629
1630 $ hg up -qr 'desc(empty)'
1631 $ hg branch -q dev
1632 $ hg ci -Aqm dev
1633
1634 Graft the initial change, as f was untouched, we reuse the same entry and the
1635 linkrev point to the older branch.
1636
1637 $ hg graft -q 'desc(change)'
1638
1639 Make a rename because we want to track renames. It is also important that the
1640 faulty linkrev is not the "start" commit to ensure the linkrev will be used.
1641
1642 $ hg mv f renamed
1643 $ hg ci -m renamed
1644
1645 $ hg log -G -T '{rev} {desc}'
1646 @ 4 renamed
1647 |
1648 o 3 change f
1649 |
1650 o 2 dev
1651 |
1652 | o 1 change f
1653 |/
1654 o 0 empty f
1655
1656
1657 The copy tracking should still reach rev 2 (branch creation).
1658 accessing the parent of 4 (renamed) should not jump use to revision 1.
1659
1660 $ hg diff --git -r 'desc(dev)' -r .
1661 diff --git a/f b/renamed
1662 rename from f
1663 rename to renamed
1664 --- a/f
1665 +++ b/renamed
1666 @@ -0,0 +1,1 @@
1667 +change
1668
1669 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now