public string GetComment() { var interestingFileChanges = Versions.Where(v => v.InRawChangeSet && v.Names.Count > 0 && !v.Version.Element.IsDirectory).ToList(); int nbFileChanges = interestingFileChanges.Count; int nbTreeChanges = Removed.Count + Renamed.Count + Copied.Count + SymLinks.Count + Versions.Count(v => !v.InRawChangeSet && v.Names.Count > 0 && !v.Version.Element.IsDirectory); if (nbFileChanges == 0) { return(nbTreeChanges > 0 ? nbTreeChanges + " tree modification" + (nbTreeChanges > 1 ? "s" : "") : "No actual change"); } var allComments = interestingFileChanges.Where(v => !string.IsNullOrWhiteSpace(v.Version.Comment)) .Select(v => new { Name = v.Names[0], v.Version.Comment }) .GroupBy(e => (e.Comment ?? "").Trim().Replace("\r", "")) .OrderByDescending(g => g.Count()) .ToDictionary(g => g.Key, g => g.Select(v => v.Name).ToList()); string title; if (nbTreeChanges > 0) { title = string.Format("{0} file modification{1} and {2} tree modification{3}", nbFileChanges, (nbFileChanges > 1 ? "s" : ""), nbTreeChanges, nbTreeChanges > 1 ? "s" : ""); } else { title = string.Format("{0} file modification{1}", nbFileChanges, (nbFileChanges > 1 ? "s" : "")); } if (allComments.Count == 0) { return(title + ": " + DisplayFileNames(interestingFileChanges.Select(v => v.Names[0]).ToList(), false)); } var mostFrequentComment = allComments.First(); // no multi-line comment as title bool useMostFrequentCommentAsTitle = mostFrequentComment.Value.Count >= nbFileChanges / 2 + 1 && !mostFrequentComment.Key.Contains("\n"); if (useMostFrequentCommentAsTitle) { title = mostFrequentComment.Key + " (" + title + ")"; } if (useMostFrequentCommentAsTitle && allComments.Count == 1) { return(title + ": " + DisplayFileNames(interestingFileChanges.Select(v => v.Names[0]).ToList(), false)); } var sb = new StringBuilder(title); sb.Append("\n"); foreach (var comment in allComments) { sb.Append("\n"); sb.Append(DisplayFileNames(comment.Value, true)); sb.Append(":\n\t"); sb.Append(comment.Key.Replace("\n", "\n\t")); } return(sb.ToString()); }