Pro git - 5.2
Updated:
Pro git - 프로젝트에 기여하기
0. 프로젝트에 기여하기
- 기여하는 방식에 영향을 끼치는 몇 가지 변수가 있다.
- 활발히 활동하는 개발자의 수
- 프로젝트에서 선택한 워크플로
- 접근 권한
1. 커밋 가이드라인
- Git 프로젝트에 보면 커밋 메시지를 작성하는데 참고할 만한 좋은 팁이 많다.
- Git 프로젝트의
Documentation/SubmittingPatches
문서를 참고하자. - 무엇보다도 먼저 공백문자를 깨끗하게 정리하고 커밋해야 한다.
-
커밋을 하기 전에
git diff --check
명령으로 공백문자에 대한 오류를 확인할 수 있다. - 각 커밋은 논리적으로 구분되는 Changeset이다.
- 최대한 수정사항을 한 주제로 요약할 수 있어야 한다.
- 여러 가지 이슈에 대한 수정사항을 하나의 커밋에 담지 않아야 한다.
- 작업 내용을 분할하고, 각 커밋마다 적절한 메시지를 작성한다.
- 같은 파일의 다른 부분을 수정하는 경우에는
git add -patch
명령을 써서 한 부분씩 나누어 Staging Area에 저장해야 한다. - 그래도 이왕이면 나누어 커밋하는 것이 좋다.
- 메시지의 첫 라인에 50자가 넘지 않는 아주 간략한 메시지를 적어 해당 커밋을 요약한다.
- 다음 한 라인은 비우고 그다음 라인부터 커밋을 자세히 설명한다.
- 현재형 표현을 사용하는 것이 좋다.
- 명령문으로 시작하는 것도 좋은 방법이다.
git log --no-merges
명령으로 메시지 확인 가능
영문 50글자 이하의 간략한 수정 요약
자세한 설명. 영문 72글자 이상이 되면
라인 바꿈을 하고 이어지는 내용을 작성한다.
특정 상황에서는 첫 번째 라인이 이메일
메시지의 제목이 되고 나머지는 메일
내용이 된다. 빈 라인은 본문과 요약을
구별해주기에 중요하다(본문 전체를 생략하지 않는 한).
이어지는 내용도 한 라인 띄우고 쓴다.
- 목록 표시도 사용할 수 있다.
- 보통 '-' 나 '*' 표시를 사용해서 목록을 표현하고
표시 앞에 공백 하나, 각 목록 사이에는 빈 라인
하나를 넣는데, 이건 상황에 따라 다르다.
git commit
명령에서-m
옵션을 사용하여 간단하게 적는다.- 우선적으로 시키는 대로 하는 것이 좋다.
2. 비공개 소규모 팀
- 비공개 소규모 팀 환경에서는 보통 Subversion 같은 중앙집중형 버전 관리 시스템에서 사용하던 방식을 사용한다.
2.1 예시
- 개발자인 John은 저장소를 Clone 하고 파일을 수정하고 나서 로컬에 커밋한다.
# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'remove invalid default value'
[master 738ee87] remove invalid default value
1 files changed, 1 insertions(+), 1 deletions(-)
- 개발자인 Jessica도 저장소를 Clone 하고 나서 파일을 하나 새로 추가하고 커밋한다.
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
1 files changed, 1 insertions(+), 0 deletions(-)
- Jessica는 서버에 커밋을 Push 한다.
# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc master -> master
- 마지막 줄의 기본적인 형태는
<oldref>..<newref> fromref -> toref
이다. oldref
는 이전 레퍼런스를,newref
는 새 레퍼런스를,fromref
는 Push 명령에서 사용한 로컬 레퍼런스의 이름을,toref
는 Push로 업데이트한 리모트 레퍼런스를 나타낸다.- John도 내용을 변경하고 커밋을 만든 후 서버로 커밋을 Push 하려고 한다.
# John's Machine
$ git push origin master
To john@githost:simplegit.git
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'
- Jessica의 Push한 내용으로 인해, John의 커밋은 서버에서 거절된다.
- Subversion에서는 서로 다른 파일을 수정하는 이런 Merge 작업은 자동으로 서버가 처리한다.
- 하지만 Git은 로컬에서 먼저 Merge 해야 한다.
- John은 Push 하기 전에 Jessica가 수정한 커밋을 Fetch 하고 Merge 해야 한다는 말이다.
$ git fetch origin
...
From john@githost:simplegit
+ 049d078...fbff5bc master -> origin/master
- Fetch 하고 나면 John의 로컬 저장소는 아래와 같이 된다.
- John은 Fetch하여 가져 온 Jessica의 작업 내용을 Merge 할 수 있다.
$ git merge origin/master
Merge made by the 'recursive' strategy.
TODO | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
- Merge가 잘 이루어지면 John의 브랜치는 아래와 같은 상태가 된다.
- John은 Merge 하고 나서 자신이 작업한 코드가 제대로 동작하는지 확인한다. 그 후에 공유하는 저장소에 Push 한다.
$ git push origin master
...
To john@githost:simplegit.git
fbff5bc..72bbc59 master -> master
- John의 저장소는 아래와 같이 되었다.
- 동시에 Jessica는 토픽 브랜치를 하나 만든다.
- issue54 브랜치를 만들고 세 번에 걸쳐서 커밋한다.
- 아직 John의 커밋을 Fetch 하지 않은 상황이기 때문에 아래와 같은 상황이 된다.
- Jessica는 John이 새로 Push했다는 것을 알게 되어 하던 작업을 멈추고 John의 작업 내용을 살펴보려고 한다.
- 하지만 아직 Jessica는 John의 변경사항을 가지고 있지 않은 상태이다.
# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
fbff5bc..72bbc59 master -> origin/master
- John이 Push 한 커밋을 모두 내려받는다.
- 그러면 Jessica의 저장소는 아래와 같은 상태가 된다.
- 이제
orgin/master
와 Merge 할 차례다. - Jessica는 토픽 브랜치에서의 작업을 마치고 어떤 내용이 Merge 되는지
git log
명령으로 확인한다.
$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date: Fri May 29 16:01:27 2009 -0700
remove invalid default value
issue54..origin/master
문법은 히스토리를 검색할 때 뒤의 브랜치(origin/master
)에 속한 커밋 중 앞의 브랜치(issue54
)에 속하지 않은 커밋을 검색하는 문법이다.- 히스토리를 검색한 결과 John이 생성하고 Jessica가 Merge 하지 않은 커밋을 하나 찾았다.
-
origin/master
브랜치를 Merge 하게 되면 검색된 커밋 하나가 로컬 작업에 Merge 될 것이다. - Merge 할 내용을 확인한 Jessica는 자신이 작업한 내용과 John이 Push 한 작업(
origin/master
)을master
브랜치에 Merge 하고 Push 한다. issue54
토픽 브랜치에 쌓은 모든 내용을 합치려면, 우선master
브랜치를 Checkout 해야 한다.
$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
-
origin/master
,issue54
모두 Upstream 브랜치이기 때문에 둘 중에 무엇을 먼저 Merge 하든 상관이 없다. - 물론 어떤 것을 먼저 Merge 하느냐에 따라 히스토리 순서는 달라지지만, 최종 결과는 똑같다.
- Jessica는 먼저
issue54
브랜치를 Merge 한다.
$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
README | 1 +
lib/simplegit.rb | 6 +++++-
2 files changed, 6 insertions(+), 1 deletions(-)
- 보다시피 Fast-forward Merge 이기 때문에 명령 실행 결과는 별 문제가 없다.
origin/master
에 쌓여있던 John의 작업 내용을 다음과 같이 실행하여 Jessica는 Merge 작업을 완료할 수 있다.
$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
origin/master
브랜치가 Jessica의master
브랜치로 나아갈(reachable) 수 있기 때문에 Push는 성공한다(물론 John이 그 사이에 Push 하지 않았다면).
$ git push origin master
...
To jessica@githost:simplegit.git
72bbc59..8059c15 master -> master
- 두 개발자의 커밋을 성공적으로 Merge 하고 나면 결과는 아래와 같다.
2.2 정리
- 토픽 브랜치에서 수정하고 로컬의
master
브랜치에 Merge 한다. - 작업한 내용을 프로젝트의 공유 저장소에 Push 하고자 할 때는 우선
origin/master
브랜치를 Fetch 하고 Merge 한다. - 그리고 나서 Merge 한 결과를 다시 서버로 Push 한다.
3. 비공개 대규모 팀
-
보통 팀을 여러 개로 나눈다. 그래서 각각의 작은 팀이 서로 어떻게 하나로 Merge 하는지를 살펴본다.
- John과 Jessica는 “featureA” 기능을 함께 작업하게 됐다.
- Jessica는 Josie와 함께 “featureB” 기능도 작업하고 있다.
- 이런 상황이라면 회사는 Integration-manager 워크플로를 선택하는 게 좋다.
- 작은 팀이 수행한 결과물은 Integration-Manager가 Merge 하고 공유 저장소의
master
브랜치를 업데이트한다. - 팀마다 브랜치를 하나씩 만들고 Integration-Manager는 그 브랜치를 Pull 해서 Merge 한다.
- 두 팀에 모두 속한 Jessica의 작업 순서를 살펴보자.
- 우선 Jessica는 저장소를 Clone 하고
featureA
작업을 먼저 한다. featureA
브랜치를 만들고 수정하고 커밋한다.
# Jessica's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
1 files changed, 1 insertions(+), 1 deletions(-)
- 이 수정한 부분을 John과 공유해야 한다.
- 공유하려면 우선
featureA
브랜치를 서버로 Push 한다. - Integration-Manager만
master
브랜치를 업데이트할 수 있기 때문에 master 브랜치로 Push를 할 수 없고 다른 브랜치로 John과 공유한다.
$ git push -u origin featureA
...
To jessica@githost:simplegit.git
* [new branch] featureA -> featureA
- Jessica는 자신이 한 일을
featureA
라는 브랜치로 Push 했다는 이메일을 John에게 보낸다. - John의 피드백을 기다리는 동안 Jessica는 Josie와 함께 하는
featureB
작업을 하기로 한다. - 서버의
master
브랜치를 기반으로 새로운 브랜치를 하나 만든다.
# Jessica's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'
- 몇 가지 작업을 하고
featureB
브랜치에 커밋한다.
$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
1 files changed, 5 insertions(+), 0 deletions(-)
- 그럼 Jessica의 저장소는 그림 아래와 같다.
- 작업을 마치고 Push 하려고 하는데 Jesie가 이미 “featureB” 작업을 하고 서버에
featureBee
브랜치로 Push 했다는 이메일을 보내왔다. - Jessica는 Josie의 작업을 먼저 Merge 해야만 Push 할 수 있다.
- Merge 하기 위해서 우선
git fetch
로 Fetch 한다.
$ git fetch origin
...
From jessica@githost:simplegit
* [new branch] featureBee -> origin/featureBee
- Jessica가 앞서 Checkout 한
featureB
브랜치에서 작업중일 때, Fetch 해 온 브랜치를git merge
명령으로 Merge 한다.
$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
lib/simplegit.rb | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
- 이 시점에서 Jessica는 Merge 한 “featureB” 작업을 서버로 Push 할 때 서버의
featureB
브랜치로 Push하지 않고자 한다. - 이미 Josie가 생성한
featureBee
로 작업 내용을 Push 하려면 아래와 같이 실행한다.
$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
fba9af8..cd685d1 featureB -> featureBee
- 이것은 refspec 이란 것을 사용하는 것인데 Refspec 에서 자세하게 설명한다.
-
명령에서 사용한
-u
옵션은--set-upstream
옵션의 짧은 표현인데 브랜치를 추적하도록 설정해서 이후 Push 나 Pull 할 때 좀 더 편하게 사용할 수 있다. - John이 몇 가지 작업을 하고 나서
featureA
에 Push 했고 확인해 달라는 내용의 이메일을 보내왔다. - Jessica는 John의 작업 내용을 확인하기 위해 다시 한 번
git fetch
로 Push된 작업을 Fetch 한다.
$ git fetch origin
...
From jessica@githost:simplegit
3300904..aad881d featureA -> origin/featureA
- Jessica의 로컬
featureA
브랜치와 Fetch 해 온 John의 작업내용이 같은featureA
브랜치 상에서 어떤 것이 업데이트됐는지git log
명령으로 확인한다.
$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date: Fri May 29 19:57:33 2009 -0700
changed log output to 30 from 25
- 확인을 마치면 로컬의
featureA
브랜치로 John의 작업 내용을 다음과 같이 Merge 한다.
$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
lib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
Jessica는 일부 수정하고, featureA
브랜치에 커밋하고, 수정한 내용을 다시 서버로 Push 한다.
$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
3300904..774b3ed featureA -> featureA
- 위와 같은 작업을 마치고 나면 Jessica의 저장소는 아래와 같은 모습이 된다.
- 그럼
featureA
와featureBee
브랜치가 프로젝트의 메인 브랜치로 Merge 할 준비가 되었다고 Integration-Manager에게 알려준다. - Integration-Manager가 두 브랜치를 모두 Merge 하고 난 후에 메인 브랜치를 Fetch 하면 아래와 같은 모양이 된다.
3.1 정리
4. 공개 프로젝트 Fork
- 공개 팀을 운영할 때는 모든 개발자가 프로젝트의 공유 저장소에 직접적으로 쓰기 권한을 가지지는 않는다.
- 프로젝트 관리자는 보통 Fork 하는 것으로 프로젝트를 운영한다.
- 우선 처음 할 일은 메인 저장소를 Clone 하는 것이다.
- 그리고 나서 토픽 브랜치를 만들고 일정 부분 기여한다.
$ git clone <url>
$ cd project
$ git checkout -b featureA
... work ...
$ git commit
... work ...
$ git commit
-
rebase -i
명령을 사용하면 여러 커밋을 하나의 커밋으로 합치거나 프로젝트의 관리자가 수정사항을 쉽게 이해하도록 커밋을 정리할 수 있다. - 일단 프로젝트의 웹사이트로 가서 “Fork” 버튼을 누르면 원래 프로젝트 저장소에서 갈라져 나온, 쓰기 권한이 있는 저장소가 하나 만들어진다.
- 그러면 로컬에서 수정한 커밋을 원래 저장소에 Push 할 수 있다.
- 그 저장소를 로컬 저장소의 리모트 저장소로 등록한다
$ git remote add myfork <url>
- 자 이제 등록한 리모트 저장소에 Push 한다.
- 작업하던 것을 로컬 저장소의
master
브랜치에 Merge 한 후 Push 하는 것보다 리모트 브랜치에 바로 Push를 하는 방식이 훨씬 간단하다. - 이렇게 하는 이유는 관리자가 토픽 브랜치를 프로젝트에 포함시키고 싶지 않을 때 토픽 브랜치를 Merge 하기 이전 상태로
master
브랜치를 되돌릴 필요가 없기 때문이다. - 관리자가 토픽 브랜치를 Merge 하든 Rebase 하든 Cherry-Pick 하든지 간에 결국 다시 관리자의 저장소를 Pull 할 때는 토픽 브랜치의 내용이 들어 있을 것이다.
- 어떤 경우라도 다음과 같이 작업 내용을 Push 할 수 있다.
$ git push -u myfork featureA
- Fork 한 저장소에 Push 하고 나면 프로젝트 관리자에게 이 내용을 알려야 한다.
- 이것을 Pull Request 라고 한다.
- Git 호스팅 사이트에서 관리자에게 보낼 메시지를 생성하거나
git request-pull
명령으로 이메일을 수동으로 만들 수 있다. -
GitHub의 “Pull Request” 버튼은 자동으로 메시지를 만들어 주는데 관련 내용은 GitHub 에서 살펴볼 수 있다.
git request-pull
명령은 아규먼트를 두 개 입력받는다.- 첫 번째 아규먼트는 작업한 토픽 브랜치의 Base 브랜치이다.
- 두 번째는 토픽 브랜치가 위치한 저장소 URL인데 위에서 등록한 리모트 저장소 이름을 적을 수 있다.
- 이 명령은 토픽 브랜치 수정사항을 요약한 내용을 결과로 보여준다.
- 예를 들어 Jessica가 John에게 Pull 요청을 보내는 상황을 살펴보자.
- Jessica는 토픽 브랜치에 두 번 커밋을 하고 Fork 한 저장소에 Push 했다. 그리고 아래와 같이 실행한다.
$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
Jessica Smith (1):
added a new function
are available in the git repository at:
git://githost/simplegit.git featureA
Jessica Smith (2):
add limit to log function
change log output to 30 from 25
lib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
- 관리자에게 이 내용을 보낸다.
-
이 내용에는 토픽 브랜치가 어느 시점에 갈라져 나온 것인지, 어떤 커밋이 있는지, Pull 하려면 어떤 저장소에 접근해야 하는지에 대한 내용이 들어 있다.
- 프로젝트 관리자가 아니라고 해도 보통
origin/master
를 추적하는master
브랜치는 가지고 있다. - 그래도 토픽 브랜치를 만들고 일을 하면 관리자가 수정 내용을 거부할 때 쉽게 버릴 수 있다.
- 토픽 브랜치를 만들어서 주제별로 독립적으로 일을 하는 동안에도 주 저장소의
master
브랜치는 계속 수정된다. - 하지만 주 저장소의 브랜치의 최근 커밋 이후로 Rebase 하면 깨끗하게 Merge 할 수 있다.
- 그리고 다른 주제의 일을 하려고 할 때는 앞서 Push 한 토픽 브랜치에서 시작하지 말고 주 저장소의
master
브랜치로부터 만들어야 한다.
$ git checkout -b featureB origin/master
... work ...
$ git commit
$ git push myfork featureB
$ git request-pull origin/master myfork
... email generated request pull to maintainer ...
$ git fetch origin
- 각 토픽은 일종의 실험실이라고 할 수 있다.
- 각 토픽은 서로 방해하지 않고 독립적으로 수정하고 Rebase 할 수 있다.
- 프로젝트 관리자가 사람들의 수정 사항을 Merge 하고 나서 Jessica의 브랜치를 Merge 하려고 할 때 충돌이 날 수도 있다.
- 그러면 Jessica가 자신의 브랜치를
origin/master
에 Rebase 해서 충돌을 해결하고 다시 Pull Request을 보낸다.
$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA
- 명령들을 실행하고 나면 히스토리는 아래와 같아진다.
- 브랜치를 Rebase 해 버렸기 때문에 Push 할 때
-f
옵션을 주고 강제로 기존 서버에 있던featureA
브랜치의 내용을 덮어 써야 한다. -
아니면 새로운 브랜치를(예를 들어
featureAv2
) 서버에 Push 해도 된다. - 또 다른 시나리오를 하나 더 살펴보자.
- 프로젝트 관리자는
featureB
브랜치의 내용은 좋지만, 상세 구현은 다르게 하고 싶다. - 관리자는
featureB
담당자에게 상세 구현을 다르게 해달라고 요청한다. featureB
담당자는 하는 김에featureB
브랜치를 프로젝트의 최신master
브랜치 기반으로 옮긴다.- 먼저
origin/master
브랜치에서featureBv2
브랜치를 새로 하나 만들고,featureB
의 커밋들을 모두 Squash 해서 Merge 하고, 만약 충돌이 나면 해결하고, 상세 구현을 수정하고, 새 브랜치를 Push 한다.
$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
... change implementation ...
$ git commit
$ git push myfork featureBv2
--squash
옵션은 현재 브랜치에 Merge 할 때 해당 브랜치의 커밋을 모두 커밋 하나로 합쳐서 Merge 한다.- 이 때 Merge 커밋은 만들지 않는다.
- 다른 브랜치에서 수정한 사항을 전부 가져오는 것은 똑같다.
- 하지만 새로 만들어지는 커밋은 부모가 하나이고 커밋을 기록하기 전에 좀 더 수정할 기회도 있다.
- 다른 브랜치에서 수정한 사항을 전부 가져오면서 그전에 추가적으로 수정할 게 있으면 수정하고 Merge 할 수 있다.
- 게다가 새로 만들어지는 커밋은 부모가 하나다.
-
--no-commit
옵션을 추가하면 커밋을 합쳐 놓고 자동으로 커밋하지 않는다. - 수정을 마치면 관리자에게
featureBv2
브랜치를 확인해 보라고 메시지를 보낸다.
5. 대규모 공개 프로젝트와 이메일을 통한 관리
- 대규모 프로젝트는 보통 수정사항이나 Patch를 수용하는 자신만의 규칙을 마련해놓고 있다.
- 프로젝트마다 규칙은 서로 다를 수 있으므로 각 프로젝트의 규칙을 미리 알아둘 필요가 있다.
- 오래된 대규모 프로젝트는 대부분 메일링리스트를 통해서 Patch를 받아들이는데 예제를 통해 살펴본다.
- 토픽 브랜치를 만들어 수정하는 작업은 앞서 살펴본 바와 거의 비슷하지만, Patch를 제출하는 방식이 다르다.
- 프로젝트를 Fork 하여 Push 하는 것이 아니라 커밋 내용을 메일로 만들어 개발자 메일링리스트에 제출한다.
$ git checkout -b topicA
... work ...
$ git commit
... work ...
$ git commit
- 커밋을 두 번 하고 메일링리스트에 보내 보자.
git format-patch
명령으로 메일링리스트에 보낼 mbox 형식의 파일을 생성한다.- 각 커밋은 하나씩 이메일 메시지로 생성되는데 커밋 메시지의 첫 번째 라인이 제목이 되고 Merge 메시지 내용과 Patch 자체가 메일 메시지의 본문이 된다.
- 이 방식은 수신한 이메일에 들어 있는 Patch를 바로 적용할 수 있어서 좋다.
- 메일 속에는 커밋의 모든 내용이 포함된다. 메일에 포함된 Patch를 적용하는 것은 다음 절에서 살펴본다.
$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
format-patch
명령을 실행하면 생성한 파일 이름을 보여준다.-M
옵션은 이름이 변경된 파일이 있는지 살펴보라는 옵션이다. 각 파일의 내용은 아래와 같다.
$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function
Limit log functionality to the first 20
---
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
end
def log(treeish = 'master')
- command("git log #{treeish}")
+ command("git log -n 20 #{treeish}")
end
def ls_tree(treeish = 'master')
--
2.1.0
- 메일링리스트에 이메일을 보내기 전에 각 Patch 파일을 손으로 고칠 수 있다.
---
라인과 Patch가 시작되는 라인(diff --git
로 시작하는 라인) 사이에 내용을 추가하면 다른 개발자는 읽을 수 있지만, 나중에 Patch에 적용되지는 않는다.- 특정 메일 프로그램을 사용하거나 이메일을 보내는 명령어로 메일링리스트에 보낼 수 있다.
- 붙여 넣기로 위의 내용이 그대로 들어가지 않는 메일 프로그램도 있다.
- 사용자 편의를 위해 공백이나 라인 바꿈 문자 등을 넣어 주는 메일 프로그램은 원본 그대로 들어가지 않는다.
- 다행히 Git에는 Patch 메일을 그대로 보낼 수 있는 도구가 있다. IMAP 프로토콜로 보낸다.
- 저자가 사용하는 방법으로 Gmail을 사용하여 Patch 메일을 전송하는 방법을 살펴보자.
- 추가로 Git 프로젝트의
Documentation/SubmittingPatches
문서의 마지막 부분을 살펴보면 다양한 메일 프로그램으로 메일을 보내는 방법을 설명한다. - 메일을 보내려면 먼저
~/.gitconfig
파일에서 이메일 부분 설정한다. git config
명령으로 추가할 수도 있고 직접 파일을 열어서 추가할 수도 있다.
[imap]
folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com
user = user@gmail.com
pass = YX]8g76G_2^sFbd
port = 993
sslverify = false
- IMAP 서버가 SSL을 사용하지 않으면 마지막 두 라인은 필요 없고 host에서
imaps://
대신imap://
로 한다. - 이렇게 설정하면
git imap-send
명령으로 Patch 파일을 IMAP 서버의 Draft 폴더에 이메일로 보낼 수 있다.
$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done
-
이후 Gmail의 Draft 폴더로 가서 To 부분을 메일링리스트의 주소로 변경하고 CC 부분에 해당 메일을 참고해야 하는 관리자나 개발자의 메일 주소를 적고 실제로 전송한다.
- SMTP 서버를 이용해서 Patch를 보낼 수도 있다.
- 먼저 SMTP 서버를 설정해야 한다.
git config
명령으로 하나씩 설정할 수도 있지만 아래와 같이~/.gitconfig
파일의 sendemail 섹션을 손으로 직접 고쳐도 된다.
[sendemail]
smtpencryption = tls
smtpserver = smtp.gmail.com
smtpuser = user@gmail.com
smtpserverport = 587
- 이렇게 설정하면
git send-email
명령으로 패치를 보낼 수 있다.
$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y
- 명령을 실행하면 아래와 같이 서버로 Patch를 보내는 내용이 화면에 나타난다.
(mbox) Adding cc: Jessica Smith <jessica@example.com> from
\line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>
Result: OK