Skip to content

Java操作Git (JGit)

JGit文档地址:https://github.com/centic9/jgit-cookbook
JGit是eclipse基金会下属的一个Java项目,用于在java环境下实现对git仓库的操作,包括的基本的clone pull push remote commit add等操作。底层的实现逻辑还是依赖了操作系统中已安装的Git软件,所以请确保安装了Git。

注意

jdk1.8使用5.13版本(含)
jdk11及以上使用5.13以上版本

POM依赖

xml
<!-- com.jcraft.jsch -->  
<dependency>  
	<groupId>com.jcraft</groupId>  
	<artifactId>jsch</artifactId>  
	<version>0.1.55</version>  
</dependency>  
<!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->  
<dependency>  
	<groupId>org.eclipse.jgit</groupId>  
	<artifactId>org.eclipse.jgit</artifactId>  
	<version>5.13.2.202306221912-r</version>  
</dependency>

为什么要使用 com.jcraft.jsch 包?因为jgit需要这个包,但jgit没有依赖它,需要你自己去导入这个依赖。

克隆仓库

java
try {
	CloneCommand cloneCommand = Git.cloneRepository();  
	cloneCommand.setURI(uri);  
	cloneCommand.setBranch(branch);  
	cloneCommand.setDirectory(new File(repositoryDir));  
	cloneCommand.setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password));
	Git git = cloneCommand.call();
} catch (Exception e) {  
	e.printStackTrace();
}

拉取代码

java
Git git = null;
try {
	git = Git.open(new File("仓库目录"));  
	PullCommand pull = git.pull();  
	pull.setRemote("origin");  
	pull.setCredentialsProvider(new UsernamePasswordCredentialsProvider("用户名", "密码"));  
	pull.setRemoteBranchName("分支名");  
	pull.call();
} catch (Exception e) {
	e.printStackTrace();
	//释放资源
	if (git != null && git.getRepository() != null) {  
		git.getRepository().close();  
	}
}

代码比对信息统计

java
public static void log(Repository repository, String commitId) {
	try (RevWalk revWalk = new RevWalk(repository)) {
		RevCommit revCommit = revWalk.parseCommit(ObjectId.fromString(commitId));  
		//只需要 1 个父提交  
		if (revCommit.getParents().length == 1) {
			//当前提交的父提交
			RevCommit parentCommit = revCommit.getParent(0);
			CommitCodeLinesBO ccl = codeDiff(repository, revCommit, parentCommit);
			//当前提交的commitId
			System.out.println(revCommit.getName());
			//父提交的commitId
			System.out.println(parentCommit.getName());
			//当前提交人信息
			PersonIdent committer = revCommit.getCommitterIdent();
			//提交人name
			System.out.println(committer.getName());
			//提交人邮箱
			System.out.println(committer.getEmailAddress());
			//提交message
			System.out.println(revCommit.getFullMessage());
			//提交时间戳
			System.out.println(revCommit.getCommitTime() * 1000L);
		} else {  
			System.out.println("jgit操作:根据commitId获取详细信息,包含多个父提交,跳过");
		}  
	} catch (Exception e) {  
		log.warn("jgit操作:根据commitId获取详细信息失败:", e);  
		if (repository != null) {  
			repository.close();  
		}  
	}  
}

/**  
* 代码比较  
* @param repository 仓库  
* @param currentCommit 当前提交(新)  
* @param parentCommit 父提交(旧)  
* @return 代码变更行数  
*/
public static void codeDiff(Repository repository, RevCommit currentCommit, RevCommit parentCommit) {  
	CommitCodeLinesBO codeLinesBO = new CommitCodeLinesBO();  
	try (DiffFormatter diffFormatter = new DiffFormatter(DisabledOutputStream.INSTANCE)) {  
		//设置仓库  
		diffFormatter.setRepository(repository);  
		//忽略所有空白  
		diffFormatter.setDiffComparator(RawTextComparator.WS_IGNORE_ALL);  
		//启用重命名检测  
		diffFormatter.setDetectRenames(true);  
		//比较提交  
		List<DiffEntry> diffs = diffFormatter.scan(parentCommit, currentCommit);  
		//增 删 的行数  
		int addLines = 0, deleteLines = 0;  
		for (DiffEntry diff : diffs) {  
			FileHeader fileHeader = diffFormatter.toFileHeader(diff);  
			List<HunkHeader> hunks = (List<HunkHeader>) fileHeader.getHunks();  
			for (HunkHeader hunkHeader : hunks) {  
				EditList editList = hunkHeader.toEditList();  
				for (Edit edit : editList) {  
					//新增行数  
					addLines += edit.getEndB() - edit.getBeginB();  
					//删除行数  
					deleteLines += edit.getEndA() - edit.getBeginA();  
				}  
			}  
		}  
		System.out.pringln("新增代码行数" + addLines);
		System.out.pringln("删除代码行数" + deleteLines);
		System.out.pringln("改动的文件数" + diffs.size());
	} catch (Exception e) {  
		e.printStackTrace();
	}  
}

遇到的问题

remote hung up unexpectedly

问题原因:因为使用了ssh操作git。作者说jgit从5.8版本将ssh支持给抽出去了,但即使你在pom里依赖了jssh也不会解决这个问题,因为Jgit仍然无法找到正确的SshSessionFactory。尽管使用旧版本,也会报一个Auth false的错误。解决办法:

  1. 使用https的方式,需要用户名和密码做身份验证。
CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "https://example.com/repo.git" );
cloneCommand.setCredentialsProvider(new UsernamePasswordCredentialsProvider("user", "password" ));
cloneCommand.setDirectory(file)
cloneCommand.call();
  1. 在代码中配置ssh。需要使用公钥做身份验证。