如何使用JGit获取文件中的更改列表?

时间:2016-10-08 17:17:52

标签: java eclipse git jgit

使用JGit,我希望git log --full-history -p -1 <hash-id>尽可能获得提交文件中的更改列表。

这可能吗?如果是这样,你怎么做?

我知道如何获得每次提交,并查看提交消息:

//Load repo
FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repo = builder.setGitDir(new File("/path/to/repo/.git")).setMustExist(true).build();
Git git = new Git(repo);
//get commits
Iterable<RevCommit> log = git.log().call();
for (RevCommit commit : log) {
    //Shows the hashid
    System.out.println("LogCommit: " + commit);
    //Shows only commit message
    String logMessage = commit.getFullMessage();
    System.out.println("LogMessage: " + logMessage);
}
git.close();

是什么让我可以获得文件中的更改?

例如我写道:

git log --full-history -p -1 8309c1262e1b7ffce8fc86efc1ae5777a4a96777

回复是

commit 8309c1262e1b7ffce8fc86efc1ae5777a4a96777
Author: <redacted>
Date:   Thu Aug 4 12:15:23 2016 -0400

    Fixed typo in commit

diff --git a/Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java b/Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java
index fa55e7e..4f3c155 100644
--- a/Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java
+++ b/Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java
@@ -56,6 +57,7 @@ public abstract class BaseService {

     protected AssertionType getAssertion(WebServiceContext context, AssertionType assertionIn) {
         AssertionType assertion;
-        WSAHeaderHelper wsaHlpr = new WSAHeaderHelper();
+        WSAHeaderHelper wsaHelper = new WSAHeaderHelper();
         if (assertionIn == null) {
             assertion = SAML2AssertionExtractor.getInstance().extractSamlAssertion(context);

我希望得到以下内容。变化是一个补课:

//Load repo
FileRepositoryBuilder builder = new FileRepositoryBuilder();
Repository repo = builder.setGitDir(new File("/path/to/repo/.git")).setMustExist(true).build();
Git git = new Git(repo);
//get commits
Iterable<RevCommit> log = git.log().call();
for (RevCommit commit : log) {
    //Shows the hashid
    System.out.println("LogCommit: " + commit);
    //Shows only commit message
    String logMessage = commit.getFullMessage();
    System.out.println("LogMessage: " + logMessage);
    List<Change> changes = commit.getChanges();
    for(Change change: changes):
        System.out.println("File: " + change.getFile());
        System.out.println("Change: " + change.getChange());
        System.out.println("ChangeType: " + change.getChangeType());
}
git.close();

输出看起来像:

LogCommit: 8309c1262e1b7ffce8fc86efc1ae5777a4a96777
LogMessage: Fixed typo in commit
File: Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java
Change: WSAHeaderHelper wsaHlpr = new WSAHeaderHelper();
ChangeType: D
File: Product/Production/Common/CONNECTCoreLib/src/main/java/gov/hhs/fha/nhinc/messaging/server/BaseService.java
Change: WSAHeaderHelper wsaHelper = new WSAHeaderHelper();
ChangeType: A

2 个答案:

答案 0 :(得分:5)

JGit有一个非常简单的diff命令,可以将两次提交之间的更改的文本差异写入输出流。

例如:

OutputStream outputStream = ...
List<DiffEntry> diffEntries = git.diff().setOutputStream( outputStream ).call();

调用命令后返回的DiffEntry列表可能更有趣。 每个DiffEntry表示一个已更改的文件,并告知其路径名称,是否已添加,更改或删除,指向(blob-id&#39; s)旧内容和新内容等等。

从每个DiffEntry,您可以获得EditList,其中包含有关哪些行已更改的信息。

例如:

try( DiffFormatter diffFormatter = new DiffFormatter( DisabledOutputStream.INSTANCE ) ) {
  diffFormatter.setRepository( git.getRepository() );
  List<DiffEntry> diffEntries = diffFormatter.scan( oldTreeIterator, newTreeIterator );
  FileHeader fileHeader = diffFormatter.toFileHeader( diffEntries.get( 0 ) );
  return fileHeader.toEditList();
}

此代码还说明了如何在不使用DiffCommand的情况下获得具有更详细控制的差异条目。

就在最近,我写了一篇关于JGit差异API的完整博客文章。有关详细信息,请参阅此处:http://www.codeaffine.com/2016/06/16/jgit-diff/

答案 1 :(得分:4)

感谢Rüdiger Herrmann提供反馈,并感谢他gist上的部分代码。

我创建了一个方法diffCommit(String hashID),其中包含3个辅助函数,其工作方式与git log --full-history -p -1 <hash-id>.完全相同

private Git git;
private Repository repo;

private void diffCommit(String hashID) throws IOException {
    //Initialize repositories.
    FileRepositoryBuilder builder = new FileRepositoryBuilder();
    repo = builder.setGitDir(new File("/path/to/repo" + "/.git")).setMustExist(true)
            .build();
    git = new Git(repo);

    //Get the commit you are looking for.
    RevCommit newCommit;
    try (RevWalk walk = new RevWalk(repo)) {
        newCommit = walk.parseCommit(repo.resolve(hashID));
    }

    System.out.println("LogCommit: " + newCommit);
    String logMessage = newCommit.getFullMessage();
    System.out.println("LogMessage: " + logMessage);
    //Print diff of the commit with the previous one.
    System.out.println(getDiffOfCommit(newCommit));

}
//Helper gets the diff as a string.
private String getDiffOfCommit(RevCommit newCommit) throws IOException {

    //Get commit that is previous to the current one.
    RevCommit oldCommit = getPrevHash(newCommit);
    if(oldCommit == null){
        return "Start of repo";
    }
    //Use treeIterator to diff.
    AbstractTreeIterator oldTreeIterator = getCanonicalTreeParser(oldCommit);
    AbstractTreeIterator newTreeIterator = getCanonicalTreeParser(newCommit);
    OutputStream outputStream = new ByteArrayOutputStream();
    try (DiffFormatter formatter = new DiffFormatter(outputStream)) {
        formatter.setRepository(git.getRepository());
        formatter.format(oldTreeIterator, newTreeIterator);
    }
    String diff = outputStream.toString();
    return diff;
}
//Helper function to get the previous commit.
public RevCommit getPrevHash(RevCommit commit)  throws  IOException {

    try (RevWalk walk = new RevWalk(repo)) {
        // Starting point
        walk.markStart(commit);
        int count = 0;
        for (RevCommit rev : walk) {
            // got the previous commit.
            if (count == 1) {
                return rev;
            }
            count++;
        }
        walk.dispose();
    }
    //Reached end and no previous commits.
    return null;
}
//Helper function to get the tree of the changes in a commit. Written by Rüdiger Herrmann
private AbstractTreeIterator getCanonicalTreeParser(ObjectId commitId) throws IOException {
    try (RevWalk walk = new RevWalk(git.getRepository())) {
        RevCommit commit = walk.parseCommit(commitId);
        ObjectId treeId = commit.getTree().getId();
        try (ObjectReader reader = git.getRepository().newObjectReader()) {
            return new CanonicalTreeParser(null, reader, treeId);
        }
    }
}

以下是产生与git log --full-history

类似的输出的其他代码
public void commit_logs() throws IOException, NoHeadException, GitAPIException {
    List<String> logMessages = new ArrayList<String>();
    FileRepositoryBuilder builder = new FileRepositoryBuilder();
    Repository repo = builder.setGitDir(new File("/path/to/repo" + "/.git"))
            .setMustExist(true).build();
    git = new Git(repo);
    Iterable<RevCommit> log = git.log().call();
    RevCommit previousCommit = null;
    for (RevCommit commit : log) {
        if (previousCommit != null) {
            AbstractTreeIterator oldTreeIterator = getCanonicalTreeParser( previousCommit );
            AbstractTreeIterator newTreeIterator = getCanonicalTreeParser( commit );
            OutputStream outputStream = new ByteArrayOutputStream();
            try( DiffFormatter formatter = new DiffFormatter( outputStream ) ) {
              formatter.setRepository( git.getRepository() );
              formatter.format( oldTreeIterator, newTreeIterator );
            }
            String diff = outputStream.toString();
            System.out.println(diff);
        }
        System.out.println("LogCommit: " + commit);
        String logMessage = commit.getFullMessage();
        System.out.println("LogMessage: " + logMessage);
        logMessages.add(logMessage.trim());
        previousCommit = commit;
    }
    git.close();
}


  private AbstractTreeIterator getCanonicalTreeParser( ObjectId commitId ) throws IOException {
    try( RevWalk walk = new RevWalk( git.getRepository() ) ) {
      RevCommit commit = walk.parseCommit( commitId );
      ObjectId treeId = commit.getTree().getId();
      try( ObjectReader reader = git.getRepository().newObjectReader() ) {
        return new CanonicalTreeParser( null, reader, treeId );
      }
    }
  }