Created
May 18, 2018 20:15
-
-
Save robisonsantos/7a35b79c86eedb58a31402d3ffca63f6 to your computer and use it in GitHub Desktop.
Simple jGit git diff --raw implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.apache.commons.lang3.StringUtils; | |
import org.eclipse.jgit.api.Git; | |
import org.eclipse.jgit.api.errors.GitAPIException; | |
import org.eclipse.jgit.diff.DiffEntry; | |
import org.eclipse.jgit.lib.ObjectReader; | |
import org.eclipse.jgit.lib.Repository; | |
import org.eclipse.jgit.revwalk.RevCommit; | |
import org.eclipse.jgit.revwalk.RevTree; | |
import org.eclipse.jgit.revwalk.RevWalk; | |
import org.eclipse.jgit.treewalk.AbstractTreeIterator; | |
import org.eclipse.jgit.treewalk.CanonicalTreeParser; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.IOException; | |
import java.nio.file.Files; | |
import java.nio.file.StandardCopyOption; | |
import java.nio.file.StandardOpenOption; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Optional; | |
import static java.util.stream.Collectors.joining; | |
public class RawDiff { | |
public static void main(String[] args) throws IOException, GitAPIException { | |
Repository repo = createSampleRepo().orElseThrow(() -> new RuntimeException("Fail to create sample repo")); | |
System.out.println(String.format("Repository created at: %s", repo.getDirectory().getAbsolutePath())); | |
for (int i = 1; i < 6; i++) { | |
printRawDiff(repo, i); | |
} | |
FileUtils.deleteDirectory(repo.getDirectory().getParentFile()); | |
} | |
private static void printRawDiff(Repository repo, int commitsFromHead) throws IOException, GitAPIException { | |
String commits = new String(new char[commitsFromHead]).replace("\0", "~"); | |
List<DiffEntry> diffs = getDiff(repo, "HEAD", "HEAD" + commits); | |
String rawDiff = diffs.stream().map(diff -> { | |
List<String> entry = new ArrayList<>(); | |
entry.add(StringUtils.leftPad(diff.getOldMode().toString(), 6, "0")); | |
entry.add(StringUtils.leftPad(diff.getNewMode().toString(), 6, "0")); | |
entry.add(diff.getOldId().name()); | |
entry.add(diff.getNewId().name()); | |
switch (diff.getChangeType()) { | |
case ADD: | |
case MODIFY: | |
case DELETE: | |
entry.add(diff.getChangeType().name().substring(0,1)); // A, M or D | |
break; | |
case COPY: | |
case RENAME: | |
entry.add(String.format("%s%d", diff.getChangeType().name().charAt(0), diff.getScore())); // C21, R43 | |
} | |
if (!diff.getOldPath().equals("/dev/null")) { | |
entry.add(diff.getOldPath()); | |
} | |
if (!diff.getNewPath().equals("/dev/null")) { | |
entry.add(diff.getNewPath()); | |
} | |
return entry.stream().collect(joining(" ")); | |
}).collect(joining("\n")); | |
System.out.println(String.format("---- git diff --raw HEAD%s HEAD ----", commits)); | |
System.out.println(rawDiff); | |
System.out.println(); | |
} | |
private static List<DiffEntry> getDiff(Repository repository, String after, String before) throws IOException, GitAPIException { | |
Git git = new Git(repository); | |
return git.diff().setOldTree(prepareTreeParser(repository, before)) | |
.setNewTree(prepareTreeParser(repository, after)) | |
.call(); | |
} | |
private static AbstractTreeIterator prepareTreeParser(Repository repository, String objectId) throws IOException { | |
// from the commit we can build the tree which allows us to construct the TreeParser | |
//noinspection Duplicates | |
try (RevWalk walk = new RevWalk(repository)) { | |
RevCommit commit = walk.parseCommit(repository.resolve(objectId)); | |
RevTree tree = walk.parseTree(commit.getTree().getId()); | |
CanonicalTreeParser treeParser = new CanonicalTreeParser(); | |
try (ObjectReader reader = repository.newObjectReader()) { | |
treeParser.reset(reader, tree.getId()); | |
} | |
walk.dispose(); | |
return treeParser; | |
} | |
} | |
private static Optional<Repository> createSampleRepo() { | |
Optional<Repository> repository = RepoUtils.createRepository(); | |
return repository.map(repo -> { | |
File file = createFile(repo.getDirectory().getParent(), "testFile"); | |
writeToFile(file, "This is a test"); | |
addAndCommit(repo, "firstCommit"); | |
writeToFile(file, "This is another test"); | |
addAndCommit(repo, "secondCommit"); | |
File file2 = createFile(repo.getDirectory().getParent(), "testFile2"); | |
writeToFile(file2, "This is a test"); | |
addAndCommit(repo, "thirdCommit"); | |
File file3 = renameFile(file2, "newFile"); | |
addAndCommit(repo, "Renamed file"); | |
File file4 = copyTo("copiedFile", file3); | |
addAndCommit(repo,"Copied file"); | |
deleteFile(file4); | |
addAndCommit(repo, "File deleted"); | |
return repo; | |
}); | |
} | |
private static void deleteFile(File file) { | |
try { | |
Files.deleteIfExists(file.toPath()); | |
} catch (IOException e) { | |
throw new RuntimeException("Could not delete file", e); | |
} | |
} | |
private static File copyTo(String newName, File file) { | |
File newFile = new File(file.getParent(), newName); | |
try { | |
return Files.copy(file.toPath(), newFile.toPath(), StandardCopyOption.REPLACE_EXISTING).toFile(); | |
} catch (IOException e) { | |
throw new RuntimeException("Could not copy file", e); | |
} | |
} | |
private static File renameFile(File file, String newName) { | |
File newFile = new File(file.getParent(), newName); | |
if (!file.renameTo(newFile)) { | |
throw new RuntimeException("Could not rename file"); | |
} | |
return newFile; | |
} | |
private static void addAndCommit(Repository repo, String commitMessage) { | |
try (Git git = new Git(repo)) { | |
// Add everything | |
git.add().setUpdate(true).addFilepattern(".").call(); | |
git.add().addFilepattern(".").call(); | |
git.commit().setMessage(commitMessage).call(); | |
} catch (GitAPIException e) { | |
throw new RuntimeException(e.getMessage(), e); | |
} | |
} | |
private static void writeToFile(File file, String content) { | |
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardOpenOption.APPEND)) { | |
writer.write(content); | |
writer.newLine(); | |
} catch (IOException ioe) { | |
throw new RuntimeException(ioe.getMessage(), ioe); | |
} | |
} | |
private static File createFile(String dirLocation, String fileName) { | |
File file = new File(dirLocation, fileName); | |
try { | |
if (!file.createNewFile()) { | |
throw new RuntimeException(String.format("Not able to create file %s", file)); | |
} | |
} catch (IOException ioe) { | |
throw new RuntimeException(ioe.getMessage(), ioe); | |
} | |
return file; | |
} | |
} | |
// After running this: | |
// ---- git diff --raw HEAD~ HEAD ---- | |
//100644 000000 0527e6bd2d76b45e2933183f1b506c7ac49f5872 0000000000000000000000000000000000000000 D copiedFile | |
// | |
//---- git diff --raw HEAD~~ HEAD ---- | |
// | |
// | |
//---- git diff --raw HEAD~~~ HEAD ---- | |
//000000 100644 0000000000000000000000000000000000000000 0527e6bd2d76b45e2933183f1b506c7ac49f5872 A newFile | |
//100644 000000 0527e6bd2d76b45e2933183f1b506c7ac49f5872 0000000000000000000000000000000000000000 D testFile2 | |
// | |
//---- git diff --raw HEAD~~~~ HEAD ---- | |
//000000 100644 0000000000000000000000000000000000000000 0527e6bd2d76b45e2933183f1b506c7ac49f5872 A newFile | |
// | |
//---- git diff --raw HEAD~~~~~ HEAD ---- | |
//000000 100644 0000000000000000000000000000000000000000 0527e6bd2d76b45e2933183f1b506c7ac49f5872 A newFile | |
//100644 100644 0527e6bd2d76b45e2933183f1b506c7ac49f5872 9b95249b27451b62b60a19cd1badf0b79a493538 M testFile testFile | |
// Git execution: | |
//|master ⇒ git diff --raw HEAD~ HEAD | |
//:100644 000000 0527e6b... 0000000... D copiedFile | |
// | |
//|master ⇒ git diff --raw HEAD~~ HEAD | |
// | |
//|master ⇒ git diff --raw HEAD~~~ HEAD | |
//:000000 100644 0000000... 0527e6b... A newFile | |
//:100644 000000 0527e6b... 0000000... D testFile2 | |
// | |
//|master ⇒ git diff --raw HEAD~~~~ HEAD | |
//:000000 100644 0000000... 0527e6b... A newFile | |
// | |
//|master ⇒ git diff --raw HEAD~~~~~ HEAD | |
//:000000 100644 0000000... 0527e6b... A newFile | |
//:100644 100644 0527e6b... 9b95249... M testFile |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment