/// <summary> /// Find the best match by file path for a given DiffEntry from a list of /// DiffEntrys. /// </summary> /// <remarks> /// Find the best match by file path for a given DiffEntry from a list of /// DiffEntrys. The returned DiffEntry will be of the same type as <src>. If /// no DiffEntry can be found that has the same type, this method will return /// null. /// </remarks> /// <param name="src">the DiffEntry to try to find a match for</param> /// <param name="list">a list of DiffEntrys to search through</param> /// <returns>the DiffEntry from <list> who's file path best matches <src></returns> private static DiffEntry BestPathMatch(DiffEntry src, IList <DiffEntry> list) { DiffEntry best = null; int score = -1; foreach (DiffEntry d in list) { if (SameType(Mode(d), Mode(src))) { int tmp = SimilarityRenameDetector.NameScore(Path(d), Path(src)); if (tmp > score) { best = d; score = tmp; } } } return(best); }
/// <exception cref="System.IO.IOException"></exception> private void FindContentRenames(ContentSource.Pair reader, ProgressMonitor pm) { int cnt = Math.Max(added.Count, deleted.Count); 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(); Sharpen.Collections.AddAll(entries, d.GetMatches()); } else { overRenameLimit = true; } }
private void FindExactRenames(ProgressMonitor pm) { pm.BeginTask(JGitText.Get().renamesFindingExact, added.Count + added.Count + deleted .Count + added.Count * deleted.Count); // Dictionary <AbbreviatedObjectId, object> deletedMap = PopulateMap(deleted, pm); Dictionary <AbbreviatedObjectId, object> addedMap = PopulateMap(added, pm); AList <DiffEntry> uniqueAdds = new AList <DiffEntry>(added.Count); AList <IList <DiffEntry> > nonUniqueAdds = new AList <IList <DiffEntry> >(); foreach (object o in addedMap.Values) { if (o is DiffEntry) { uniqueAdds.AddItem((DiffEntry)o); } else { nonUniqueAdds.AddItem((IList <DiffEntry>)o); } } AList <DiffEntry> left = new AList <DiffEntry>(added.Count); foreach (DiffEntry a in uniqueAdds) { object del = deletedMap.Get(a.newId); if (del is DiffEntry) { // We have one add to one delete: pair them if they are the same // type DiffEntry e = (DiffEntry)del; if (SameType(e.oldMode, a.newMode)) { e.changeType = DiffEntry.ChangeType.RENAME; entries.AddItem(ExactRename(e, a)); } else { left.AddItem(a); } } else { if (del != null) { // We have one add to many deletes: find the delete with the // same type and closest name to the add, then pair them IList <DiffEntry> list = (IList <DiffEntry>)del; DiffEntry best = BestPathMatch(a, list); if (best != null) { best.changeType = DiffEntry.ChangeType.RENAME; entries.AddItem(ExactRename(best, a)); } else { left.AddItem(a); } } else { left.AddItem(a); } } pm.Update(1); } foreach (IList <DiffEntry> adds in nonUniqueAdds) { object o_1 = deletedMap.Get(adds[0].newId); if (o_1 is DiffEntry) { // We have many adds to one delete: find the add with the same // type and closest name to the delete, then pair them. Mark the // rest as copies of the delete. DiffEntry d = (DiffEntry)o_1; DiffEntry best = BestPathMatch(d, adds); if (best != null) { d.changeType = DiffEntry.ChangeType.RENAME; entries.AddItem(ExactRename(d, best)); foreach (DiffEntry a_1 in adds) { if (a_1 != best) { if (SameType(d.oldMode, a_1.newMode)) { entries.AddItem(ExactCopy(d, a_1)); } else { left.AddItem(a_1); } } } } else { Sharpen.Collections.AddAll(left, adds); } } else { if (o_1 != null) { // We have many adds to many deletes: score all the adds against // all the deletes by path name, take the best matches, pair // them as renames, then call the rest copies IList <DiffEntry> dels = (IList <DiffEntry>)o_1; long[] matrix = new long[dels.Count * adds.Count]; int mNext = 0; for (int delIdx = 0; delIdx < dels.Count; delIdx++) { string deletedName = dels[delIdx].oldPath; for (int addIdx = 0; addIdx < adds.Count; addIdx++) { string addedName = adds[addIdx].newPath; int score = SimilarityRenameDetector.NameScore(addedName, deletedName); matrix[mNext] = SimilarityRenameDetector.Encode(score, delIdx, addIdx); mNext++; } } Arrays.Sort(matrix); for (--mNext; mNext >= 0; mNext--) { long ent = matrix[mNext]; int delIdx_1 = SimilarityRenameDetector.SrcFile(ent); int addIdx = SimilarityRenameDetector.DstFile(ent); DiffEntry d = dels[delIdx_1]; DiffEntry a_1 = adds[addIdx]; if (a_1 == null) { pm.Update(1); continue; } // was already matched earlier DiffEntry.ChangeType type; if (d.changeType == DiffEntry.ChangeType.DELETE) { // First use of this source file. Tag it as a rename so we // later know it is already been used as a rename, other // matches (if any) will claim themselves as copies instead. // d.changeType = DiffEntry.ChangeType.RENAME; type = DiffEntry.ChangeType.RENAME; } else { type = DiffEntry.ChangeType.COPY; } entries.AddItem(DiffEntry.Pair(type, d, a_1, 100)); adds.Set(addIdx, null); // Claim the destination was matched. pm.Update(1); } } else { Sharpen.Collections.AddAll(left, adds); } } } added = left; deleted = new AList <DiffEntry>(deletedMap.Count); foreach (object o_2 in deletedMap.Values) { if (o_2 is DiffEntry) { DiffEntry e = (DiffEntry)o_2; if (e.changeType == DiffEntry.ChangeType.DELETE) { deleted.AddItem(e); } } else { IList <DiffEntry> list = (IList <DiffEntry>)o_2; foreach (DiffEntry e in list) { if (e.changeType == DiffEntry.ChangeType.DELETE) { deleted.AddItem(e); } } } } pm.EndTask(); }