서버에서 파일을 생성하고 GIT에다가 Commit하고 원격 Repo에다가 Push 해야하는 기능이 필요했다. 현재 Backend는 spring-webflux로 개발되어 있으므로 java로 git 기능을 사용할 수 있는 라이브러로를 찾던 중 JGIT이라는 것을 알게 되었다.
이클립스를 만든 회사에서 개발한 라이브러리인 듯 하다. 모든 기능을 다 사용해보지는 못했지만 일반적으로 GIT에서 사용하는 기능은 대부분 지원해주는 듯 하다.
아래 내가 써 본 기능을 한번 정리해봤다.
특정 폴더를 git repo로 생성하는 init 기능을 jgit으로 할 수 있다.
@Test
@DisplayName("git init test")
@Order(1)
void gitInitTest() throws GitAPIException, IOException {
//create git folder
File gitDir = new File("C:\\jgit_test\\git_init_test");
if(gitDir.exists()){
FileUtils.deleteDirectory(gitDir);
}
if(gitDir.mkdirs()){
log.info("dir create success");
}
//init
Git git = Git.init().setDirectory(gitDir).call();
Assertions.assertThat(git).isNotNull();
git.close();
}
특정 폴더를 생성하고 Git.init() 메소드에 해당 폴더를 지정하여 호출하면 해당 폴더가 git repo로 잡히고 Git 파일을 생성한다.
임시로 생성한 git_init_test 폴더에 .git 폴더 생성된 것을 확인할 수 있다.
GitHub, GitLab 같은 remote repository로부터 local repository를 생성할 수 있는 clone 작업도 할 수 있다.
@Test
@DisplayName("git-hub clone test")
@Order(2)
void gitHubCloneTest() throws GitAPIException, IOException {
//create git folder
File gitDir = new File("C:\\jgit_test\\git_hub_clone_test");
if(gitDir.exists()){
FileUtils.deleteDirectory(gitDir);
}
if(gitDir.mkdirs()){
log.info("dir create success");
}
//set username, access token
CredentialsProvider credentialsProvider
= new UsernamePasswordCredentialsProvider(
"ID 입력"
, "액세스토큰 입력"); //access token
//clone
Git git = Git.cloneRepository()
.setURI("원격 GIT 주소 URI")
.setCredentialsProvider(credentialsProvider)
.setDirectory(gitDir)
.call();
Assertions.assertThat(git).isNotNull();
git.close();
}
Git.cloneRepository() 메소드를 활용하여 로컬PC에 폴더를 생성하고 해당 폴더에 clone을 한다. CredentialsProvider 객체에 remote git의 ID와 액세스 토큰을 설정한다.
#Git 액세스 토큰을 발급받는 방법은 구글 검색을 하면 많은 자료가 검색된다.
해당 코드를 실행하면 위와 같이 clone 작업이 실행됐음을 알 수 있다.
git에다 소스를 반영하는 add & commit 아래와 같이 구현 가능하다.
@Test
@DisplayName("git add test")
@Order(4)
void gitAddTest() throws GitAPIException, IOException {
//git repo path
String dirPath = "C:\\jgit_test\\jgit-push-test";
File gitDir = new File(dirPath);
//create temp file
String fileName = UUID.randomUUID().toString();
File file = new File(dirPath+"\\"+fileName+".txt");
FileUtils.writeStringToFile(file, "testing it...", StandardCharsets.UTF_8);
//add
Git git = Git.open(gitDir);
Assertions.assertThat(git).isNotNull();
AddCommand add = git.add();
add.addFilepattern(fileName+".txt").call();
git.close();
}
@Test
@DisplayName("git commit test")
@Order(5)
void gitCommitTest() throws IOException, GitAPIException {
//git repo path
String dirPath = "C:\\jgit_test\\jgit-push-test";
File gitDir = new File(dirPath);
//commit
Git git = Git.open(gitDir);
git.commit().setMessage("JGIT commit test").call();
Assertions.assertThat(git).isNotNull();
git.close();
}
git폴더를 Git.open 메소드로 지정한 후 add, commit 사용이 가능하다. git과 똑같이 파일지정하여 add하고 commit시 메세지도 입력 가능하다.
remote repository에 소스를 반영하는 push 작업도 작업 가능하다.
@Test
@DisplayName("git push test")
@Order(6)
void gitPushTest() throws IOException, GitAPIException {
//git repo path
String dirPath = "C:\\jgit_test\\jgit-push-test";
File gitDir = new File(dirPath);
//set username, access token
CredentialsProvider credentialsProvider
= new UsernamePasswordCredentialsProvider(
"ID 입력"
, "액세스토큰 입력"); //access token
//push
Git git = Git.open(gitDir);
git.push()
.setCredentialsProvider(credentialsProvider)
.setRemote("원격이름")
.setRefSpecs(new RefSpec("branch명"))
.call();
Assertions.assertThat(git).isNotNull();
git.close();
}
원격 이름과 branch를 지정하고 실행하면 push가 된다.
우리가 git 사용하는 이유의 8할은 branch 기능이 넘 잘 되어 있기 때문이다. 우리는 기존 소스에서 영향도가 큰 작업을 할 경우 branch를 생성해서 해당 branch에서 작업을 진행하게 된다.
@Test
@DisplayName("git branch merge test")
@Order(7)
void gitBranchMergeTest() throws IOException, GitAPIException {
//git repo path
String dirPath = "C:\\jgit_test\\jgit-push-test";
File gitDir = new File(dirPath);
//set username, access token
CredentialsProvider credentialsProvider
= new UsernamePasswordCredentialsProvider(
"ID 입력"
, "액세스토큰 입력"); //access token
//branch create
Git git = Git.open(gitDir);
String branchName = "새로 생성할 branch명";
List<Ref> branchList =
git
.branchList()
.setListMode(ListBranchCommand.ListMode.ALL)
.call();
//기존 branch가 존재하는지 여부 체크
boolean existYn = branchList
.stream()
.anyMatch(ref ->
ref.getName()
.endsWith("heads/"+branchName));
//branch가 없을 경우 branch를 생성한다.
if(!existYn){
git.branchCreate().setName(branchName).call();
}
//merge sub into main
git.checkout().setName(branchName).call();
ObjectId mergeBase = git.getRepository().resolve("merge 대상 branch명");
MergeResult merge = git.merge()
.include(mergeBase)
.setCommit(true)
.setFastForward(MergeCommand.FastForwardMode.NO_FF)
.setMessage("Merged changes")
.call();
Assertions.assertThat(merge.getMergeStatus().isSuccessful()).isTrue();
//push
if(merge.getMergeStatus().isSuccessful()){
git.push()
.setCredentialsProvider(credentialsProvider)
.setRemote("원격이름")
.setRefSpecs(new RefSpec(branchName))
.call();
Assertions.assertThat(git).isNotNull();
git.close();
}
}
위 소스는 sub라는 임의 branch를 생성하여 기존 작업 branch 내역을 merge한다. 그리고 remote git에도 해당 branch를 push 한다.
JGIT을 통해 ADD -> Commit -> Push -> branch create -> merge가 정상적으로 수행됐는지 아래처럼 확인했다.