在我们的学习和开发过程中,git作为一个优秀的分布式版本控制工具是经常会被我们使用到的,那么如何通过java代码来实现Git的更新,提交,推送等操作呢?
1.首先我们会想到的应该是寻找市面上是否已经有了比较成熟的、开源的git客户端。这是我推荐使用一个比较成熟的git客户端——JGit。JGit 是一个轻量级纯 Java 的类库,用来实现 Git 的版本控制系统的访问,以及提供核心的版本控制算法。EGit 这个 Eclipse 上的 Git 插件就是采用 JGit 开发的。
如果你对git和jgit还不熟悉,推荐学习书籍:pro git
下面介绍如何在代码中集成jgit:
(1)在pom.xml中引入如下依赖:
<dependency> <groupId>org.eclipse.jgitgroupId> <artifactId>org.eclipse.jgitartifactId> <version>5.12.0.202106070339-rversion> dependency>
(2)编写配置类JgitConfig.java
@Configuration@ConfigurationProperties(prefix = "jgit")public class JgitConfig { private static String username; private static String password; public static String getUsername() { return username; } public void setUsername(String username) { JgitConfig.username = username; } public static String getPassword() { return password; } public void setPassword(String password) { JgitConfig.password = password; }}
(3)application.yml文件配置
jgit: username: #git账号名 password: #git密码
(4)编写JgitUtil工具类。(注:由于业务原因,方法中需要的localPath参数我是通过数据库获取的,大家用的时候也可以放入配置文件中配置)
@Slf4jpublic class JgitUtil { private static CredentialsProvider provider = new UsernamePasswordCredentialsProvider(JgitConfig.getUsername(), JgitConfig.getPassword()); public static Git openRpo(String localPath) { Git git = null; try { Repository repository = new FileRepositoryBuilder() .setGitDir(Paths.get(localPath, ".git").toFile()) .build(); git = new Git(repository); } catch (IOException e) { e.printStackTrace(); } return git; } public static void init(String localPath) throws GitAPIException { Git.init().setDirectory(new File(localPath)).call(); } public static void add(String localPath, String fileName) throws Exception { openRpo(localPath).add().addFilepattern(Optional.ofNullable(fileName).orElse(".")).call(); } public static void rm(String localPath, String fileName) throws Exception { openRpo(localPath).rm().addFilepattern(fileName).call(); } public static void commit(String localPath, String commitInfo) throws Exception { openRpo(localPath).commit().setMessage(Optional.ofNullable(commitInfo).orElse("default commit info")).call(); } public static void mv(String localPath, String sourcePath, String targetPath, File file) { System.out.println(sourcePath); try { File newDir = new File(targetPath); if (!newDir.exists()) { newDir.mkdirs(); } File newFile = new File(newDir, file.getName()); boolean success = file.renameTo(newFile); if (success) { add(localPath, "."); rm(localPath, sourcePath); commit(localPath, "File moved to new directory"); push(localPath); } else { // handle error log.error("文件移动异常!"); } } catch (Exception e) { e.printStackTrace(); } } public static Map<String, String> status(String localPath) throws Exception { Map<String, String> map = new HashMap<>(); Status status = openRpo(localPath).status().call(); map.put("Added", status.getAdded().toString()); map.put("Changed", status.getChanged().toString()); map.put("Conflicting", status.getConflicting().toString()); map.put("ConflictingStageState", status.getConflictingStageState().toString()); map.put("IgnoredNotInIndex", status.getIgnoredNotInIndex().toString()); map.put("Missing", status.getMissing().toString()); map.put("Modified", status.getModified().toString()); map.put("Removed", status.getRemoved().toString()); map.put("UntrackedFiles", status.getUntracked().toString()); map.put("UntrackedFolders", status.getUntrackedFolders().toString()); return map; } public static void branch(String localPath, String branchName) throws Exception { openRpo(localPath).branchCreate() .setName(branchName) .call(); } public static void delBranch(String localPath, String branchName) throws Exception { openRpo(localPath).branchDelete() .setBranchNames(branchName) .call(); } public static void checkoutBranch(String localPath, String branchName) throws Exception { openRpo(localPath).checkout() .setName(branchName) .call(); } public static List<Ref> listBranch(String localPath) throws Exception { return openRpo(localPath).branchList().call(); } public static void mergeBranch(String localPath, String branchName, String commitMsg) throws Exception { //切换分支获取分支信息存入Ref对象里 Ref refdev = openRpo(localPath).checkout().setName(branchName).call(); //切换回main分支 openRpo(localPath).checkout().setName("main").call(); // 合并目标分支 MergeResult mergeResult = openRpo(localPath).merge().include(refdev) //同时提交 .setCommit(true) // 分支合并策略NO_FF代表普通合并, FF代表快速合并 .setFastForward(MergeCommand.FastForwardMode.NO_FF) .setMessage(Optional.ofNullable(commitMsg).orElse("master Merge")) .call(); } public static void push(String localPath) throws Exception { openRpo(localPath).push() //设置推送的URL名称如"origin" .setRemote("origin") //设置需要推送的分支,如果远端没有则创建 .setRefSpecs(new RefSpec("main")) //身份验证 .setCredentialsProvider(provider) .call(); } public static void push(String localPath, String branch) throws Exception { openRpo(localPath).push() //设置推送的URL名称如"origin" .setRemote("origin") //设置需要推送的分支,如果远端没有则创建 .setRefSpecs(new RefSpec(branch)) //身份验证 .setCredentialsProvider(provider) .call(); } public static void pull(String localPath, String remotePath) throws Exception { //判断localPath是否存在,不存在调用clone方法 File directory = new File(localPath); if (!directory.exists()) { gitClone(localPath, remotePath, "main"); } openRpo(localPath).pull() .setRemoteBranchName("main") .setCredentialsProvider(provider) .call(); } public static void pull(String localPath, String remotePath, String branch) throws Exception { //判断localPath是否存在,不存在调用clone方法 File directory = new File(localPath); if (!directory.exists()) { gitClone(localPath, remotePath, branch); } openRpo(localPath).pull() .setRemoteBranchName(branch) .setCredentialsProvider(provider) .call(); } public static void gitClone(String localPath, String remotePath, String branch) throws Exception { //克隆 Git git = Git.cloneRepository() .setURI(remotePath) .setDirectory(new File(localPath)) .setCredentialsProvider(provider) //设置是否克隆子仓库 .setCloneSubmodules(true) //设置克隆分支 .setBranch(branch) .call(); //关闭源,以释放本地仓库锁 git.getRepository().close(); git.close(); }}
(5)直接在对应的业务代码中调用上述工具类中的方法即可。
如果有些朋友还需要集成其他命令,可以了解下这个开源项目:https://github.com/centic9/jgit-cookbook,git的几乎所有操作都在这里面集成了。
2.另外一种方式大家想必也猜到了。既然可以在命令行中执行git命令来操作git,那么能不能通过使用java控制终端来执行git命令呢?答案是肯定的,但前提是需要在你电脑或服务器上先安装好git客户端。
下面是示例代码:
@Slf4jpublic class GitUtils { public static String executeCommand(String command) { StringBuilder output = new StringBuilder(); Process process; try { process = Runtime.getRuntime().exec(command); process.waitFor(); BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { output.append(line).append("\n"); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } return output.toString(); } public static void cloneRepository(String remotePath, String localPath) { String command = "git clone " + remotePath + " " + localPath; String output = executeCommand(command); System.out.println(output); } public static void pull(String localPath,String branch) { String command = "git -C " + localPath + " pull origin "+branch; String output = executeCommand(command); System.out.println(output); } public static void checkoutBranch(String localPath, String branchName) { String command = "git -C " + localPath + " checkout " + branchName; String output = executeCommand(command); System.out.println(output); } public static void commit(String localPath, String message) { String command = "git -C " + localPath + " commit -a -m \"" + message + "\""; String output = executeCommand(command); System.out.println(output); } public static void add(String localPath) { String command = "git -C " + localPath + " add ."; String output = executeCommand(command); System.out.println(output); } public static void push(String localPath) { String command = "git -C " + localPath + " push"; String output = executeCommand(command); System.out.println(output); } public static void mv(File file,String localPath){ File newDir = new File(localPath); if (!newDir.exists()) { newDir.mkdirs(); } File newFile = new File(newDir, file.getName()); boolean success = file.renameTo(newFile); if (success) { add(localPath); commit(localPath,"File moved to new directory"); push(localPath); } else { // handle error log.error("文件移动异常!"); } }}
如果你的git服务端使用的是gitlab,还可以使用gitlab的api来操作。下面是具体的实现操作:
(1)在gitlab中配置访问令牌。
(2)pom.xml文件中引入依赖。
<dependency> <groupId>org.gitlab4jgroupId> <artifactId>gitlab4j-apiartifactId> <version>4.19.0version> dependency>
(3)编写配置类,并在yml文件中配置。
@Configuration@ConfigurationProperties(prefix = "git")public class GitConfig { public static String hostUrl; public static String personalAccessToken; public static String getHostUrl() { return hostUrl; } public static void setHostUrl(String hostUrl) { GitConfig.hostUrl = hostUrl; } public static String getPersonalAccessToken() { return personalAccessToken; } public static void setPersonalAccessToken(String personalAccessToken) { GitConfig.personalAccessToken = personalAccessToken; }}
git: hostUrl: #gitlab访问的ip+端口,如:http://127.0.0.1:8080 personalAccessToken: #刚刚配置的访问令牌
(4)编写工具类。(注:gitProjId,branch,filePath都可写入配置文件中,gitProjId为gitlab中对应的项目id,filePath为git本地文件路径)
public class GitLabApiUtils { private static GitLabApi gitLabApi = new GitLabApi(GitConfig.hostUrl, GitConfig.personalAccessToken, null,null); public static InputStream getRawFileStreamByProjId(Integer gitProjId, String branch, String filePath) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().getRawFile(gitProjId,branch,filePath); } public static InputStream getRawFileStreamByGitPath(String gitPath,String branch,String filePath) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().getRawFile(gitPath,branch,filePath); } public static RepositoryFile getFile(Integer projectId, String filepath, String branch) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().getFile(projectId, filepath, branch); } public static Optional<RepositoryFile> getOptionalFile(Integer projectId, String filepath, String branch) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().getOptionalFile(projectId, filepath, branch); } public static List<Project> getProjects() throws GitLabApiException { return gitLabApi.getProjectApi().getProjects(); } //查询文件树结构 public static List<TreeItem> getFileTree(Integer gitProjId, String branch, String filePath) throws GitLabApiException { return gitLabApi.getRepositoryApi().getTree(gitProjId,filePath,branch,true);//默认递归查询 } //获取blob文件列表 public static List<TreeItem> getFileList(Integer gitProjId, String branch, String filePath) throws GitLabApiException { List<TreeItem> tree = gitLabApi.getRepositoryApi().getTree(gitProjId, filePath, branch, true);//默认递归查询 筛选出文件后返回list ArrayList<TreeItem> treeItems = new ArrayList<>(); for (TreeItem treeItem : tree) { if ("blob".equals(treeItem.getType().toString()) ) { treeItems.add(treeItem); } } return treeItems; } public static List<TreeItem> getFileList(String projectPath, String branch, String filePath) throws GitLabApiException { return gitLabApi.getRepositoryApi().getTree(projectPath,filePath,branch,true);//默认递归查询 筛选出文件后返回list } public static synchronized RepositoryFile createFile(Integer gitProjId , RepositoryFile file, String branch, String commit) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().createFile(gitProjId,file,branch,commit); } public static synchronized RepositoryFile updateFile(Integer gitProjId , RepositoryFile file, String branch, String commit) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().updateFile(gitProjId,file,branch,commit); } public static RepositoryFile getFileByProjId(Integer gitProjId,String branch,String filePath) throws GitLabApiException { return gitLabApi.getRepositoryFileApi().getFile(gitProjId,filePath,branch); }}
来源地址:https://blog.csdn.net/ZhengXinMing1998/article/details/131759179