프로젝트 운영하기
프로젝트 운영은 크게 두 가지로 이루어진다.
- fotmat-patch 명령을 생성한 Patch를 이메일로 받아서 프로젝트에 Patch를 적용하는것
- 프로젝트의 다른 리모트 저장소로 부터 변경내용을 Merge하는 것
토픽 브랜치에서 일하기
임시로 토픽 브랜치에 통합해보고 나서 메인 브랜치에 통합 하는 것이 좋다.
- Patch를 적용할 때 이리저리 수정해볼 수 있다.
- 더 고민할 점이 있으면 Patch를 적용해 둔 채로 나중에 미룰 수도 있다.
프로젝트의 관리자라면 임시 통합할 토픽 브랜치의 이름을 잘 지어야 한다. 예를 들어 sc라는 사람이 작업한 Patchfkaus sc/ruby-client처럼 앞에 닉네임을 붙여서 브랜치를 만들 수 있다.
$ git branch sc/ruby_client master
checkout -b 옵션으로 브랜치를 만들고 Checkout까지 한번에 할 수 있다.
$ git checkout -b sc/ruby_client master
이렇게 토픽 브랜치를 만들고 Patch를 적용해보고 적용한 내용을 다시 Long-Running 브랜치로 Merge한다.
이메일로 받은 Patch를 적용하기
apply 명령을 사용하는 방법
am 명령을 사용하는 방법
리모트 브랜치로부터 통합하기
예를 들어 Jessica가 ruby-client 브랜치에 기능을 만들어 놨다고 메일을 보내왔다면 해당 리모트 브랜치를 등록하고 Checkout해서 테스트 한다. 이메일로 또 다른 기능을 개발한 브랜치를 보내오면 이미 저장소를 등록 했기 때문에 간단히 Fetch하고 Checkout 할 수 있다.
$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client
다른 개발자들과 함께 지속적으로 개발할 때는 이 방식이 가장 사용하기 좋다. 물론 기여하는 사람이 간단한 Patch를 이따금씩 만들어 내면 이메일로 Patch 파일을 받는 것이 낫다. 기여자가 저장소 서버를 만들어 커밋 하고 관리자가 리모트 저장소로 등록해서 Patch를 합치는 작업보다 시간과 노력이 덜 든다. 물론 Patch 한 두개를 보내는 사람들까지도 모두 리모트 저장소로 등록해서 사용해도 된다. 스크립트나 호스팅 서비스를 사용하면 좀 더 쉽게 관리할 수 있다. 어쨋듯 어떤 방식이 좋을지는 우리가 어떻게 개발하고 어떻게 기여할지에 달렸다.
리모트 저장소로 등록 하면 커밋의 히스토리도 알 수 있다. Merge할 때 어디서 부터 커밋이 갈라졌는지 알 수 있기 때문에 -3 옵션을 주지 않아도 자동으로 3-way Merge가 적용된다.
리모트 저장소로 등록하지 않고도 Merge할 수 있다. 계속 함께 일할 개발자가 아닐때 사용하면 좋다. 아래는 리모트 저장소로 등록하지 않고 URL을 직접 사용하여 Merge를 하는 예이다.
$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
* branch HEAD -> FETCH_HEAD
Merge made by the 'recursive' strategy.
무슨 내용인지 확인하기
기여물을 Merge 할지 말지 결정해야 한다.
-- not 옵션 : master 브랜치에 속한 커밋은 제외하고 살펴본다.
예를 들어 contrib 브랜치에 두 개 Merge 했으면 다음과 같은 명령어로 그 결과를 볼 수 있다.
$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Oct 24 09:53:59 2008 -0700
seeing if this helps the gem
commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date: Mon Oct 22 19:38:36 2008 -0700
updated the gemspec to hopefully work better
git log 명령에 -p 옵션을 주면 각 커밋에서 무슨 내용이 변경됐는지 살펴볼수 있다.
diff 명령을 사용할 때 두 브랜치 사이에 ...를 쓰면, 두 브랜치의 공통 조상과 브랜치의 마지막 커밋을 비교한다.
$ git diff master...contrib
기여물 통합하기
Merge Workflow
이 Workflow는 master 브랜치가 가장 안전한 코드라고 가정한다. 토픽 브랜치를 검증하고 master 브랜치로 merge 할때마다 토픽 브랜치를 삭제한다.
ruby_client 브랜치와 php_client 브랜치가 다음과 같이 있다.
ruby_client 브랜치를 master 브랜치로 Merge 한 후 php_client 브랜치를 Merge 하면 다음과 같다.
이 Workflow는 간단하지만, 프로젝트의 규모가 커지면 문제가 생길 수 있다.
개발자가 많고 규모가 큰 프로젝트에서는 두 단계로 Merge 하는 것이 좋다. 그래서 Long-Running 브랜치를 두 개로 유지해야 한다. master 브랜치는 아주 안정적인 버전을 릴리즈 하기 위해서 사용한다. develop 브랜치는 새로 수정된 코드를 통합할 때 사용한다. 그리고 두 브랜치를 모두 저장소에 Push한다.
다음은 master 브랜치, develop 브랜치가 있고 ruby_client 브랜치(토픽브랜치)를 Merge하기 전 모습이다.
우선 develop 브랜치에 ruby_client 브랜치(토픽브랜치)를 Merge한다.
그 후에 릴리즈해도 될만한 수준이 되면 master 브랜치를 develop 브랜치까지 Fast-forward시킨다.
이 Workflow를 사용하면 프로젝트 저장소를 Clone 하고나서 개발자가 안정 버전이 필요하면 master 브랜치를 빌드하고, 안정적이지 않더라도 좀 더 최신 버젼이 필요하면 develop 브랜치를 빌드하고, 안정적이지 않더라도 좀 더 최신 버전이 필요하면 develop 브랜치를 Checkout하여 빌드한다.
이 개념을 좀 더 확장해서 사용할 수 있다.
- 토픽 브랜치를 검증하기 위한 integrate 브랜치를 만들어 Merge하고
- 토픽 브랜치가 검증되면 develop 브랜치에 Merge한다.
- 그리고 develop 브랜치에서 충분히 안정하더는 것이 증명되면 그때 master 브랜치에 merge한다.
대규모 Merge Workflow
Git을 개발하는 프로젝트는 Long-Running의 브랜치를 4개 운영한다.
- master
- next
- pu(Proposed Updates)
- maint : 마지막으로 릴리즈한 버젼을 지원하는 브랜치
기여자가 새로운 기능을 제안하면 관리자는 다음 그림과 같이 자신의 저장소에 토픽 브랜치를 만들어 관리한다.
- 토픽 브랜치가 안정화되면 next로 Merge하고 저장소에 Push한다. 그러면 모두가 잘 통합되었는지 확인할 수 있다.
- 토픽 브랜치가 좀 더 개선되어야 한다면 next가 아니라 pu에 Merge한다.
- 그후 충분히 검증을 마치면 pu에서 next로 옮기고 next를 기반으로 pu를 다시 만든다.
- next에는 아직 master에 넣기에 모자라 보이는 것들이 들어있다.
- 즉 next브랜치는 가끔 Rebase하고, pu는 자주 Rebase하지만
- master는 항상 Fast-Forward한다.
토픽 브랜치가 결국 master 브랜치로 Merge되면 저장소에서 삭제한다. 그리고 이전 릴리즈 버전에 Patch가 필요하면 maint 브랜치를 이용해 대응한다. Git을 개발하는 프로젝트를 Clone하면 브랜치가 4개 있고 각 브랜치를 이용하여 진행사항을 확인해 볼수 있다. 그래서 새로운 기능을 추가하려면 적당한 브랜치를 보고 고른다. 이 Workflow는 잘 구조화 돼 있어서 코드가 새로 추가돼도 테스트하기 쉽다.
Rebase와 Cherry-pick Workflow
히스토리를 평평하게 관리하려고 Merge보다 Rebase나 Cherry-pick을 선호하는 관리자들도 있다. 토픽 브랜치에서 작업을 마친 후 master에 통합할 때 master 브랜치를 기반으로 Rebase한다. 그러면 커밋이 다시 만들어진다. master 대신 develop등의 브랜치에도 가능하다. 문제가 없으면 master 브랜치를 Fast-Forward 시킨다. 이렇게 평형한 히스토리를 유지할 수 있다.
한 브랜치에서 다른 브랜치로 작업한 내용을 옮기는 또 다른 방식으로 Cherry-pick이란 것도 있다.
Git의 Cherry-pick은 커밋 하나만 Rebase하는 것이다.
커밋 하나로 Patch 내용을 만들어 현재 브랜치에 적용을 하는 것이다. 토픽 브랜치에 있는 커밋 중에서 하나만 고르거나 토픽 브랜치에 커밋이 하나밖에 없을 때 Rebase 보다 유용하다.
Cherry-pick을 실행하기 전의 저장소 이다.
e43a6 커밋 하나만 현재 브랜치에 적용하려면 다음과 같은 명령을 실행한다.
$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
3 files changed, 17 insertions(+), 3 deletions(-)
위 명령을 실행하면 e43a6 커밋에서 변경된 내용을 현재 브랜치에 똑같이 적용을 한다. 하지만, 변경을 적용한 시점이 다르므로 새 커밋의 SHA-1 해시 값을 달라진다.
Rebase나 Cherry-pick 방식으로 토픽 브랜치를 합치고 나면 필요 없는 토픽 브랜치나 커밋은 삭제한다.
릴리스 버젼 태그 달기
적당한 때가 되면 릴리스해야 한다. 그리고 언제든지 그 시점으로 되돌릴 수 있게 태그를 다는 것이 좋다. 2장에서 살펴본 대로 태그를 달면 된다. 서명된 태그를 달면 다음과 같이 출력된다.
$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09
태그에 서명하면 서명에 사용한 PGP 공개키도 배포해야 한다. Git 개발 프로젝트는 관리자의 PGP 공개키를 Blog 형식으로 Git 저장소에 함께 배포한다. 이 Blob 파일을 사용하여 태그에 서명했다. 다음과 같은 명령으로 어떤 PGP 공개키를 포함할 지 확인한다.
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub 1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid Scott Chacon <schacon@gmail.com>
sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09]
git hash-object라는 명령으로 공개키를 바로 Git 저장소에 넣을 수 있다. 이 명령은 Git 저장소 안에 Blob 형식으로 공개키를 저장해주고, 그 Blob의 SHA-1 값을 알려준다.
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
이 SHA-1 해시값으로 PGP 공개키를 가리키는 태그를 만든다.
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
git push --tags 명령으로 앞서 만든 maintainer-pgp-pub 태그를 공유한다. 다른 사람이 태그의 서명을 확인하려면 우선 Git 저장소에 저장된 PGP 공개키를 꺼내서 GPG키 데이터베이스에 저장해야 한다.
$ git show maintainer-pgp-pub | gpg --import
사람들은 이렇게 공개키를 얻어서 서명된 태그를 확인한다. 또한, 관리자가 태그 메시지에 서명을 확인하는 방법을 적어 놓으면 좋다. git show <tag>으로 어떻게 서명된 태그를 확인하는 지 설명한다.
빌드 넘버 만들기
Git은 'v123' 처럼 숫자 형태로 커밋 이름을 만들지 않기 때문에 사람이 기억하기 어렵다. 하지만 git describe 명령으로 좀 더 사람이 기억하기 쉬운 이름을 얻을 수 있다 . Git은 가장 가까운 태그의 이름과, 태그에서 얼마나 더 커밋이 쌓였는지, 그리고 해당 커밋의 SHA-1 값을 조금 가져다가 이름을 만든다.
$ git describe master
v1.6.2-rc1-20-g8c5b85c
이렇게 사람이 읽을 수 있는 이름으로 스냅샷이나 빌드를 만든다. 만약 저장소에서 Clone한 후 소스코드로 Git을 설치하면 git --version 명령을 이렇게 생긴 빌드넘버를 보여준다. 태그가 달린 커밋에 git describe명령을 사용하면 다른 정보 없이 태그 이름만 사용한다.
git describe 명령은 -a나 -s 옵션을 주고 만든 Annotated 태그가 필요하다. 릴리스 태그는 git describe 명령으로 만드니까 꼭 이름이 적당한지 사전에 확인해야 한다. 그리고 이 값은 Checktou이나 Show 명령에도 사용할 수 있지만, 전적으로 이름 뒤에 붙은 SHA-1 값을 사용한다. 그래서 이 값으로는 해당 커밋을 찾지 못할 수도 있다. 최근 Linux 커널은 충돌 때문에 축약된 SHA-1를 8자에서 10자로 늘렸다. 이제는 8자일 때 생성한 겂을 사용할 수 없다.
릴리스 준비하기
먼저 Git을 사용하지 않는 사람을 위해 소스코드 스냅샷을 압축한다. 쉽게 압축할 수 있도록 Git은 git archive 명령을 지원한다.
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
이 압축 파일을 폴면 프로젝트의 가장 마지막 스냅샷이 나온다. ZIP 형식으로 압축파일을 만들려면 --format=zip 옵션을 사용한다.
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
이렇게 압축한 스냅샷 파일은 웹사이트나 이메일로 사람들에게 배포할 수 있다.
Shortlog 보기
이메일로 프로젝트의 변경 사항을 사람들에게 알려야 할때, git shortlog 명령을 사용하면 지난 릴리스 이후의 변경 사항 목록을 쉽게 얻어올 수 있다. git shortlog 명령은 주어진 범위에 있는 커밋을 요약해 준다. 아래는 최근 릴리스 버전인 v1.0.1 이후의 커밋을 요약해 주는 예제 이다.
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
Add support for annotated tags to Grit::Tag
Add packed-refs annotated tag support.
Add Grit::Commit#to_patch
Update version and History.txt
Remove stray `puts`
Make ls_tree ignore nils
Tom Preston-Werner (4):
fix dates in history
dynamic version method
Version bump to 1.0.2
Regenerated gemspec for version 1.0.2
이렇게 Author를 기준으로 정리한 커밋을 이메일로 전송한다.
'책 > 프로 Git' 카테고리의 다른 글
Git 도구-2 - 대화형 명령어 (0) | 2020.07.29 |
---|---|
Git 도구-1 - 리비전 조회하기 (0) | 2020.07.29 |
분산 환경에서의 Git-4 - 프로젝트에 기여하기 - 공개 팀 (0) | 2020.07.28 |
분산 환경에서의 Git-2 - 프로젝트에 기여하기 - 비공개 소규모 팀 (0) | 2020.07.28 |
분산 환경에서의 Git-3 - 프로젝트에 기여하기 - 비공개 대규모 팀 (0) | 2020.07.28 |