-
1. 시작하기
-
2. Git의 기초
- 2.1 Git 저장소 만들기
- 2.2 수정하고 저장소에 저장하기
- 2.3 커밋 히스토리 조회하기
- 2.4 되돌리기
- 2.5 리모트 저장소
- 2.6 태그
- 2.7 Git Alias
- 2.8 요약
-
3. Git 브랜치
-
4. Git 서버
- 4.1 프로토콜
- 4.2 서버에 Git 설치하기
- 4.3 SSH 공개키 만들기
- 4.4 서버 설정하기
- 4.5 Git 데몬
- 4.6 스마트 HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 또 다른 선택지, 호스팅
- 4.10 요약
-
5. 분산 환경에서의 Git
- 5.1 분산 환경에서의 워크플로
- 5.2 프로젝트에 기여하기
- 5.3 프로젝트 관리하기
- 5.4 요약
-
6. GitHub
- 6.1 계정 만들고 설정하기
- 6.2 GitHub 프로젝트에 기여하기
- 6.3 GitHub 프로젝트 관리하기
- 6.4 Organization 관리하기
- 6.5 GitHub 스크립팅
- 6.6 요약
-
7. Git 도구
- 7.1 리비전 조회하기
- 7.2 대화형 명령
- 7.3 Stashing과 Cleaning
- 7.4 내 작업에 서명하기
- 7.5 검색
- 7.6 히스토리 단장하기
- 7.7 Reset 명확히 알고 가기
- 7.8 고급 Merge
- 7.9 Rerere
- 7.10 Git으로 버그 찾기
- 7.11 서브모듈
- 7.12 Bundle
- 7.13 Replace
- 7.14 Credential 저장소
- 7.15 요약
-
8. Git맞춤
- 8.1 Git 설정하기
- 8.2 Git Attributes
- 8.3 Git Hooks
- 8.4 정책 구현하기
- 8.5 요약
-
9. Git과 여타 버전 관리 시스템
- 9.1 Git: 범용 Client
- 9.2 Git으로 옮기기
- 9.3 요약
-
10. Git의 내부
- 10.1 Plumbing 명령과 Porcelain 명령
- 10.2 Git 개체
- 10.3 Git Refs
- 10.4 Packfile
- 10.5 Refspec
- 10.6 데이터 전송 프로토콜
- 10.7 운영 및 데이터 복구
- 10.8 환경변수
- 10.9 요약
-
A1. 부록 A: 다양한 환경에서 Git 사용하기
- A1.1 GUI
- A1.2 Visual Studio
- A1.3 Eclipse
- A1.4 Bash
- A1.5 Zsh
- A1.6 Git in Powershell
- A1.7 요약
-
A2. 부록 B: 애플리케이션에 Git 넣기
-
A3. 부록 C: Git 명령어
- A3.1 설치와 설정
- A3.2 프로젝트 가져오기와 생성하기
- A3.3 스냅샷 다루기
- A3.4 Branch와 Merge
- A3.5 공유하고 업데이트하기
- A3.6 보기와 비교
- A3.7 Debugging
- A3.8 Patch 하기
- A3.9 Email
- A3.10 다른 버전 관리 시스템
- A3.11 관리
- A3.12 Plumbing 명령어
A2.3 부록 B: 애플리케이션에 Git 넣기 - JGit
JGit
Java에는 JGit이라는 훌륭한 Git 라이브러리가 있다. JGit에는 Git 기능이 한가득 구현돼 있다. 순수하게 Java로 작성됐고 Java 커뮤니티에서 널리 사용한다. The JGit 프로젝트는 Eclipse 재단에 둥지를 틀었고 홈페이지는 http://www.eclipse.org/jgit에 있다.
설치하기
JGit을 프로젝트에 추가해서 코딩을 시작하는 방법은 여러 가지다.
그중 Maven을 사용하는 방법이 가장 쉽다. pom.xml 파일에 <dependencies>
태그를 아래와 같이 추가한다.
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version>
</dependency>
version
은 시간에 따라 올라갈 것이기 때문에 http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit에서 최신 버전을 확인해야 한다.
추가하면 Maven이 우리가 명시한 버전의 JGit을 자동으로 추가해준다.
반면 수동으로 바이너리를 관리하고 싶을 수도 있다. http://www.eclipse.org/jgit/download 에서 빌드된 바이너리를 내려받는다. 이 바이너리를 이용해서 아래와 같이 컴파일할 수 있다:
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
Plumbing
JGit의 API는 크게 Plumbing과 Porcelain으로 나눌 수 있다. 이 둘은 Git 용어이고 JGit도 이에 따라 나눈다. 일반 사용자가 사용하는 Git 명령어를 Porcelain 명령어라고 부르는데 이와 관련된 API도 Procelain API라고 부른다. 반대로 Plumbing API는 저장소 개체를 저수준에서 직접 사용하는 API다.
JGit을 사용하는 것은 Repository
클래스의 인스턴스를 만드는 것으로 시작한다.
파일 시스템에 있는 저장소에 접근할 때는 FileRepostiorybuilder
를 사용한다.
// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();
// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();
Git 저장소를 나타내는 정보를 하나씩 이 빌더 넘긴다. 넘기는 정보에 따라 조금 다른 API를 사용한다.
환경 변수를 읽고(.readEnvironment()
) 워킹 디렉토리를 주고 Git 디렉토리를 찾을 수도 있고(.setWorkTree(…).findGitDir()
) 예제로 보여준 것처럼 아예 .git
디렉토리를 바로 넘겨 줄 수도 있다.
Repository
인스턴스를 기점으로 온갖 일을 다 할 수 있다.
예제를 하나 보자.
// Get a reference
Ref master = repo.getRef("master");
// Get the object the reference points to
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();
// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();
// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");
이 예제가 어떤 뜻인지 하나씩 살펴보자.
첫 라인에서 master
Ref를 얻었다.
Jgit은 refs/heads/master
에 있는 진짜 master Ref를 가져와서 인스턴스를 리턴한다. 이 객체로 Ref에 대한 정보를 얻을 수 있다.
이름(.getName()
), Ref가 가리키는 개체(.getObjectId()
), Symbolic Ref가 가리키는 Ref(.getTarget()
)를 이 객체로 얻을 수 있다.
Ref 인스턴스는 태그 Ref와 개체를 나타내고 태그가 “Peeled” 인지도 확인할 수 있다. “Peeled” 은 껍질을 다 벗긴 상태 그러니까 커밋 개체를 가리키는 상태를 말한다.
두 번째 라인은 master
가 가리키는 ObjectId 인스턴스를 리턴한다.
ObjectId는 객체의 SHA-1 해시 정보다. 실제로 객체가 Git 객체 데이터베이스에 존재하는지는 상관없다.
셋째 라인도 ObjectId 인스턴스를 리턴하는데 JGit에서 rev-parse 문법을 어떻게 다뤄야 하는지 보여준다. 이 문법은 브랜치로 가리키기에서 설명했다. Git이 이해하는 표현은 전부 사용 가능하다. 표현식이 맞으면 해당 객체를 리턴하고 아니면 null을 리턴한다.
그다음 두 라인은 객체의 내용을 읽어서 보여준다.
ObjectLoader.copyTo()
함수로 객체의 내용을 표준출력으로 출력(Stream)했다. ObjectLoader에는 객체의 타입과 크기를 알려주거나 객체의 내용을 바이트 배열에 담아서 리턴하는 메소드도 있다.
파일이 큰지도 확인할 수 있다. .isLarge()
라는 메소드가 true
를 리턴하면 큰 파일이다. 큰 파일이면 .openStream()
호출해서 ObjectStream
인스턴스를 얻는다. 이 인스턴스는 일종의 InputStream으로 한 번에 전부 메모리로 올리지 않고 데이터를 처리할 수 있게 해준다.
그다음 몇 라인은 새 브랜치를 만드는 것을 보여준다.
RefUpdate 인스턴스를 만들고, 파라미터를 설정하고 나서 .update()
를 호출하면 브랜치가 생성된다.
그다음 몇 라인은 만든 브랜치를 삭제하는 코드다.
.setForceUpdate(true)
는 꼭 필요하다. 이것을 빼먹으면 .delete()
는 REJECTED
를 리턴하고 아무 일도 일어나지 않는다.
마지막 예제는 user.name
이라는 설정 값을 가져오는 것이다.
이 코드는 마치 해당 저장소의 local 설정만 읽어서 Config 객체를 리턴하는 것 같지만, global 설정과 system 설정까지 잘 찾아서 적용해준다.
여기서는 Plumbing API의 맛보기 정도만 보여줬다. 이용 가능한 메소드와 클래스가 많이 있다.
그리고 JGit의 에러를 처리하는 방법도 생략했다.
JGIT API에서는 JGit에서 정의한 NoRemoteRepositoryException
, CorruptObjectException
, NoMergeBaseException
같은 예외뿐만 아니라 IOExceptioin
같은 Java 표준 예외도 던진다.
Porcelain
Plumbing API로도 모든 일을 다 할 수 있지만, 일반적인 상황에 사용하기에는 좀 귀찮다. Index에 파일을 추가하거나 새로 커밋하는 것 같은 일은 Porcelain API가 낫다.
Porcelain API는 고수준에서 사용하기 편하게 했고 Git
클래스의 인스턴스를 만드는 것으로 시작한다.
Repository repo;
// construct repo...
Git git = new Git(repo);
Git 클래스는 빌더 스타일의 메소드의 집합이라서 복잡해 보이는 일을 쉽게 할 수 있다.
git ls-remote
명령어처럼 동작하는 예제를 살펴보자.
CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
.setCredentialsProvider(cp)
.setRemote("origin")
.setTags(true)
.setHeads(false)
.call();
for (Ref ref : remoteRefs) {
System.out.println(ref.getName() + " -> " + ref.getObjectId().name());
}
Git 클래스는 이런 식으로 사용한다. 메소드가 해당 Command 인스턴스를 리턴하면 체이닝으로 메소드를 호출해서 파라미터를 설정하고 .call()
을 호출하는 시점에 실제로 실행된다.
이 예제는 origin
리모트의 'tag’를 요청하는 예제다. 'head’는 빼고 요청한다.
사용자 인증은 CredentialsProvider
객체를 사용한다는 점을 기억하자.
Git 클래스로 실행하는 명령은 매우 많다. 우리에게 익숙한 add
, blame
, commit
, clean
, push
, rebase
, revert
, reset
명령 말고도 많다.
읽을거리
여기서는 JGit을 아주 조금만 보여줬다. 자세히 알고 싶다면 아래 링크에서 도움받을 수 있다.
-
공식 JGit API 문서: https://www.eclipse.org/jgit/documentation 표준 Javadoc 문서로 즐겨 쓰는 JVM IDE에 추가할 수 있다.
-
JGit Cookbook: https://github.com/centic9/jgit-cookbook JGit으로 무엇을 할 수 있는지 보여주는 예제가 많다.