Mercurial > jhg
comparison src/org/tmatesoft/hg/core/HgLogCommand.java @ 528:f7fbf48b9383
Report rename when walking file history regardless of followRenames parameter, solely based on HgFileRenameHandlerMixin presence
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 17 Jan 2013 19:23:52 +0100 |
parents | 2f9ed6bcefa2 |
children | 6ca3d0c5b4bc |
comparison
equal
deleted
inserted
replaced
527:47b7bedf0569 | 528:f7fbf48b9383 |
---|---|
341 } | 341 } |
342 } | 342 } |
343 } else { | 343 } else { |
344 filterInsp.delegateTo(csetTransform); | 344 filterInsp.delegateTo(csetTransform); |
345 final HgFileRenameHandlerMixin withCopyHandler = Adaptable.Factory.getAdapter(handler, HgFileRenameHandlerMixin.class, null); | 345 final HgFileRenameHandlerMixin withCopyHandler = Adaptable.Factory.getAdapter(handler, HgFileRenameHandlerMixin.class, null); |
346 List<Pair<HgDataFile, Nodeid>> fileRenames = buildFileRenamesQueue(); | 346 FileRenameQueueBuilder frqBuilder = new FileRenameQueueBuilder(); |
347 progressHelper.start(-1/*XXX enum const, or a dedicated method startUnspecified(). How about startAtLeast(int)?*/); | 347 List<Pair<HgDataFile, Nodeid>> fileRenames = frqBuilder.buildFileRenamesQueue(); |
348 | 348 progressHelper.start(fileRenames.size()); |
349 for (int nameIndex = 0, fileRenamesSize = fileRenames.size(); nameIndex < fileRenamesSize; nameIndex++) { | 349 for (int nameIndex = 0, fileRenamesSize = fileRenames.size(); nameIndex < fileRenamesSize; nameIndex++) { |
350 Pair<HgDataFile, Nodeid> curRename = fileRenames.get(nameIndex); | 350 Pair<HgDataFile, Nodeid> curRename = fileRenames.get(nameIndex); |
351 HgDataFile fileNode = curRename.first(); | 351 HgDataFile fileNode = curRename.first(); |
352 if (followAncestry) { | 352 if (followAncestry) { |
353 TreeBuildInspector treeBuilder = new TreeBuildInspector(followAncestry); | 353 TreeBuildInspector treeBuilder = new TreeBuildInspector(followAncestry); |
386 } | 386 } |
387 batchInspector.reset(); | 387 batchInspector.reset(); |
388 } | 388 } |
389 } | 389 } |
390 } | 390 } |
391 if (followRenames && withCopyHandler != null && nameIndex + 1 < fileRenamesSize) { | 391 if (withCopyHandler != null && nameIndex + 1 < fileRenamesSize) { |
392 Pair<HgDataFile, Nodeid> nextRename = fileRenames.get(nameIndex+1); | 392 Pair<HgDataFile, Nodeid> nextRename = fileRenames.get(nameIndex+1); |
393 HgFileRevision src, dst; | 393 HgFileRevision src, dst; |
394 // A -> B | 394 // A -> B |
395 if (iterateDirection == HgIterateDirection.OldToNew) { | 395 if (iterateDirection == HgIterateDirection.OldToNew) { |
396 // curRename: A, nextRename: B | 396 // curRename: A, nextRename: B |
402 src = new HgFileRevision(nextRename.first(), nextRename.second(), null); | 402 src = new HgFileRevision(nextRename.first(), nextRename.second(), null); |
403 dst = new HgFileRevision(fileNode, fileNode.getRevision(0), src.getPath()); | 403 dst = new HgFileRevision(fileNode, fileNode.getRevision(0), src.getPath()); |
404 } | 404 } |
405 withCopyHandler.copy(src, dst); | 405 withCopyHandler.copy(src, dst); |
406 } | 406 } |
407 progressHelper.worked(1); | |
407 } // for renames | 408 } // for renames |
409 frqBuilder.reportRenameIfNotInQueue(fileRenames, withCopyHandler); | |
408 } // file != null | 410 } // file != null |
409 } catch (HgRuntimeException ex) { | 411 } catch (HgRuntimeException ex) { |
410 throw new HgLibraryFailureException(ex); | 412 throw new HgLibraryFailureException(ex); |
411 } finally { | 413 } finally { |
412 csetTransform = null; | 414 csetTransform = null; |
529 } | 531 } |
530 }; | 532 }; |
531 | 533 |
532 // renamed files in the queue are placed with respect to #iterateDirection | 534 // renamed files in the queue are placed with respect to #iterateDirection |
533 // i.e. if we iterate from new to old, recent filenames come first | 535 // i.e. if we iterate from new to old, recent filenames come first |
534 List<Pair<HgDataFile, Nodeid>> fileRenamesQueue = buildFileRenamesQueue(); | 536 FileRenameQueueBuilder frqBuilder = new FileRenameQueueBuilder(); |
537 List<Pair<HgDataFile, Nodeid>> fileRenamesQueue = frqBuilder.buildFileRenamesQueue(); | |
535 // XXX perhaps, makes sense to look at selected file's revision when followAncestry is true | 538 // XXX perhaps, makes sense to look at selected file's revision when followAncestry is true |
536 // to ensure file we attempt to trace is in the WC's parent. Native hg aborts if not. | 539 // to ensure file we attempt to trace is in the WC's parent. Native hg aborts if not. |
537 progressHelper.start(4 * fileRenamesQueue.size()); | 540 progressHelper.start(4 * fileRenamesQueue.size()); |
538 for (int namesIndex = 0, renamesQueueSize = fileRenamesQueue.size(); namesIndex < renamesQueueSize; namesIndex++) { | 541 for (int namesIndex = 0, renamesQueueSize = fileRenamesQueue.size(); namesIndex < renamesQueueSize; namesIndex++) { |
539 | 542 |
540 final Pair<HgDataFile, Nodeid> renameInfo = fileRenamesQueue.get(namesIndex); | 543 final Pair<HgDataFile, Nodeid> renameInfo = fileRenamesQueue.get(namesIndex); |
541 dispatcher.prepare(progressHelper, renameInfo); | 544 dispatcher.prepare(progressHelper, renameInfo); |
542 cancelHelper.checkCancelled(); | 545 cancelHelper.checkCancelled(); |
543 if (namesIndex > 0) { | 546 if (namesIndex > 0) { |
544 dispatcher.connectWithLastJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex - 1), renameHandler); | 547 dispatcher.connectWithLastJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex - 1)); |
545 } | 548 } |
546 if (namesIndex + 1 < renamesQueueSize) { | 549 if (namesIndex + 1 < renamesQueueSize) { |
547 // there's at least one more name we are going to look at | 550 // there's at least one more name we are going to look at |
548 dispatcher.updateJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex+1)); | 551 dispatcher.updateJunctionPoint(renameInfo, fileRenamesQueue.get(namesIndex+1), renameHandler != null); |
549 } else { | 552 } else { |
550 dispatcher.clearJunctionPoint(); | 553 dispatcher.clearJunctionPoint(); |
551 } | 554 } |
552 dispatcher.dispatchAllChanges(); | 555 dispatcher.dispatchAllChanges(); |
556 if (renameHandler != null && namesIndex + 1 < renamesQueueSize) { | |
557 dispatcher.reportRenames(renameHandler); | |
558 } | |
553 } // for fileRenamesQueue; | 559 } // for fileRenamesQueue; |
560 frqBuilder.reportRenameIfNotInQueue(fileRenamesQueue, renameHandler); | |
554 progressHelper.done(); | 561 progressHelper.done(); |
555 } | 562 } |
556 | 563 |
557 private static class ReverseIterator<E> implements Iterator<E> { | 564 private static class ReverseIterator<E> implements Iterator<E> { |
558 private final ListIterator<E> listIterator; | 565 private final ListIterator<E> listIterator; |
571 listIterator.remove(); | 578 listIterator.remove(); |
572 } | 579 } |
573 } | 580 } |
574 | 581 |
575 /** | 582 /** |
576 * Follows file renames and build a list of all corresponding file nodes and revisions they were | 583 * Utility to build sequence of file renames |
577 * copied/renamed/branched at (IOW, their latest revision to look at). | 584 */ |
578 * | 585 private class FileRenameQueueBuilder { |
579 * If {@link #followRenames} is <code>false</code>, the list contains one element only, | 586 |
580 * file node with the name of the file as it was specified by the user. | 587 /** |
581 * | 588 * Follows file renames and build a list of all corresponding file nodes and revisions they were |
582 * For the most recent file revision depends on {@link #followAncestry}, and is file revision from working copy parent | 589 * copied/renamed/branched at (IOW, their latest revision to look at). |
583 * in it's true. <code>null</code> indicates file's TIP revision shall be used. | 590 * |
584 * | 591 * @param followRename when <code>false</code>, the list contains one element only, |
585 * TODO may use HgFileRevision (after some refactoring to accept HgDataFile and Nodeid) instead of Pair | 592 * file node with the name of the file as it was specified by the user. |
586 * and possibly reuse this functionality | 593 * |
587 * | 594 * @param followAncestry the most recent file revision reported depends on this parameter, |
588 * @return list of file renames, ordered with respect to {@link #iterateDirection} | 595 * and it is file revision from working copy parent in there when it's true. |
589 */ | 596 * <code>null</code> as Pair's second indicates file's TIP revision shall be used. |
590 private List<Pair<HgDataFile, Nodeid>> buildFileRenamesQueue() throws HgPathNotFoundException { | 597 * |
591 LinkedList<Pair<HgDataFile, Nodeid>> rv = new LinkedList<Pair<HgDataFile, Nodeid>>(); | 598 * TODO may use HgFileRevision (after some refactoring to accept HgDataFile and Nodeid) instead of Pair |
592 Nodeid startRev = null; | 599 * and possibly reuse this functionality |
593 HgDataFile fileNode = repo.getFileNode(file); | 600 * |
594 if (!fileNode.exists()) { | 601 * @return list of file renames, ordered with respect to {@link #iterateDirection} |
595 throw new HgPathNotFoundException(String.format("File %s not found in the repository", file), file); | 602 */ |
596 } | 603 public List<Pair<HgDataFile, Nodeid>> buildFileRenamesQueue() throws HgPathNotFoundException { |
597 if (followAncestry) { | 604 LinkedList<Pair<HgDataFile, Nodeid>> rv = new LinkedList<Pair<HgDataFile, Nodeid>>(); |
598 // TODO subject to dedicated method either in HgRepository (getWorkingCopyParentRevisionIndex) | 605 Nodeid startRev = null; |
599 // or in the HgDataFile (getWorkingCopyOriginRevision) | 606 HgDataFile fileNode = repo.getFileNode(file); |
600 Nodeid wdParentChangeset = repo.getWorkingCopyParents().first(); | 607 if (!fileNode.exists()) { |
601 if (!wdParentChangeset.isNull()) { | 608 throw new HgPathNotFoundException(String.format("File %s not found in the repository", file), file); |
602 int wdParentRevIndex = repo.getChangelog().getRevisionIndex(wdParentChangeset); | 609 } |
603 startRev = repo.getManifest().getFileRevision(wdParentRevIndex, fileNode.getPath()); | 610 if (followAncestry) { |
604 } | 611 // TODO subject to dedicated method either in HgRepository (getWorkingCopyParentRevisionIndex) |
605 // else fall-through, assume null (eventually, lastRevision()) is ok here | 612 // or in the HgDataFile (getWorkingCopyOriginRevision) |
606 } | 613 Nodeid wdParentChangeset = repo.getWorkingCopyParents().first(); |
607 rv.add(new Pair<HgDataFile, Nodeid>(fileNode, startRev)); | 614 if (!wdParentChangeset.isNull()) { |
608 if (!followRenames) { | 615 int wdParentRevIndex = repo.getChangelog().getRevisionIndex(wdParentChangeset); |
616 startRev = repo.getManifest().getFileRevision(wdParentRevIndex, fileNode.getPath()); | |
617 } | |
618 // else fall-through, assume null (eventually, lastRevision()) is ok here | |
619 } | |
620 Pair<HgDataFile, Nodeid> p = new Pair<HgDataFile, Nodeid>(fileNode, startRev); | |
621 rv.add(p); | |
622 if (!followRenames) { | |
623 return rv; | |
624 } | |
625 while (hasOrigin(p)) { | |
626 p = origin(p); | |
627 if (iterateDirection == HgIterateDirection.OldToNew) { | |
628 rv.addFirst(p); | |
629 } else { | |
630 assert iterateDirection == HgIterateDirection.NewToOld; | |
631 rv.addLast(p); | |
632 } | |
633 }; | |
609 return rv; | 634 return rv; |
610 } | 635 } |
611 while (fileNode.isCopy()) { | 636 |
637 public boolean hasOrigin(Pair<HgDataFile, Nodeid> p) { | |
638 return p.first().isCopy(); | |
639 } | |
640 | |
641 public Pair<HgDataFile, Nodeid> origin(Pair<HgDataFile, Nodeid> p) { | |
642 HgDataFile fileNode = p.first(); | |
643 assert fileNode.isCopy(); | |
612 Path fp = fileNode.getCopySourceName(); | 644 Path fp = fileNode.getCopySourceName(); |
613 Nodeid copyRev = fileNode.getCopySourceRevision(); | 645 Nodeid copyRev = fileNode.getCopySourceRevision(); |
614 fileNode = repo.getFileNode(fp); | 646 fileNode = repo.getFileNode(fp); |
615 Pair<HgDataFile, Nodeid> p = new Pair<HgDataFile, Nodeid>(fileNode, copyRev); | 647 return new Pair<HgDataFile, Nodeid>(fileNode, copyRev); |
616 if (iterateDirection == HgIterateDirection.OldToNew) { | 648 } |
617 rv.addFirst(p); | 649 |
618 } else { | 650 /** |
619 assert iterateDirection == HgIterateDirection.NewToOld; | 651 * Shall report renames based solely on HgFileRenameHandlerMixin presence, |
620 rv.addLast(p); | 652 * even if queue didn't get rename information due to followRenames == false |
621 } | 653 * |
622 }; | 654 * @param queue value from {@link #buildFileRenamesQueue()} |
623 return rv; | 655 * @param renameHandler may be <code>null</code> |
656 */ | |
657 public void reportRenameIfNotInQueue(List<Pair<HgDataFile, Nodeid>> queue, HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { | |
658 if (renameHandler != null && !followRenames) { | |
659 // If followRenames is true, all the historical names were in the queue and are processed already. | |
660 // Hence, shall process origin explicitly only when renameHandler is present but followRenames is not requested. | |
661 assert queue.size() == 1; // see the way queue is constructed above | |
662 Pair<HgDataFile, Nodeid> curRename = queue.get(0); | |
663 if (hasOrigin(curRename)) { | |
664 Pair<HgDataFile, Nodeid> origin = origin(curRename); | |
665 HgFileRevision src, dst; | |
666 src = new HgFileRevision(origin.first(), origin.second(), null); | |
667 dst = new HgFileRevision(curRename.first(), curRename.first().getRevision(0), src.getPath()); | |
668 renameHandler.copy(src, dst); | |
669 } | |
670 } | |
671 } | |
624 } | 672 } |
625 | 673 |
626 private static class TreeBuildInspector implements HgChangelog.ParentInspector, HgChangelog.RevisionInspector { | 674 private static class TreeBuildInspector implements HgChangelog.ParentInspector, HgChangelog.RevisionInspector { |
627 private final boolean followAncestry; | 675 private final boolean followAncestry; |
628 | 676 |
772 private ProgressSupport progress; | 820 private ProgressSupport progress; |
773 protected HgDataFile currentFileNode; | 821 protected HgDataFile currentFileNode; |
774 // node where current file history chunk intersects with same file under other name history | 822 // node where current file history chunk intersects with same file under other name history |
775 // either mock of B(0) or A(k), depending on iteration order | 823 // either mock of B(0) or A(k), depending on iteration order |
776 private HistoryNode junctionNode; | 824 private HistoryNode junctionNode; |
825 // initialized when there's HgFileRenameHandlerMixin | |
826 private HgFileRevision copiedFrom, copiedTo; | |
777 | 827 |
778 // parentProgress shall be initialized with 4 XXX refactor all this stuff with parentProgress | 828 // parentProgress shall be initialized with 4 XXX refactor all this stuff with parentProgress |
779 public void prepare(ProgressSupport parentProgress, Pair<HgDataFile, Nodeid> renameInfo) { | 829 public void prepare(ProgressSupport parentProgress, Pair<HgDataFile, Nodeid> renameInfo) { |
780 // if we don't followAncestry, take complete history | 830 // if we don't followAncestry, take complete history |
781 // XXX treeBuildInspector knows followAncestry, perhaps the logic | 831 // XXX treeBuildInspector knows followAncestry, perhaps the logic |
802 } | 852 } |
803 progress.start(historyNodeCount); | 853 progress.start(historyNodeCount); |
804 // switch to present chunk's file node | 854 // switch to present chunk's file node |
805 switchTo(renameInfo.first()); | 855 switchTo(renameInfo.first()); |
806 } | 856 } |
807 | 857 |
808 public void updateJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> nextRename) { | 858 public void updateJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> nextRename, boolean needCopyFromTo) { |
859 copiedFrom = copiedTo = null; | |
860 // | |
809 // A (old) renamed to B(new). A(0..k..n) -> B(0..m). If followAncestry, k == n | 861 // A (old) renamed to B(new). A(0..k..n) -> B(0..m). If followAncestry, k == n |
810 // curRename.second() points to A(k) | 862 // curRename.second() points to A(k) |
811 if (iterateDirection == HgIterateDirection.OldToNew) { | 863 if (iterateDirection == HgIterateDirection.OldToNew) { |
812 // looking at A chunk (curRename), nextRename points to B | 864 // looking at A chunk (curRename), nextRename points to B |
813 HistoryNode junctionSrc = findJunctionPointInCurrentChunk(curRename.second()); // A(k) | 865 HistoryNode junctionSrc = findJunctionPointInCurrentChunk(curRename.second()); // A(k) |
817 // price for simplicity of the code (and opportunity to follow renames while not following ancestry) | 869 // price for simplicity of the code (and opportunity to follow renames while not following ancestry) |
818 junctionSrc.bindChild(junctionDestMock); | 870 junctionSrc.bindChild(junctionDestMock); |
819 // Save mock A(k) 1) not to keep whole A history in memory 2) Don't need it's parent and children once get to B | 871 // Save mock A(k) 1) not to keep whole A history in memory 2) Don't need it's parent and children once get to B |
820 // moreover, children of original A(k) (junctionSrc) would list mock B(0) which is undesired once we iterate over real B | 872 // moreover, children of original A(k) (junctionSrc) would list mock B(0) which is undesired once we iterate over real B |
821 junctionNode = new HistoryNode(junctionSrc.changeset, junctionSrc.fileRevision, null, null); | 873 junctionNode = new HistoryNode(junctionSrc.changeset, junctionSrc.fileRevision, null, null); |
874 if (needCopyFromTo) { | |
875 copiedFrom = new HgFileRevision(curRename.first(), junctionNode.fileRevision, null); // "A", A(k) | |
876 copiedTo = new HgFileRevision(nextRename.first(), junctionDestMock.fileRevision, copiedFrom.getPath()); // "B", B(0) | |
877 } | |
822 } else { | 878 } else { |
823 assert iterateDirection == HgIterateDirection.NewToOld; | 879 assert iterateDirection == HgIterateDirection.NewToOld; |
824 // looking at B chunk (curRename), nextRename points at A | 880 // looking at B chunk (curRename), nextRename points at A |
825 HistoryNode junctionDest = changeHistory.get(0); // B(0) | 881 HistoryNode junctionDest = changeHistory.get(0); // B(0) |
826 // prepare mock A(k) | 882 // prepare mock A(k) |
832 // for the sake of parent cset revisions). We have to, indeed, update real A(k), | 888 // for the sake of parent cset revisions). We have to, indeed, update real A(k), |
833 // once we get to iteration over A, with B(0) (junctionDest) as one more child. | 889 // once we get to iteration over A, with B(0) (junctionDest) as one more child. |
834 junctionSrcMock.bindChild(junctionDest); | 890 junctionSrcMock.bindChild(junctionDest); |
835 // Save mock B(0), for reasons see above for opposite direction | 891 // Save mock B(0), for reasons see above for opposite direction |
836 junctionNode = new HistoryNode(junctionDest.changeset, junctionDest.fileRevision, null, null); | 892 junctionNode = new HistoryNode(junctionDest.changeset, junctionDest.fileRevision, null, null); |
893 if (needCopyFromTo) { | |
894 copiedFrom = new HgFileRevision(nextRename.first(), junctionSrcMock.fileRevision, null); // "A", A(k) | |
895 copiedTo = new HgFileRevision(curRename.first(), junctionNode.fileRevision, copiedFrom.getPath()); // "B", B(0) | |
896 } | |
897 } | |
898 } | |
899 | |
900 public void reportRenames(HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { | |
901 if (renameHandler != null) { // shall report renames | |
902 assert copiedFrom != null; | |
903 assert copiedTo != null; | |
904 renameHandler.copy(copiedFrom, copiedTo); | |
837 } | 905 } |
838 } | 906 } |
839 | 907 |
840 public void clearJunctionPoint() { | 908 public void clearJunctionPoint() { |
841 junctionNode = null; | 909 junctionNode = null; |
842 } | 910 copiedFrom = copiedTo = null; |
843 | 911 } |
844 public void connectWithLastJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> prevRename, HgFileRenameHandlerMixin renameHandler) throws HgCallbackTargetException { | 912 |
913 /** | |
914 * Replace mock src/dest HistoryNode connected to junctionNode with a real one | |
915 */ | |
916 public void connectWithLastJunctionPoint(Pair<HgDataFile, Nodeid> curRename, Pair<HgDataFile, Nodeid> prevRename) { | |
845 assert junctionNode != null; | 917 assert junctionNode != null; |
846 // A renamed to B. A(0..k..n) -> B(0..m). If followAncestry: k == n | 918 // A renamed to B. A(0..k..n) -> B(0..m). If followAncestry: k == n |
847 if (iterateDirection == HgIterateDirection.OldToNew) { | 919 if (iterateDirection == HgIterateDirection.OldToNew) { |
848 // forward, from old to new: | 920 // forward, from old to new: |
849 // changeHistory points to B | 921 // changeHistory points to B |
850 // Already reported: A(0)..A(n), A(k) is in junctionNode | 922 // Already reported: A(0)..A(n), A(k) is in junctionNode |
851 // Shall connect histories: A(k).bind(B(0)) | 923 // Shall connect histories: A(k).bind(B(0)) |
852 HistoryNode junctionDest = changeHistory.get(0); // B(0) | 924 HistoryNode junctionDest = changeHistory.get(0); // B(0) |
853 // junctionNode is A(k) | 925 // junctionNode is A(k) |
854 junctionNode.bindChild(junctionDest); | 926 junctionNode.bindChild(junctionDest); |
855 if (renameHandler != null) { // shall report renames | |
856 HgFileRevision copiedFrom = new HgFileRevision(prevRename.first(), junctionNode.fileRevision, null); // "A", A(k) | |
857 HgFileRevision copiedTo = new HgFileRevision(curRename.first(), junctionDest.fileRevision, copiedFrom.getPath()); // "B", B(0) | |
858 renameHandler.copy(copiedFrom, copiedTo); | |
859 } | |
860 } else { | 927 } else { |
861 assert iterateDirection == HgIterateDirection.NewToOld; | 928 assert iterateDirection == HgIterateDirection.NewToOld; |
862 // changeHistory points to A | 929 // changeHistory points to A |
863 // Already reported B(m), B(m-1)...B(0), B(0) is in junctionNode | 930 // Already reported B(m), B(m-1)...B(0), B(0) is in junctionNode |
864 // Shall connect histories A(k).bind(B(0)) | 931 // Shall connect histories A(k).bind(B(0)) |
865 // if followAncestry: A(k) is latest in changeHistory (k == n) | 932 // if followAncestry: A(k) is latest in changeHistory (k == n) |
866 HistoryNode junctionSrc = findJunctionPointInCurrentChunk(curRename.second()); // A(k) | 933 HistoryNode junctionSrc = findJunctionPointInCurrentChunk(curRename.second()); // A(k) |
867 junctionSrc.bindChild(junctionNode); | 934 junctionSrc.bindChild(junctionNode); |
868 if (renameHandler != null) { | |
869 HgFileRevision copiedFrom = new HgFileRevision(curRename.first(), junctionSrc.fileRevision, null); // "A", A(k) | |
870 HgFileRevision copiedTo = new HgFileRevision(prevRename.first(), junctionNode.fileRevision, copiedFrom.getPath()); // "B", B(0) | |
871 renameHandler.copy(copiedFrom, copiedTo); | |
872 } | |
873 } | 935 } |
874 } | 936 } |
875 | 937 |
876 private HistoryNode findJunctionPointInCurrentChunk(Nodeid fileRevision) { | 938 private HistoryNode findJunctionPointInCurrentChunk(Nodeid fileRevision) { |
877 if (followAncestry) { | 939 if (followAncestry) { |