private void updateFollowFilter(ObjectId[] trees, DiffConfig cfg) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException { TreeWalk tw = pathFilter; FollowFilter oldFilter = (FollowFilter) tw.getFilter(); tw.setFilter(TreeFilter.ANY_DIFF); tw.reset(trees); List<DiffEntry> files = DiffEntry.scan(tw); RenameDetector rd = new RenameDetector(tw.getObjectReader(), cfg); rd.addAll(files); files = rd.compute(); TreeFilter newFilter = oldFilter; for (DiffEntry ent : files) { if (isRename(ent) && ent.getNewPath().equals(oldFilter.getPath())) { newFilter = FollowFilter.create(ent.getOldPath(), cfg); RenameCallback callback = oldFilter.getRenameCallback(); if (callback != null) { callback.renamed(ent); // forward the callback to the new follow filter ((FollowFilter) newFilter).setRenameCallback(callback); } break; } } tw.setFilter(newFilter); }
private void findContentRenames(ContentSource.Pair reader, ProgressMonitor pm) throws IOException, CancelledException { int cnt = Math.max(added.size(), deleted.size()); if (getRenameLimit() == 0 || cnt <= getRenameLimit()) { SimilarityRenameDetector d; d = new SimilarityRenameDetector(reader, deleted, added); d.setRenameScore(getRenameScore()); d.compute(pm); overRenameLimit |= d.isTableOverflow(); deleted = d.getLeftOverSources(); added = d.getLeftOverDestinations(); entries.addAll(d.getMatches()); } else { overRenameLimit = true; } }
private List<DiffEntry> detectRenames(List<DiffEntry> files) throws IOException { renameDetector.reset(); renameDetector.addAll(files); try { return renameDetector.compute(reader, progressMonitor); } catch (CancelledException e) { // TODO: consider propagating once bug 536323 is tackled // (making DiffEntry.scan() and DiffFormatter.scan() and // format() cancellable). return Collections.emptyList(); } }
breakModifies(reader, pm); findExactRenames(pm); findContentRenames(reader, pm); rejoinModifies(pm);
private void breakModifies(ContentSource.Pair reader, ProgressMonitor pm) throws IOException, CancelledException { ArrayList<DiffEntry> newEntries = new ArrayList<>(entries.size()); pm.beginTask(JGitText.get().renamesBreakingModifies, entries.size()); for (int i = 0; i < entries.size(); i++) { DiffEntry e = entries.get(i); if (e.getChangeType() == ChangeType.MODIFY) { int score = calculateModifyScore(reader, e); if (score < breakScore) { List<DiffEntry> tmp = DiffEntry.breakModify(e); DiffEntry del = tmp.get(0); del.score = score; deleted.add(del); added.add(tmp.get(1)); } else { newEntries.add(e); } } else { newEntries.add(e); } advanceOrCancel(pm); } entries = newEntries; }
@NotNull private Map<String, String> collectRename(@NotNull GitFile oldTree, @NotNull GitFile newTree) throws IOException { if (!renameDetection) { return Collections.emptyMap(); } final GitObject<ObjectId> oldTreeId = oldTree.getObjectId(); final GitObject<ObjectId> newTreeId = newTree.getObjectId(); if (oldTreeId == null || newTreeId == null || !Objects.equals(oldTreeId.getRepo(), newTreeId.getRepo())) { return Collections.emptyMap(); } final TreeWalk tw = new TreeWalk(repository); tw.setRecursive(true); tw.addTree(oldTree.getObjectId().getObject()); tw.addTree(newTree.getObjectId().getObject()); final RenameDetector rd = new RenameDetector(repository); rd.addAll(DiffEntry.scan(tw)); final Map<String, String> result = new HashMap<>(); for (DiffEntry diff : rd.compute(tw.getObjectReader(), null)) { if (diff.getScore() >= rd.getRenameScore()) { result.put(StringHelper.normalize(diff.getNewPath()), StringHelper.normalize(diff.getOldPath())); } } return result; }
tw.setFilter(TreeFilter.ANY_DIFF); final RenameDetector rd = new RenameDetector(repo); rd.reset(); rd.addAll(DiffEntry.scan(tw)); List<DiffEntry> diffs = rd.compute(or, null); if (useRawOutput) { for (DiffEntry diff : diffs) {
TreeWalk tw = new TreeWalk(repository); tw.setRecursive(true); tw.addTree(CommitUtils.getHead(repository).getTree()); tw.addTree(new FileTreeIterator(repository)); RenameDetector rd = new RenameDetector(repository); rd.addAll(DiffEntry.scan(tw)); List<DiffEntry> lde = rd.compute(tw.getObjectReader(), null); for (DiffEntry de : lde) { if (de.getScore() >= rd.getRenameScore()) { System.out.println("file: " + de.getOldPath() + " copied/moved to: " + de.getNewPath()); } }
/** * Detect renames in the current file set. * <p> * This convenience function runs without a progress monitor. * * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s * representing all files that have been changed. * @throws java.io.IOException * file contents cannot be read from the repository. */ public List<DiffEntry> compute() throws IOException { return compute(NullProgressMonitor.INSTANCE); }
HashMap<AbbreviatedObjectId, Object> deletedMap = populateMap(deleted, pm); HashMap<AbbreviatedObjectId, Object> addedMap = populateMap(added, pm); if (sameType(e.oldMode, a.newMode)) { e.changeType = ChangeType.RENAME; entries.add(exactRename(e, a)); } else { left.add(a); DiffEntry best = bestPathMatch(a, list); if (best != null) { best.changeType = ChangeType.RENAME; entries.add(exactRename(best, a)); } else { left.add(a); advanceOrCancel(pm); DiffEntry best = bestPathMatch(d, adds); if (best != null) { d.changeType = ChangeType.RENAME; entries.add(exactRename(d, best)); for (DiffEntry a : adds) { if (a != best) { if (sameType(d.oldMode, a.newMode)) { entries.add(exactCopy(d, a)); } else { left.add(a);
/** * Enable or disable rename detection. * * Before enabling rename detection the repository must be set with * {@link #setRepository(Repository)}. Once enabled the detector can be * configured away from its defaults by obtaining the instance directly from * {@link #getRenameDetector()} and invoking configuration. * * @param on * if rename detection should be enabled. */ public void setDetectRenames(boolean on) { if (on && renameDetector == null) { assertHaveReader(); renameDetector = new RenameDetector(reader, diffCfg); } else if (!on) renameDetector = null; }
/** * Add an entry to be considered for rename detection. * * @param entry * to add. * @throws java.lang.IllegalStateException * if {@code getEntries} was already invoked. */ public void add(DiffEntry entry) { addAll(Collections.singletonList(entry)); }
/** * Create a new rename detector with a specified reader and diff config. * * @param reader * reader to obtain objects from the repository with. * @param cfg * diff config specifying rename detection options. * @since 3.0 */ public RenameDetector(ObjectReader reader, DiffConfig cfg) { objectReader = reader.newReader(); renameLimit = cfg.getRenameLimit(); reset(); }
private void breakModifies(ContentSource.Pair reader, ProgressMonitor pm) throws IOException { ArrayList<DiffEntry> newEntries = new ArrayList<DiffEntry>(entries.size()); pm.beginTask(JGitText.get().renamesBreakingModifies, entries.size()); for (int i = 0; i < entries.size(); i++) { DiffEntry e = entries.get(i); if (e.getChangeType() == ChangeType.MODIFY) { int score = calculateModifyScore(reader, e); if (score < breakScore) { List<DiffEntry> tmp = DiffEntry.breakModify(e); DiffEntry del = tmp.get(0); del.score = score; deleted.add(del); added.add(tmp.get(1)); } else { newEntries.add(e); } } else { newEntries.add(e); } pm.update(1); } entries = newEntries; }
tw.addTree(newTree); final RenameDetector rd = new RenameDetector(repository); rd.setRenameScore(80); rd.addAll(DiffEntry.scan(tw)); for (DiffEntry diff : rd.compute(tw.getObjectReader(), null)) { ChangeType changeType = diff.getChangeType(); String oldPath = diff.getOldPath(); if (changeType == ChangeType.RENAME && diff.getScore() >= rd.getRenameScore()) { if (isJavafile(oldPath) && isJavafile(newPath)) { renamedFilesHint.put(oldPath, newPath);
/** * Detect renames in the current file set. * * @param pm * report progress during the detection phases. * @return an unmodifiable list of {@link org.eclipse.jgit.diff.DiffEntry}s * representing all files that have been changed. * @throws java.io.IOException * file contents cannot be read from the repository. * @throws CancelledException * if rename detection was cancelled */ // TODO(ms): use org.eclipse.jgit.api.errors.CanceledException in next major // version public List<DiffEntry> compute(ProgressMonitor pm) throws IOException, CancelledException { if (!done) { try { return compute(objectReader, pm); } finally { objectReader.close(); } } return Collections.unmodifiableList(entries); }
HashMap<AbbreviatedObjectId, Object> deletedMap = populateMap(deleted, pm); HashMap<AbbreviatedObjectId, Object> addedMap = populateMap(added, pm); if (sameType(e.oldMode, a.newMode)) { e.changeType = ChangeType.RENAME; entries.add(exactRename(e, a)); } else { left.add(a); DiffEntry best = bestPathMatch(a, list); if (best != null) { best.changeType = ChangeType.RENAME; entries.add(exactRename(best, a)); } else { left.add(a); advanceOrCancel(pm); DiffEntry best = bestPathMatch(d, adds); if (best != null) { d.changeType = ChangeType.RENAME; entries.add(exactRename(d, best)); for (DiffEntry a : adds) { if (a != best) { if (sameType(d.oldMode, a.newMode)) { entries.add(exactCopy(d, a)); } else { left.add(a);
/** * Enable (or disable) following file renames, on by default. * <p> * If true renames are followed using the standard FollowFilter behavior * used by RevWalk (which matches {@code git log --follow} in the C * implementation). This is not the same as copy/move detection as * implemented by the C implementation's of {@code git blame -M -C}. * * @param follow * enable following. * @return {@code this} */ public BlameGenerator setFollowFileRenames(boolean follow) { if (follow) renameDetector = new RenameDetector(getRepository()); else renameDetector = null; return this; }
breakModifies(reader, pm); findExactRenames(pm); findContentRenames(reader, pm); rejoinModifies(pm);
/** * Add an entry to be considered for rename detection. * * @param entry * to add. * @throws java.lang.IllegalStateException * if {@code getEntries} was already invoked. */ public void add(DiffEntry entry) { addAll(Collections.singletonList(entry)); }