public void buildCompositeCommits() throws IOException { revWalk = new RevWalk(repository); ByteArrayOutputStream diffTexts = new ByteArrayOutputStream(); DiffFormatter df = new DiffFormatter(diffTexts); df.setRepository(repository); df.setDiffComparator(RawTextComparator.WS_IGNORE_ALL); df.setContext(0); df.setDiffAlgorithm(DiffAlgorithm.getAlgorithm(SupportedAlgorithm.HISTOGRAM)); df.setDetectRenames(true); for (int idx = 0; idx < _commits.size(); idx++) { RevCommit commit = revWalk.parseCommit(_commits.get(idx)); int p_count = commit.getParentCount(); if (p_count == 0) { throw new RuntimeException("commit with no parent ?!?!"); } RevCommit p = revWalk.parseCommit(commit.getParent(0).getId()); List<DiffEntry> diffs = df.scan(p.getTree(), commit.getTree()); for (DiffEntry d : diffs) { CompositeDiff cd = new CompositeDiff(d, commit); if (ParsingUtils.isSourceFile(d.getOldPath()) || ParsingUtils.isSourceFile(d.getNewPath())) { extractCodeEdits(diffTexts, df, d, cd); } _diffs.add(cd); } } revWalk.release(); }
private Path path(final DiffEntry s) { final ChangeType changeType = s.getChangeType(); switch (changeType) { case DELETE: return Paths.get(s.getOldPath()); case ADD: return Paths.get(s.getNewPath()); case COPY: return Paths.get(s.getNewPath()); case MODIFY: return Paths.get(s.getNewPath()); case RENAME: return Paths.get(s.getNewPath()); default: throw new RuntimeException("Unrecognized change type: " + changeType); } }
private DiffEntry findRename(RevCommit parent, RevCommit commit, PathFilter path) throws IOException { if (renameDetector == null) return null; treeWalk.setFilter(TreeFilter.ANY_DIFF); treeWalk.reset(parent.getTree(), commit.getTree()); renameDetector.reset(); renameDetector.addAll(DiffEntry.scan(treeWalk)); for (DiffEntry ent : renameDetector.compute()) { if (isRename(ent) && ent.getNewPath().equals(path.getPath())) return ent; } return null; }
/** * Returns the diff between the two commits for the specified file or folder formatted as a patch. * * @param repository * @param baseCommit if base commit is unspecified, the patch is generated against the primary * parent of the specified commit. * @param commit * @param path if path is specified, the patch is generated only for the specified file or folder. * if unspecified, the patch is generated for the entire diff between the two commits. * @return patch as a string */ public static String getCommitPatch( Repository repository, RevCommit baseCommit, RevCommit commit, String path) { String diff = null; try { final ByteArrayOutputStream os = new ByteArrayOutputStream(); RawTextComparator cmp = RawTextComparator.DEFAULT; PatchFormatter df = new PatchFormatter(os); df.setRepository(repository); df.setDiffComparator(cmp); df.setDetectRenames(true); RevTree commitTree = commit.getTree(); RevTree baseTree; if (baseCommit == null) { if (commit.getParentCount() > 0) { final RevWalk rw = new RevWalk(repository); RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); baseTree = parent.getTree(); } else { // FIXME initial commit. no parent?! baseTree = commitTree; } } else { baseTree = baseCommit.getTree(); } List<DiffEntry> diffEntries = df.scan(baseTree, commitTree); if (path != null && path.length() > 0) { for (DiffEntry diffEntry : diffEntries) { if (diffEntry.getNewPath().equalsIgnoreCase(path)) { df.format(diffEntry); break; } } } else { df.format(diffEntries); } diff = df.getPatch(commit); df.flush(); } catch (Throwable t) { try { error(t, repository, "failed to generate commit diff!"); } catch (Exception e) { } } return diff; }
@Override public void format(DiffEntry ent) throws IOException { currentPath = diffStat.addPath(ent); nofLinesCurrent = 0; isOff = false; entry = ent; if (!truncated) { totalNofLinesPrevious = totalNofLinesCurrent; if (globalDiffLimit > 0 && totalNofLinesPrevious > globalDiffLimit) { truncated = true; isOff = true; } truncateTo = os.size(); } else { isOff = true; } if (truncated) { skipped.add(ent); } else { // Produce a header here and now String path; String id; if (ChangeType.DELETE.equals(ent.getChangeType())) { path = ent.getOldPath(); id = ent.getOldId().name(); } else { path = ent.getNewPath(); id = ent.getNewId().name(); } StringBuilder sb = new StringBuilder( MessageFormat.format( "<div class='header'><div class=\"diffHeader\" id=\"n{0}\"><i class=\"icon-file\"></i> ", id)); sb.append(StringUtils.escapeForHtml(path, false)).append("</div></div>"); sb.append("<div class=\"diff\"><table cellpadding='0'><tbody>\n"); os.write(sb.toString().getBytes()); } // Keep formatting, but if off, don't produce anything anymore. We just keep on counting. super.format(ent); if (!truncated) { // Close the table os.write("</tbody></table></div>\n".getBytes()); } }
/** * Workaround function for complex private methods in DiffFormatter. This sets the html for the * diff headers. * * @return */ public String getHtml() { String html = RawParseUtils.decode(os.toByteArray()); String[] lines = html.split("\n"); StringBuilder sb = new StringBuilder(); for (String line : lines) { if (line.startsWith("index")) { // skip index lines } else if (line.startsWith("new file") || line.startsWith("deleted file")) { // skip new file lines } else if (line.startsWith("\\ No newline")) { // skip no new line } else if (line.startsWith("---") || line.startsWith("+++")) { // skip --- +++ lines } else if (line.startsWith("diff")) { // skip diff lines } else { boolean gitLinkDiff = line.length() > 0 && line.substring(1).startsWith("Subproject commit"); if (gitLinkDiff) { sb.append("<tr><th class='diff-line'></th><th class='diff-line'></th>"); if (line.charAt(0) == '+') { sb.append("<th class='diff-state diff-state-add'></th><td class=\"diff-cell add2\">"); } else { sb.append( "<th class='diff-state diff-state-sub'></th><td class=\"diff-cell remove2\">"); } line = StringUtils.escapeForHtml(line.substring(1), false); } sb.append(line); if (gitLinkDiff) { sb.append("</td></tr>"); } sb.append('\n'); } } if (truncated) { sb.append( MessageFormat.format( "<div class='header'><div class='diffHeader'>{0}</div></div>", StringUtils.escapeForHtml( getMsg("gb.diffTruncated", "Diff truncated after the above file"), false))); // List all files not shown. We can be sure we do have at least one path in skipped. sb.append( "<div class='diff'><table cellpadding='0'><tbody><tr><td class='diff-cell' colspan='4'>"); String deletedSuffix = StringUtils.escapeForHtml(getMsg("gb.diffDeletedFileSkipped", "(deleted)"), false); boolean first = true; for (DiffEntry entry : skipped) { if (!first) { sb.append('\n'); } if (ChangeType.DELETE.equals(entry.getChangeType())) { sb.append( "<span id=\"n" + entry.getOldId().name() + "\">" + StringUtils.escapeForHtml(entry.getOldPath(), false) + ' ' + deletedSuffix + "</span>"); } else { sb.append( "<span id=\"n" + entry.getNewId().name() + "\">" + StringUtils.escapeForHtml(entry.getNewPath(), false) + "</span>"); } first = false; } skipped.clear(); sb.append("</td></tr></tbody></table></div>"); } return sb.toString(); }
public static List<PathChangeModel> getFilesInCommit(Repository repository, RevCommit commit) { List<PathChangeModel> list = new ArrayList<PathChangeModel>(); if (!hasCommits(repository)) { return list; } RevWalk rw = new RevWalk(repository); try { if (commit == null) { ObjectId object = getDefaultBranch(repository); commit = rw.parseCommit(object); } if (commit.getParentCount() == 0) { TreeWalk tw = new TreeWalk(repository); tw.reset(); tw.setRecursive(true); tw.addTree(commit.getTree()); while (tw.next()) { list.add( new PathChangeModel( tw.getPathString(), tw.getPathString(), 0, tw.getRawMode(0), commit.getId().getName(), ChangeType.ADD)); } tw.release(); } else { RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE); df.setRepository(repository); df.setDiffComparator(RawTextComparator.DEFAULT); df.setDetectRenames(true); List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree()); for (DiffEntry diff : diffs) { if (diff.getChangeType().equals(ChangeType.DELETE)) { list.add( new PathChangeModel( diff.getOldPath(), diff.getOldPath(), 0, diff.getNewMode().getBits(), commit.getId().getName(), diff.getChangeType())); } else { list.add( new PathChangeModel( diff.getNewPath(), diff.getNewPath(), 0, diff.getNewMode().getBits(), commit.getId().getName(), diff.getChangeType())); } } } } catch (Throwable t) { // todo Logger.error(t, t.getMessage()); } finally { rw.dispose(); } return list; }
protected String doDiff(Git git, String objectId, String baseObjectId, String path) { Repository r = git.getRepository(); /* RevCommit commit = JGitUtils.getCommit(r, objectId); ObjectId current; if (isNotBlank(objectId)) { current = BlobUtils.getId(r, objectId, blobPath); } else { current = CommitUtils.getHead(r).getId(); } ObjectId previous; if (isNotBlank(baseObjectId)) { previous = BlobUtils.getId(r, baseObjectId, blobPath); } else { RevCommit revCommit = CommitUtils.getCommit(r, current); RevCommit[] parents = revCommit.getParents(); if (parents.length == 0) { throw new IllegalArgumentException("No parent commits!"); } else { previous = parents[0]; } } Collection<Edit> changes = BlobUtils.diff(r, previous, current); // no idea how to format Collection<Edit> :) */ RevCommit commit; if (Strings.isNotBlank(objectId)) { commit = CommitUtils.getCommit(r, objectId); } else { commit = CommitUtils.getHead(r); } RevCommit baseCommit = null; if (Strings.isNotBlank(baseObjectId)) { baseCommit = CommitUtils.getCommit(r, baseObjectId); } ByteArrayOutputStream buffer = new ByteArrayOutputStream(); RawTextComparator cmp = RawTextComparator.DEFAULT; DiffFormatter formatter = new DiffFormatter(buffer); formatter.setRepository(r); formatter.setDiffComparator(cmp); formatter.setDetectRenames(true); RevTree commitTree = commit.getTree(); RevTree baseTree; try { if (baseCommit == null) { if (commit.getParentCount() > 0) { final RevWalk rw = new RevWalk(r); RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); rw.dispose(); baseTree = parent.getTree(); } else { // FIXME initial commit. no parent?! baseTree = commitTree; } } else { baseTree = baseCommit.getTree(); } List<DiffEntry> diffEntries = formatter.scan(baseTree, commitTree); if (path != null && path.length() > 0) { for (DiffEntry diffEntry : diffEntries) { if (diffEntry.getNewPath().equalsIgnoreCase(path)) { formatter.format(diffEntry); break; } } } else { formatter.format(diffEntries); } formatter.flush(); return buffer.toString(); } catch (IOException e) { throw new RuntimeIOException(e); } }
/** * Returns the diff between two commits for the specified file. * * @param repository * @param baseCommit if base commit is null the diff is to the primary parent of the commit. * @param commit * @param path if the path is specified, the diff is restricted to that file or folder. if * unspecified, the diff is for the entire commit. * @param outputType * @return the diff */ public static DiffOutput getDiff( Repository repository, RevCommit baseCommit, RevCommit commit, String path, DiffOutputType outputType) { DiffStat stat = null; String diff = null; try { final ByteArrayOutputStream os = new ByteArrayOutputStream(); RawTextComparator cmp = RawTextComparator.DEFAULT; DiffFormatter df; switch (outputType) { case HTML: df = new GitBlitDiffFormatter(os, commit.getName()); break; case PLAIN: default: df = new DiffFormatter(os); break; } df.setRepository(repository); df.setDiffComparator(cmp); df.setDetectRenames(true); RevTree commitTree = commit.getTree(); RevTree baseTree; if (baseCommit == null) { if (commit.getParentCount() > 0) { final RevWalk rw = new RevWalk(repository); RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); rw.dispose(); baseTree = parent.getTree(); } else { // FIXME initial commit. no parent?! baseTree = commitTree; } } else { baseTree = baseCommit.getTree(); } List<DiffEntry> diffEntries = df.scan(baseTree, commitTree); if (path != null && path.length() > 0) { for (DiffEntry diffEntry : diffEntries) { if (diffEntry.getNewPath().equalsIgnoreCase(path)) { df.format(diffEntry); break; } } } else { df.format(diffEntries); } if (df instanceof GitBlitDiffFormatter) { // workaround for complex private methods in DiffFormatter diff = ((GitBlitDiffFormatter) df).getHtml(); stat = ((GitBlitDiffFormatter) df).getDiffStat(); } else { diff = os.toString(); } df.flush(); } catch (Throwable t) { try { error(t, repository, "failed to generate commit diff!"); } catch (Exception e) { } } return new DiffOutput(outputType, diff, stat); }
public String getDiffText(String str) { int filenubs = 0; int lines = 0; FileRepositoryBuilder builder = new FileRepositoryBuilder(); File gitDir = new File("F:/work/demo-rio/.git"); Repository repository = null; try { if (git == null) { git = Git.open(gitDir); } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } try { String cid = str; repository = builder.setGitDir(gitDir).readEnvironment().findGitDir().build(); RevWalk walk = new RevWalk(repository); ObjectId objId = ObjectId.fromString(cid); RevCommit commit = walk.parseCommit(objId); System.out.println(commit.getFullMessage()); TreeWalk tw = new TreeWalk(repository); RevCommit[] parent_commits = commit.getParents(); if (parent_commits.length == 0) { throw new Exception("当前只有一个版本"); } ObjectId objId2 = parent_commits[0].toObjectId(); RevCommit paren_commit = walk.parseCommit(objId2); tw.addTree(paren_commit.getTree()); tw.addTree(commit.getTree()); tw.setRecursive(true); ByteArrayOutputStream out = new ByteArrayOutputStream(); DiffFormatter df = new DiffFormatter(out); df.setRepository(git.getRepository()); RenameDetector rd = new RenameDetector(repository); rd.addAll(DiffEntry.scan(tw)); List<DiffEntry> diffEntries = rd.compute(); if (diffEntries != null || diffEntries.size() != 0) { Iterator<DiffEntry> iterator = new ArrayList<DiffEntry>(diffEntries).iterator(); DiffEntry diffEntry = null; while (iterator.hasNext()) { diffEntry = iterator.next(); String changeType = diffEntry.getChangeType().toString(); String type = ""; if (changeType.equals("DELETE")) { type = ConfigUtil.getFileType(diffEntry.getOldPath()); filenubs++; System.out.println(diffEntry.getOldPath()); } else { type = ConfigUtil.getFileType(diffEntry.getNewPath()); filenubs++; System.out.println(diffEntry.getNewPath()); } // 检查文件的后缀 // System.out.println(type); if (fileTypes.contains(type)) { df.format(diffEntry); String diffText = out.toString("UTF-8"); lines += scanDiffText(diffText); } } } } catch (Exception e) { e.printStackTrace(); } return filenubs + "&" + lines; // System.out.println("the changed file nubs: "+ filenubs); // System.out.println("the changed linr nubs: "+ lines); }