pom依赖
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version>
</dependency>
jgit客户端常用功能实现
import com.jcraft.jsch.Session;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CheckoutCommand;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.PullCommand;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.SshTransport;
/**
* 功能描述:
* 1. 将远程仓库pre分支拉取至本地,如果pre不存在则使用master分支
* 2. 如果本地存在temp4deleteSwitches分支则删除分支,从本地pre分支check出temp4deleteSwitches分支
* 3. 如果远程存在temp4deleteSwitches分支则删除分支,将本地temp4deleteSwitches分支推送至远程temp4deleteSwitches分支
* @author 会灰翔的灰机
* @date 2019/11/1
*/
@Slf4j
public class GitService {
/**
* 本地操作使用分支名称
*/
public static final String GIT_TEMP = "temp4deleteSwitches";
public static final String PRE = "pre";
public static final String MASTER = "master";
public static final String SEPARATOR = "/";
/**
* 与git服务使用ssh认证
*/
private static final SshSessionFactory SSH_SESSION_FACTORY = new JschConfigSessionFactory() {
@Override
protected void configure(Host host, Session session) {
}
};
private String gitDir = "/tmp";
public void autoCommit() throws IOException, GitAPIException {
Git git;
String gitPath = getGitPath(gitlabProjectDTO.getName());
// 1. 如果本地git仓库已存在则打开,否则clone至本地
if (new File(gitPath).exists()) {
git = open(gitPath);
} else {
git = clone(gitlabProjectDTO.getSshUrlToRepo(), gitPath);
}
Ref ref = null;
if (git != null) {
ref = getRemotePreOrMasterRef(git);
if (ref == null) {
log.error("不存在pre或master分支,操作失败。gitlabProjectDTOJsonDTO={}",
gitlabProjectDTO);
}
ref = checkout2Temp(git, ref);
}
List<String> modifiedFiles = new LinkedList<>();
add(git, modifiedFiles);
commit(git);
push(git, ref);
}
/**
* 打开本地git仓库
* @param uri :
* @return org.eclipse.jgit.api.Git :
*/
public Git open(String uri) throws IOException {
Git git = null;
File file = new File(uri);
if (file.exists()) {
git = Git.open(file);
}
return git;
}
/**
* 克隆pre分支,如果不存在pre分支则克隆master分支
* @param uri :
* @param gitDir :
* @return org.eclipse.jgit.api.Git :
*/
public Git clone(String uri, String gitDir) throws GitAPIException {
Git git;
boolean useMaster = false;
try {
git = clone(uri, gitDir, PRE);
} catch (GitAPIException e) {
e.printStackTrace();
useMaster = true;
git = clone(uri, gitDir, MASTER);
}
if (findRemoteRef(git, PRE) != null && useMaster) {
throw new RuntimeException("clone pre分支失败");
}
return git;
}
/**
* git clone,如果本地目录存在则先删除后再clone
* @param uri :
* @param gitDir :
* @param branchName :
* @return org.eclipse.jgit.api.Git :
*/
public Git clone(String uri, String gitDir, String branchName) throws GitAPIException {
CloneCommand cloneCommand = Git.cloneRepository();
File file = new File(gitDir);
if (file.exists()) {
if (!file.delete()) {
return null;
}
}
configTransport(cloneCommand);
cloneCommand.setURI(uri);
cloneCommand.setDirectory(file);
cloneCommand.setBranch(branchName);
cloneCommand.setNoCheckout(true);
return cloneCommand.call();
}
/**
* Git pull
* @param git :
* @param ref :
* @return org.eclipse.jgit.api.PullResult :
*/
public PullResult pull(Git git, Ref ref) throws GitAPIException {
PullCommand pull = git.pull();
configTransport(pull);
pull.setRemoteBranchName(ref.getName());
return pull.call();
}
/**
* git push 命令
* @param git :
* @param ref :
* @return java.lang.Iterable<org.eclipse.jgit.transport.PushResult> :
*/
public Iterable<PushResult> push(Git git, Ref ref) throws GitAPIException {
PushCommand push = git.push();
configTransport(push);
push.add(ref);
push.setForce(true);
return push.call();
}
/**
* git add 命令
* @param git :
* @param modifiedFiles :
* @return org.eclipse.jgit.dircache.DirCache :
*/
public DirCache add(Git git, List<String> modifiedFiles) throws GitAPIException {
AddCommand add = git.add();
Status status = git.status().call();
Set<String> modified = status.getModified();
modified.forEach(modifiedFile -> {
if (!modifiedFiles.contains(modifiedFile.substring(modifiedFile.lastIndexOf(SEPARATOR)))) {
log.warn("has added unwanted file:{}", modifiedFile);
}
add.addFilepattern(modifiedFile);
});
return add.call();
}
/**
* 提交代码
* @param git :
* @return org.eclipse.jgit.revwalk.RevCommit :
*/
public RevCommit commit(Git git) throws GitAPIException {
CommitCommand commit = git.commit();
commit.setMessage("auto commit");
return commit.call();
}
public String getGitPath(String projectName) {
return gitDir + "/" + projectName;
}
/**
* 配置ssh会话
* @param transportCommand :
*/
public void configTransport(TransportCommand transportCommand){
transportCommand.setTransportConfigCallback((transport) -> {
SshTransport sshTransport = (SshTransport)transport;
sshTransport.setSshSessionFactory(SSH_SESSION_FACTORY);
});
}
/**
* 1. checkout至pre或master分支
* 2. git pull拉取最新代码
* 3. 从本地pre或master分支checkout至临时分支
* @param git : git客户端实例
* @param ref : 当前分支引用
* @return org.eclipse.jgit.lib.Ref : checkout分支后的分支引用
*/
public Ref checkout2Temp(Git git, Ref ref) throws GitAPIException, IOException {
// 1. 将远程分支check至本地,分支名称与远程同名,如果本地分支不存在则创建
CheckoutCommand checkout = git.checkout();
// 设置远程分支
checkout.setStartPoint(ref.getName());
// 设置本地分支名称
checkout.setName(getBranchName(ref));
// 如果本地不存在同名分支则创建
if (!refExist(git, getBranchName(ref))) {
checkout.setCreateBranch(true);
}
Ref preOrMasterRef = checkout.call();
if (preOrMasterRef == null) {
log.error("checkout 操作失败,结果为空");
return null;
}
// pull最新代码
PullResult pullResult = pull(git, preOrMasterRef);
if (!pullResult.isSuccessful()) {
log.error("pull 操作失败:{}", pullResult);
return null;
}
// 如果本地存在临时分支则删除
if (refExist(git, GIT_TEMP)) {
git.branchDelete().setBranchNames(GIT_TEMP).setForce(true).call();
}
// 如果远程存在临时分支则删除
Ref remoteTemp = findRemoteRef(git, GIT_TEMP);
if (remoteTemp != null) {
RefSpec refSpec = new RefSpec().setSource(null).setDestination(getDestination(GIT_TEMP));
git.push().setRefSpecs(refSpec).setRemote(Constants.DEFAULT_REMOTE_NAME).call();
}
// 创建本地临时分支
checkout = git.checkout();
checkout.setStartPoint(ref.getName());
checkout.setName(GIT_TEMP);
checkout.setCreateBranch(true);
return checkout.call();
}
/**
* 查找远程分支
* @param git : git客户端实例
* @param branchName : 分支名称
* @return org.eclipse.jgit.lib.Ref : 返回远程分支引用
*/
public Ref findRemoteRef(Git git, String branchName) throws GitAPIException {
Ref existRef = null;
if (git != null) {
List<Ref> refs = git.branchList().setListMode(ListMode.REMOTE).call();
for (Ref ref : refs) {
if (getBranchName(ref).equals(branchName)) {
existRef = ref;
break;
}
}
}
return existRef;
}
/**
* 判断本地分支是否存在
* @param git :
* @param branchName : 分支名称
* @return boolean : 是否存在
*/
public boolean refExist(Git git, String branchName) throws IOException {
return git.getRepository().resolve(branchName) != null;
}
public Ref getRemotePreOrMasterRef(Git git) throws GitAPIException {
Ref ref = findRemoteRef(git, PRE);
if (ref == null) {
ref = findRemoteRef(git, MASTER);
}
return ref;
}
public String getBranchName(Ref ref) {
return ref.getName().substring(ref.getName().lastIndexOf(SEPARATOR) + 1);
}
public String getDestination(String branchName) {
return Constants.R_HEADS + branchName;
}
}
@Value("${username:none}")
private String username;
@Value("${password:none}")
private String password;
private static CredentialsProvider credentialsProvider;
public void configTransport(TransportCommand<?,?> transportCommand, boolean useSsh){
if (useSsh) {
transportCommand.setTransportConfigCallback((transport) -> {
SshTransport sshTransport = (SshTransport) transport;
sshTransport.setSshSessionFactory(SSH_SESSION_FACTORY);
});
} else {
transportCommand.setCredentialsProvider(credentialsProvider);
}
}
@Override
public void afterPropertiesSet() {
if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
credentialsProvider = new UsernamePasswordCredentialsProvider(username, password);
}
}