Mercurial > jhg
comparison src/org/tmatesoft/hg/repo/HgBlameFacility.java @ 573:e49f9d9513fa
Partial blame when start/end revisions are in the middle of a single filename history
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Fri, 12 Apr 2013 19:50:21 +0200 |
parents | 36853bb80a35 |
children | 43cfa08ff3fd |
comparison
equal
deleted
inserted
replaced
572:becd2a1310a2 | 573:e49f9d9513fa |
---|---|
77 */ | 77 */ |
78 public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, Inspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { | 78 public void annotate(int changelogRevIndexStart, int changelogRevIndexEnd, Inspector insp, HgIterateDirection iterateOrder) throws HgCallbackTargetException { |
79 if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) { | 79 if (wrongRevisionIndex(changelogRevIndexStart) || wrongRevisionIndex(changelogRevIndexEnd)) { |
80 throw new IllegalArgumentException(); | 80 throw new IllegalArgumentException(); |
81 } | 81 } |
82 // Note, changelogRevisionIndex may be TIP, while the code below doesn't tolerate constants | 82 // Note, changelogRevIndexEnd may be TIP, while the code below doesn't tolerate constants |
83 // | 83 // |
84 int lastRevision = df.getRepo().getChangelog().getLastRevision(); | 84 int lastRevision = df.getRepo().getChangelog().getLastRevision(); |
85 if (changelogRevIndexEnd == TIP) { | 85 if (changelogRevIndexEnd == TIP) { |
86 changelogRevIndexEnd = lastRevision; | 86 changelogRevIndexEnd = lastRevision; |
87 } | 87 } |
99 fileHistory.init(fileLastClogRevIndex); | 99 fileHistory.init(fileLastClogRevIndex); |
100 fileHistory.linkTo(nextChunk); | 100 fileHistory.linkTo(nextChunk); |
101 fileCompleteHistory.addFirst(fileHistory); // to get the list in old-to-new order | 101 fileCompleteHistory.addFirst(fileHistory); // to get the list in old-to-new order |
102 nextChunk = fileHistory; | 102 nextChunk = fileHistory; |
103 bh.useFileUpTo(currentFile, fileLastClogRevIndex); | 103 bh.useFileUpTo(currentFile, fileLastClogRevIndex); |
104 if (currentFile.isCopy()) { | 104 if (fileHistory.changeset(0) > changelogRevIndexStart && currentFile.isCopy()) { |
105 // TODO SessionContext.getPathFactory() and replace all Path.create | 105 // fileHistory.changeset(0) is the earliest revision we know about so far, |
106 // once we get to revisions earlier than the requested start, stop digging. | |
107 // The reason there's NO == (i.e. not >=) because: | |
108 // (easy): once it's equal, we've reached our intended start | |
109 // (hard): if changelogRevIndexStart happens to be exact start of one of renames in the | |
110 // chain of renames (test-annotate2 repository, file1->file1a->file1b, i.e. points | |
111 // to the very start of file1a or file1 history), presence of == would get us to the next | |
112 // chunk and hence changed parents of present chunk's first element. Our annotate alg | |
113 // relies on parents only (i.e. knows nothing about 'last iteration element') to find out | |
114 // what to compare, and hence won't report all lines of 'last iteration element' (which is the | |
115 // first revision of the renamed file) as "added in this revision", leaving gaps in annotate | |
106 HgRepository repo = currentFile.getRepo(); | 116 HgRepository repo = currentFile.getRepo(); |
107 Nodeid originLastRev = currentFile.getCopySourceRevision(); | 117 Nodeid originLastRev = currentFile.getCopySourceRevision(); |
108 currentFile = repo.getFileNode(currentFile.getCopySourceName()); | 118 currentFile = repo.getFileNode(currentFile.getCopySourceName()); |
109 fileLastClogRevIndex = currentFile.getChangesetRevisionIndex(currentFile.getRevisionIndex(originLastRev)); | 119 fileLastClogRevIndex = currentFile.getChangesetRevisionIndex(currentFile.getRevisionIndex(originLastRev)); |
110 // XXX perhaps, shall fail with meaningful exception if new file doesn't exist (.i/.d not found for whatever reason) | 120 // XXX perhaps, shall fail with meaningful exception if new file doesn't exist (.i/.d not found for whatever reason) |
111 // or source revision is missing? | 121 // or source revision is missing? |
112 } else { | 122 } else { |
123 fileHistory.chopAtChangeset(changelogRevIndexStart); | |
113 currentFile = null; // stop iterating | 124 currentFile = null; // stop iterating |
114 } | 125 } |
115 } while (currentFile != null && fileLastClogRevIndex >= changelogRevIndexStart); | 126 } while (currentFile != null && fileLastClogRevIndex > changelogRevIndexStart); |
116 // fileCompleteHistory is in (origin, intermediate target, ultimate target) order | 127 // fileCompleteHistory is in (origin, intermediate target, ultimate target) order |
117 | 128 |
118 int[] fileClogParentRevs = new int[2]; | 129 int[] fileClogParentRevs = new int[2]; |
119 int[] fileParentRevs = new int[2]; | 130 int[] fileParentRevs = new int[2]; |
120 if (iterateOrder == NewToOld) { | 131 if (iterateOrder == NewToOld) { |
404 return; | 415 return; |
405 } | 416 } |
406 target.originFileRev = fileRevsToVisit.get(0); // files to visit are new to old | 417 target.originFileRev = fileRevsToVisit.get(0); // files to visit are new to old |
407 target.originChangelogRev = changeset(target.originFileRev); | 418 target.originChangelogRev = changeset(target.originFileRev); |
408 } | 419 } |
409 | 420 |
421 /** | |
422 * Mark revision closest(ceil) to specified as the very first one (no parents) | |
423 */ | |
424 public void chopAtChangeset(int firstChangelogRevOfInterest) { | |
425 if (firstChangelogRevOfInterest == 0) { | |
426 return; // nothing to do | |
427 } | |
428 int i = 0, x = fileRevsToVisit.size(), fileRev = BAD_REVISION; | |
429 // fileRevsToVisit is new to old, greater numbers to smaller | |
430 while (i < x && changeset(fileRev = fileRevsToVisit.get(i)) >= firstChangelogRevOfInterest) { | |
431 i++; | |
432 } | |
433 assert fileRev != BAD_REVISION; // there's at least 1 revision in fileRevsToVisit | |
434 if (i == x && changeset(fileRev) != firstChangelogRevOfInterest) { | |
435 assert false : "Requested changeset shall belong to the chunk"; | |
436 return; | |
437 } | |
438 fileRevsToVisit.trimTo(i); // no need to iterate more | |
439 // pretend fileRev got no parents | |
440 fileParentRevs.set(fileRev * 2, NO_REVISION); | |
441 fileParentRevs.set(fileRev, NO_REVISION); | |
442 } | |
443 | |
410 public int[] fileRevisions(HgIterateDirection iterateOrder) { | 444 public int[] fileRevisions(HgIterateDirection iterateOrder) { |
411 // fileRevsToVisit is { r10, r7, r6, r5, r0 }, new to old | 445 // fileRevsToVisit is { r10, r7, r6, r5, r0 }, new to old |
412 int[] rv = fileRevsToVisit.toArray(); | 446 int[] rv = fileRevsToVisit.toArray(); |
413 if (iterateOrder == OldToNew) { | 447 if (iterateOrder == OldToNew) { |
414 // reverse return value | 448 // reverse return value |