[Git/JGit] PullRequest 구현하기

코드를 주고 받는 방법엔 크게 두가지가 있는것 같다. 프로깃이라는 책에서도 두가지를 설명하는데 하나는 고전적인 방법으로 패치 파일을 주고 받을 수 있겠고, 나머지 하난 상대방 브랜치를 merge하거나 rebase하는 식으로 코드를 직접 합치는 방법이 있겠다.

나는 후자를 선택했는데 그전까진 패치 파일 주고 받는 방법을 미처 생각하지 못했었고, pull request가 주는 어감때문에도 왠지 “코드 가져가라는 요청”이니까 merge로 코드를 받아가면 되겠군? 이라고 생각해서 이쪽으로 발상을 한것 같다.

암튼, 그래서 어떻게 하기로 했냐면.. 요청 보내는 쪽에서 가져갈 브랜치가 그 브랜치에 있는 코드를 어느 브랜치에 보낼지 선택하게하고 무슨 코드를 보낸다고 대충 적는다.

그럼 서버에 데이터가 하나 저장되는데 그게 PullRequest라는 도메인으로 저장된다. 그 안에는 어떤 Project(역시 도메인)에서 어떤 Project로 어떤 Branch에서 어디로 보내는지 누가 보내는지 누가 받았는지 등의 정보를 가지고 있다.

그럼 코드를 받는 프로젝트의 “코드 주고받기”라는 메뉴에 가보면 열려있는 풀리퀘 메뉴쪽에 하나가 표시되고 거길 열어보면 누군가 요청 보낸걸 볼 수 있다.

거기서 클릭해서 들어가면 이제 두가지를 할 수 있는데.. 하나는 “수락” 하나는 “거절”.

“수락”을 하면 다음과 같은 일이 발생한다.

일단 Git 저장소는 전부 bare모드로 만들어져있기 때문에 Git  저장소에서 직접 브랜치를 옮기거나 checkout을 받는다거나 하는 작업을 할 수 없다. 그래서 요청을 받아줄 프로젝트의 저장소를 bare모드가 아닌 non-bare 모드로 clone을 한다. 다음으로 ‘요청 받을 브랜치’와 ‘요청 보낸 브랜치’를 두개 만들고 각각을 ‘요청 보내온 저장소’와 ‘요청 받아줄 저장소’의 브랜치에서 fetch 해온다. 그런다음 ‘요청 받을 브랜치의 코드를 받아온 브랜치’로 이동해서 ‘요청 보내온 브랜치의 코드를 받아온 브랜치’의 코드를 머지 한다.

머지가 잘 되면 요청 받을 프로젝트의 브랜치로 ‘요청 받을 브랜치의 코드를 받아와서 요청 보낸 브랜치의 코드를 받아온 브랜치와 머지한 코드’를 푸쉬한다.

이렇게하면 풀리퀘가 된다. 그리고 머지 커밋이 항상 남도록 하려면 merge할때 NO_FF 옵션을 주면 된다.

이제부터 다듬기로, 머지하기 전에 머지가 잘되는지 확인해보고(사실 확인이라기보다 그냥 한번 해보면 되는데.. 암튼) 미리 머지가 잘 될 상황인지 아닌지 알려줄 수 있겠고, 잘 안되는 상황이면 직접 콘솔로 머지하고 컨플릭트 해결하라고 안내해 줄 수 있겠다.

그리고 풀리퀘를 만들어 보낼 시점에도 위와 같이 머지가 잘 되는 상황인지 체크해서 알려줄 수 있겠다. 어디서 하는게 좋을지 생각해 봤는데 어차피 보내느 시점과 받는 시점 사이에 받는 브랜치의 코드가 바뀌면서 처음 보낼 땐 머지가 잘 될것 같아도 나중에 안된느 시점이 있을 수 있으니까 그냥 두번 다 해주는게 좋을 것 같다고 결정했다.

그 다음 다듬기로는 풀리퀘가 어떤 커밋을 보내는 건지 커밋 목록과 브랜치 간의 파일 DIff 정보를 보여주는건데.. 후자는 금방 찾았는데 브랜치간에 차이나는 커밋 목록 만드는게 생각처럼 쉽게 안찾아진다. git show-branch와 비슷한 명령어가 jgit에 없는것 같다. 어떻게 해야할런지.. 흠… 좀 더 고민하거나 팀원에게 도움을 받아야겠다.

갈 길이 멀지만… 일단 포크/풀리퀘 구현은 가능하단걸 알았으니까 끝.

[Git/Github] JGit으로 포크는 어떻게 구현해야 할라나.

모르지 나도.. 정답이 어디 있간디? 있으면 나도 보고싶다.

