jgit比较项目不同版本间的差异及统计代码总行数

通过比较git项目两个版本,找出变动的代码,并统计代码的增量和减量

jgit版本

<dependency>
    <groupId>org.eclipse.jgit</groupId>
    <artifactId>org.eclipse.jgit</artifactId>
    <version>4.4.1.201607150455-r</version>
</dependency>
<dependency>
    <groupId>org.gitective</groupId>
    <artifactId>gitective-core</artifactId>
    <version>0.9.9</version>
</dependency>

测试代码:

package com.yy.jgit;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jgit.api.Git;
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.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.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.junit.Before;
import org.junit.Test;

import junit.framework.TestCase;

/**   
* @author <a href= "mailto:" style="color:##E0E;">牵手无奈</a>
* @date 2016年8月9日 下午3:08:35 
* @version V1.0   
*/
public class JgitTest extends TestCase {
	
    String gitFilePath = "D:\\workspace3\\feedback-classify";
    File root = new File(gitFilePath);
    Git git;
    Repository repository ;
	
    @Before
    public void init(){
    	try {
			git =Git.open(root);
			repository = git.getRepository();
			
		} catch (IOException e) {
			e.printStackTrace();
		} 
    }
    
    @Test
    public void test3() throws Exception{
    	init();
    	RevWalk walk = new RevWalk(repository);
    	List<RevCommit> commitList = new ArrayList<>();
    	//获取最近提交的两次记录
    	Iterable<RevCommit> commits = git.log().setMaxCount(2).call();
    	for(RevCommit commit:commits){
    		commitList.add(commit);
    		System.out.println(commit.getFullMessage());
        	System.out.println(commit.getAuthorIdent().getWhen());
    	}
    	
    	
    	
    	
    	if(commitList.size()==2){
        	AbstractTreeIterator newTree = prepareTreeParser(commitList.get(0));
        	AbstractTreeIterator oldTree = prepareTreeParser(commitList.get(1));
        	List<DiffEntry> diff = git.diff().setOldTree(oldTree).setNewTree(newTree).setShowNameAndStatusOnly(true).call();
            
            
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            DiffFormatter df = new DiffFormatter(out); 
            //设置比较器为忽略空白字符对比(Ignores all whitespace)
            df.setDiffComparator(RawTextComparator.WS_IGNORE_ALL);
            df.setRepository(git.getRepository()); 
            System.out.println("------------------------------start-----------------------------");
            //每一个diffEntry都是第个文件版本之间的变动差异
            for (DiffEntry diffEntry : diff) { 
            	//打印文件差异具体内容
                df.format(diffEntry);  
                String diffText = out.toString("UTF-8");  
                System.out.println(diffText);  
                
                //获取文件差异位置,从而统计差异的行数,如增加行数,减少行数
                FileHeader fileHeader = df.toFileHeader(diffEntry);
                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);
                System.out.println("subSize="+subSize);
                System.out.println("------------------------------end-----------------------------");
                out.reset();  
           } 
            
    	}
    	
	}
    
    public AbstractTreeIterator prepareTreeParser(RevCommit commit){
    	System.out.println(commit.getId());
    	try (RevWalk walk = new RevWalk(repository)) {
    		System.out.println(commit.getTree().getId());
            RevTree tree = walk.parseTree(commit.getTree().getId());

            CanonicalTreeParser oldTreeParser = new CanonicalTreeParser();
            try (ObjectReader oldReader = repository.newObjectReader()) {
                oldTreeParser.reset(oldReader, tree.getId());
            }

            walk.dispose();

            return oldTreeParser;
    }catch (Exception e) {
		// TODO: handle exception
	}
    	return null;
    }
//统计指定版本代码总行数
<pre name="code" class="java">public long getAllFileLines(RevCommit commit){
    	TreeWalk treeWalk = new TreeWalk(repository);
    	long size = 0;
    	try {
			treeWalk.addTree(commit.getTree());
			treeWalk.setRecursive(true);
			MutableObjectId id = new MutableObjectId();
			while(treeWalk.next()){
				treeWalk.getObjectId(id, 0);
				String filePath = treeWalk.getPathString();
				if(filePathFilter.accept(new ChangeFile(filePath))){
					int lines =countAddLine(BlobUtils.getContent(repository, id.toObjectId()));
					size +=lines;
				}
				
			}
		} catch (MissingObjectException e) {
			m_logger.error("error:"+e);
		} catch (IncorrectObjectTypeException e) {
			m_logger.error("error:"+e);
		} catch (CorruptObjectException e) {
			m_logger.error("error:"+e);
		} catch (IOException e) {
			m_logger.error("error:"+e);
		}
    	return size;
    }
    
    /**统计非空白行数
     * @param content
     * @return
     */
    public int countAddLine(String content){
    	char[] chars = content.toCharArray();
		int sum = 0;
		boolean notSpace = false;
		for(char ch: chars){
			if(ch =='\n' && notSpace){
				sum++;
				notSpace = false;
			}else if(ch > ' '){
				notSpace = true;
			}
		}
		//最后一行没有换行时,如果有非空白字符,则+1
		if(notSpace){
			sum++;
		}
		return sum;
    }


 


