How to show changes between commits with JGit

I am trying to show the git difference between two commits for a file. Basically, I did this as in https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/ShowChangedFilesBetweenCommits.java

You can see my full code at https://github.com/svenhornberg/JGitDiff

public class RepoDiff { public void compare(byte[] fileContentOld, byte[] fileContentNew) { try { Repository repository = createNewRepository(); Git git = new Git(repository); // create the file commitFileContent(fileContentOld, repository, git, true); commitFileContent(fileContentNew, repository, git, false); // The {tree} will return the underlying tree-id instead of the commit-id itself! ObjectId oldHead = repository.resolve("HEAD^^^^{tree}"); //here is my nullpointer ObjectId head = repository.resolve("HEAD^{tree}"); System.out.println("Printing diff between tree: " + oldHead + " and " + head); // prepare the two iterators to compute the diff between ObjectReader reader = repository.newObjectReader(); CanonicalTreeParser oldTreeIter = new CanonicalTreeParser(); oldTreeIter.reset(reader, oldHead); CanonicalTreeParser newTreeIter = new CanonicalTreeParser(); newTreeIter.reset(reader, head); // finally get the list of changed files List<DiffEntry> diffs= new Git(repository).diff() .setNewTree(newTreeIter) .setOldTree(oldTreeIter) .call(); for (DiffEntry entry : diffs) { System.out.println("Entry: " + entry); } System.out.println("Done"); } catch (Exception exception) { exception.printStackTrace(); } } /** * Adds and optionally commits fileContent to a repository * @param commit True if file should be committed, False if not * @throws Exception catch all for testing */ private void commitFileContent(byte[] fileContent, Repository repository, Git git, boolean commit) throws Exception { File myfile = new File(repository.getDirectory().getParent(), "testfile"); myfile.createNewFile(); FileOutputStream fos = new FileOutputStream (myfile); ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(fileContent); baos.writeTo(fos); // run the add git.add().addFilepattern("testfile").call(); if(commit) { // and then commit the changes git.commit().setMessage("Added fileContent").call(); } fos.close(); } /** * Helperfunction from * https://github.com/centic9/jgit-cookbook */ public static Repository createNewRepository() throws IOException { // prepare a new folder File localPath = File.createTempFile("TestGitRepository", ""); localPath.delete(); // create the directory Repository repository = FileRepositoryBuilder.create(new File( localPath, ".git")); repository.create(); return repository; } } 

The code displays this message:

 Printing diff between tree: null and AnyObjectId[c11a3a58c23b0dd6e541c4bcd553197772626bc6] java.lang.NullPointerException at org.eclipse.jgit.internal.storage.file.UnpackedObjectCache$Table.index(UnpackedObjectCache.java:146) at org.eclipse.jgit.internal.storage.file.UnpackedObjectCache$Table.contains(UnpackedObjectCache.java:109) at org.eclipse.jgit.internal.storage.file.UnpackedObjectCache.isUnpacked(UnpackedObjectCache.java:64) at org.eclipse.jgit.internal.storage.file.ObjectDirectory.openObject(ObjectDirectory.java:367) at org.eclipse.jgit.internal.storage.file.WindowCursor.open(WindowCursor.java:145) at org.eclipse.jgit.treewalk.CanonicalTreeParser.reset(CanonicalTreeParser.java:202) at javadiff.RepoDiff.compare(RepoDiff.java:40) at javadiff.GitDiff.main(GitDiff.java:30) 

the next line should be false, but it looks like an example from jgit-cookbook

  ObjectId oldHead = repository.resolve("HEAD^^^^{tree}"); //here is my nullpointer 

I tested HEAD^1{Tree} , but this does not work, it looks like {tree} should be in the line to resolve the tree instead of the commit identifier. Any ideas to make it work?

+8
source share
2 answers

To get the commit head tree, call

 git.getRepository().resolve( "HEAD^{tree}" ) 

and to get the parent HEAD commit tree, call

 git.getRepository().resolve( "HEAD~1^{tree}" ) 

Look for "Git Caret and Tilde" if you are interested in more details.

To summarize, here is a snippet that calculates the difference of two commits:

 File file = new File( git.getRepository().getWorkTree(), "file.txt" ); writeFile( file, "first version" ); RevCommit newCommit = commitChanges(); writeFile( file, "second version" ); RevCommit oldCommit = commitChanges(); ObjectReader reader = git.getRepository().newObjectReader(); CanonicalTreeParser oldTreeIter = new CanonicalTreeParser(); ObjectId oldTree = git.getRepository().resolve( "HEAD^{tree}" ); // equals newCommit.getTree() oldTreeIter.reset( reader, oldTree ); CanonicalTreeParser newTreeIter = new CanonicalTreeParser(); ObjectId newTree = git.getRepository().resolve( "HEAD~1^{tree}" ); // equals oldCommit.getTree() newTreeIter.reset( reader, newTree ); DiffFormatter df = new DiffFormatter( new ByteArrayOutputStream() ); // use NullOutputStream.INSTANCE if you don't need the diff output df.setRepository( git.getRepository() ); List<DiffEntry> entries = df.scan( oldTreeIter, newTreeIter ); for( DiffEntry entry : entries ) { System.out.println( entry ); } private RevCommit commitChanges() throws GitAPIException { git.add().addFilepattern( "." ).call(); return git.commit().setMessage( "commit message" ).call(); } private static void writeFile( File file, String content ) throws IOException { FileOutputStream outputStream = new FileOutputStream( file ); outputStream.write( content.getBytes( "UTF-8" ) ); outputStream.close(); } 

For further discussion on displaying changes between commits, you can read this in-depth discussion of the JGit diff API, which can be found here: http://www.codeaffine.com/2016/06/16/jgit-diff/

+10
source

I use the following code to print the differences between two commits. Using DiffFormatter.scan seems simpler than other solutions I've seen on SO.

I may be missing some cases where this is not supported, but it is great for our use.

 public static void main(String[] args) throws Exception { Repository repository = new FileRepositoryBuilder() .setGitDir(new File("c:/temp/jgit-test/.git")).build(); // Here we get the head commit and it first parent. // Adjust to your needs to locate the proper commits. RevCommit headCommit = getHeadCommit(repository); RevCommit diffWith = headCommit.getParent(0); FileOutputStream stdout = new FileOutputStream(FileDescriptor.out); try (DiffFormatter diffFormatter = new DiffFormatter(stdout)) { diffFormatter.setRepository(repository); for (DiffEntry entry : diffFormatter.scan(diffWith, headCommit)) { diffFormatter.format(diffFormatter.toFileHeader(entry)); } } } private static RevCommit getHeadCommit(Repository repository) throws Exception { try (Git git = new Git(repository)) { Iterable<RevCommit> history = git.log().setMaxCount(1).call(); return history.iterator().next(); } } 
+1
source

Source: https://habr.com/ru/post/979286/


All Articles