일단 내가 구상한 방법은 git clone이다. 포크는 풀리퀘를 구현하기 위한 발판이나 마찬가지인데 나중에 풀리퀘 구현 방법에 따라 포크 구현 방법이 달라질지도 모르겠다.

“user1/project1을 보고 있는 user2가 fork 버튼을 누르면 user1/project1과 동일한 user2/project1이 생긴다.”

대충 포크의 요구사항을 기술하면 위와 같은데, 이걸 달성하기 가장 쉬운 방법은 Clone 인것 같다.

DVCS 호스팅 서버에서 user2 디렉토리에서 git clone user1/project1을 실행해서 user1/project1을 clone 하면 다음과 같은 일이 벌어진다.

user2/project1이라는 디렉토리가 만들어지고 그 안으로 walking tree가 들어오고 그 안에 .git 디렉토리가 들어온다. 그리고 레퍼런스가 두개 생긴다. 하나는 remote/origin으로 user1/project1을 가리키는 레퍼런스고, 하나는 master 브랜치인데 이건 fork 할 프로젝트의 기본 브랜치가 뭐냐에 따라 달라질 수 있지만 보통은 master겠지.

https://www.kernel.org/pub/software/scm/git/docs/git-clone.html

이제 이걸 JGit으로 할라면 어떻게 해야되냐가 문제인데.. 스택오버를 뒤지면 잘 나온다.

cloneRepository()를 호출하면 CloneCommand 타입의 객체나 나온다. 나머진 API 문서 보면서 코딩.

이제 git clone으로 포크 기능 만들기에 필요한 기능은 확인이 됐는데… 이제부터가 시작이다.

만약에 포크하려는 이름의 프로젝트 이름이 이미 존재한다면? 프로젝트를 삭제하면 더 디렉토리도 잘 지워지나? 더 나가서는 100명이 포크따면 똑같은 워킹 디렉토리 100개 생기는건데 이건 어떻게하지? 그냥 그렇게 생기게 해야되는건가? 아니면 뭔가 중복되는 워킹 디렉토리 수를 줄일 수 있는 방법은 없을까? 등등 많지만.. 일단은 풀리퀘에 집중.

풀리퀘는 그럼 어떻게 구현할까나? 대충은 생각해봤지만 좀 더 정리해야되서 나중으로 미뤄야겠다.

JGit로 push 성공 기념샷.

재일이형 제보로 알게된 기트 허브 이클립스 플러그인을 설치할까 하다가 그림을 보니까 JGit랑 거의 흡사하길래 그냥 JGit에 머물기로 했습니다. 위 링크에 보이는 그림 대로 push to를 해봤더니 되네요. 이전에는 어찌해야 할지 몰라서 제대로 못 썼는데 이젠 좀 쓸만하네요.ㅋㅋ

commit, push to, fetch from 메뉴에 단축키만 지정해 두면 웬만한 SVN, CVS 플러그인 부럽지 않게 사용할 수 있을 것 같습니다.

팁으로 SVN, CVS에 비해 히스토리 정보 참조가 엄청나게 빠르다는 겁니다. 그도 그럴 것이 저장소가 로컬에 있으니깐 필요한 히스토리 정보 로딩이 SVN이나 CVS에 비해 훨씬 빠른 것 같습니다. 물론 뭐 네트워크 사정에 따라 조금씩 차이는 있겠지만요..ㅋ

JGit 설치

이클립스 업데이트 사이트: http://www.jgit.org/update-site
위 업데이트 사이트를 이용해서 설치하면 됩니다.

그런 다음 Git로 버전 관리할 프로젝트에서 Team -> Share Project -> Git를 선택합니다. 그럼 이제 Team 메뉴에서 Git 명령어 몇 개를 사용할 수 있습니다.

사용자 삽입 이미지사용자 삽입 이미지
아직은… 툴 지원이 Subversion에 비해 미약한 듯 합니다. 특히 Git에서 자주 사용할 것 같은 명령어인 Add, Commit, Pull, Push에 대한 단축키가 지정되어 있지 않다는 것이 좀 걸립니다. 물론 수동으로 단축키를 등록하고 사용하는 방법도 있지만… 조금 귀찮죠.

새로 추가한 파일은 관리 대상이 아니라는 표시가 나오고 관리 중인 코드를 변경하고 아직 commit 하지 않았을 경우 not updated라고 표시해줍니다. 이 상태에서 commit을 하면 not updated인 코드만 commit하고 새로 추가한 파일은 commit하지 않습니다.

오른쪽 조그만 빨간색은 JUnit Max인데 저장하는 순간 바로 테스트를 하고 그 결과를 알려주기 때문에 굉장히 유용한 툴인것 같습니다. 손수 테스트를 돌리지 않아도 되기 때문에 코딩 흐름을 빠르게 이어 나갈 수 있습니다.