通过例子介绍使用方法如下: 1.差异统计 统计某一个版本代码包相对于一个原始的基线代码包,变动的代码量 以及变动的代码量中各语言非空非注释行(NBNC)的结果 缺省执行的就是差异统计,直接跟上两个代码包的目录即可 实际使用中,可能会有文件名和目录名大小写不一致的情况,如果希望忽略 文件名大小写的差异,需要使用 --ignore-case 参,否则两个一样的文件 一个会算作删除,一个会算作新增 Diffcount [test\sp1] and [test\sp2] result: LANG ADD MOD DEL A&M BLK CMT NBNC RATE ----------------------------------------------------------------------- C 44 7 26 51 8 11 35 1.00 Pascal 0 0 25 0 0 0 0 0.23 Java 7 4 11 11 0 3 9 0.41 Config 31 4 0 35 1 0 34 0.12 XML 126 0 0 126 2 0 124 0.12 ----------------------------------------------------------------------- Convert all NBNC lines to standard C Total: 57.65 (standard C lines) ADD MOD DEL A&M BLK CMT NBNC RATE 的 含义分别为: 新增、修改、删除、新增+修改、空行、注释、非空非注释行、标准C折算率 2.代码统计: 如果需要,可以把diffcount当作普通的代码统计工具,统计一个代码代码统计使用 -c (或者--count-only)参, 在diffcount目录下执行 执行结果如下: Counting package [test\count] result: LANG TOTAL BLK CMT NBNC RATE ----------------------------------------------------------------------- C 203 46 61 101 1.00 C++ 57 7 25 25 0.42 Pascal 117 24 17 79 0.23 Java 71 7 24 40 0.41 ASM 129 34 12 85 2.50 C# 18 1 1 17 0.20 Basic 447 140 20 295 0.21 Perl 97 4 26 74 0.16 TCL/TK 91 12 26 54 0.50 Config 116 13 0 103 0.12 XML 126 2 0 124 0.12 ----------------------------------------------------------------------- Convert all NBNC lines to standard C Total: 490.00 (standard C lines) 如果想显示每一个文件的具体信息,请使用 --print-files-info 参
你可以使用以下代码比较两个版本的同一个文件的差异: ```java Git git = Git.open(new File("/path/to/repo")); Repository repo = git.getRepository(); // 获取两个版本的ObjectId ObjectId oldVersion = repo.resolve("HEAD~1"); ObjectId newVersion = repo.resolve("HEAD"); // 获取文件内容 ObjectReader reader = repo.newObjectReader(); CanonicalTreeParser oldTreeIter = new CanonicalTreeParser(); oldTreeIter.reset(reader, repo.parseCommit(oldVersion).getTree().getId()); CanonicalTreeParser newTreeIter = new CanonicalTreeParser(); newTreeIter.reset(reader, repo.parseCommit(newVersion).getTree().getId()); List<DiffEntry> diffs= git.diff() .setOldTree(oldTreeIter) .setNewTree(newTreeIter) .call(); // 遍历差异 for (DiffEntry diff : diffs) { System.out.println("Diff: " + diff.getChangeType() + " " + diff.getOldPath() + " -> " + diff.getNewPath()); // 获取差异的具体内容 FileHeader fileHeader = git.diff() .setOldTree(oldTreeIter) .setNewTree(newTreeIter) .setPath(diff.getNewPath()) .call() .get(0) .toFileHeader(); List<String> diffContent = fileHeader.toEditList() .stream() .flatMap(edit -> edit.getLines().stream()) .collect(Collectors.toList()); System.out.println("Diff content: " + diffContent); } ``` 其中,`/path/to/repo` 为本地 Git 仓库的路径,`HEAD~1` 表示上一个版本,`HEAD` 表示当前版本。`diffs` 列表中存放的是差异的元据,例如变更类型、旧文件路径、新文件路径等。你可以通过 `getOldPath()` 和 `getNewPath()` 方法来判断差异是修改、新增还是删除。如果想获取差异的具体内容,可以使用 `git.diff().setPath()` 指定文件路径,然后调用 `toFileHeader()` 方法获取 `FileHeader` 对象,最后通过 `toEditList()` 方法遍历差异的具体内容。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值