怎样通过JGit获得一次Commit的所有相关信息(如变更代码行数)

之前这篇博客中,我介绍了如何使用JGit获取一次Commit修改的文件列表。那如果我们想获得更多的统计信息呢?如每一个文件被修改的代码行数。

一般情况下,可以使用诸如:

git log --date-order --stat > change-details.txt

和:

git log --date-order --pretty=fuller --name-status > version-log-order.txt

的Git Log命令来获取多个Git Log的文本文件,再通过分析文本文件即可以得到。但是问题在于,例如这样的记录:

 fs/readdir.c | 128 +++++++++++++++++++++++++++++++++++++++++++----------------

如果文件路径特别长(在C、C++项目中一般不会出现,但是在较复杂的Java项目中是可能出现的),导致文件路径中可能出现省略号,从而使文件关联不准确。这时候我们就需要一些更准确的获取方法。

在给出代码之前,简单提一句,对于下面代码段中这条语句中的方法:

ObjectId versionId=Repo.resolve(versionTag);

可以看到其Java Doc:https://download.eclipse.org/jgit/site/5.3.0.201903130848-r/apidocs/org/eclipse/jgit/lib/Repository.html#resolve-java.lang.String-

JGit完整API文档链接:https://download.eclipse.org/jgit/site/5.3.0.201903130848-r/apidocs/index.html (可能会由版本变化而变化)

中介绍,其字符串参数可以是:SHA-1,也可以是Tag:id^{tag}: ensure id is a tag

我当时看文档的时候是在不了解id^{}是个什么鬼。尝试了一下,发现直接给出tag对应的字符串即可。

下面直接给出代码,主要参考了这位网友的介绍:https://blog.csdn.net/u012621115/article/details/52171679

(CSDN这个排版不能正常缩进了,也是呵呵呵呵了)

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;

public class JGitMetricsBack {
	
	static Repository Repo;
	
	static void printTime(int commitTime) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String timestampString=String.valueOf(commitTime);
        Long timestamp = Long.parseLong(timestampString) * 1000;
        String date = formatter.format(new Date(timestamp));
        System.out.println("It's commit time: "+date);
	}
	
	static List<DiffEntry> getChangedFileList(RevCommit revCommit, Repository repo) {
		List<DiffEntry> returnDiffs = null;
		
		try {
			RevCommit previsouCommit=getPrevHash(revCommit,repo);
			if(previsouCommit==null)
				return null;
			ObjectId head=revCommit.getTree().getId();
			
			ObjectId oldHead=previsouCommit.getTree().getId();
			
			System.out.println("Printing diff between the Revisions: " + revCommit.getName() + " and " + previsouCommit.getName());

            // prepare the two iterators to compute the diff between
    		try (ObjectReader reader = repo.newObjectReader()) {
        		CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
        		oldTreeIter.reset(reader, oldHead);
        		CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
        		newTreeIter.reset(reader, head);

        		// finally get the list of changed files
        		try (Git git = new Git(repo)) {
                    List<DiffEntry> diffs= git.diff()
            		                    .setNewTree(newTreeIter)
            		                    .setOldTree(oldTreeIter)
            		                    .call();
                    for (DiffEntry entry : diffs) {
//                        System.out.println("Entry: " + entry);
                    }
                    returnDiffs=diffs;
        		} catch (GitAPIException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    		}			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return returnDiffs;
	}
	
	public static RevCommit getPrevHash(RevCommit commit, Repository repo)  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;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
//		String versionTag="v2.6.19";//定位到某一次Commi,既可以使用Tag,也可以使用其hash
		String versionTag="9f79b78ef74436c7507bac6bfb7b8b989263bccb";
		String path="D:\\Projects\\Linux-Kernel\\linux-stable";
		FileRepositoryBuilder builder = new FileRepositoryBuilder();
		builder.setMustExist(true);
		builder.addCeilingDirectory(new File(path));
		builder.findGitDir(new File(path));
		try {
			Repo=builder.build();
			
			RevWalk walk = new RevWalk(Repo);
			ObjectId versionId=Repo.resolve(versionTag);
			RevCommit verCommit=walk.parseCommit(versionId);
			
			String commitName=verCommit.getName();
			System.out.println("This version is: "+versionTag+", It hash: "+commitName);//如果通过Tag定位,可以获得其SHA-1 Hash Value
			int verCommitTime=verCommit.getCommitTime();
			printTime(verCommitTime);//打印出本次Commit的时间
			
			System.out.println("The author is: "+verCommit.getAuthorIdent().getEmailAddress());//获得本次Commit Author的邮箱
			
			List<DiffEntry> diffFix=getChangedFileList(verCommit,Repo);//获取变更的文件列表
			
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			DiffFormatter df = new DiffFormatter(out);
//			df.setDiffComparator(RawTextComparator.WS_IGNORE_ALL);//如果加上这句,就是在比较的时候不计算空格,WS的意思是White Space
            df.setRepository(Repo); 
			
			for (DiffEntry entry : diffFix) {
				
				df.format(entry);
				String diffText = out.toString("UTF-8");
//				System.out.println(diffText);
				
				System.out.println(entry.getNewPath());//变更文件的路径
				
				FileHeader fileHeader = df.toFileHeader(entry);
                List<HunkHeader> hunks = (List<HunkHeader>) fileHeader.getHunks();
                int addSize = 0;
                int subSize = 0;
                for(HunkHeader hunkHeader:hunks){
                	EditList editList = hunkHeader.toEditList();
                	for(Edit edit : editList){
                		subSize += edit.getEndA()-edit.getBeginA();
                		addSize += edit.getEndB()-edit.getBeginB();
                	}
                }
                System.out.println("addSize="+addSize);//增加和减少的代码行数统计,我和Git Log核对了一下,还挺准确的。
                System.out.println("subSize="+subSize);
                out.reset();
			}
		} 
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值