책은 3개 부로 구성
- 1부 워크플로우 작성하기(1장 - 4장)
- 2부 워크플로우에 명령어 적용하기(5장 - 9장)
- 3부 Git 호스팅(10장 - 12장)
- 부록: 몇몇 Git 관련 도구 사용법
- "끝을 생각하며 시작하라": 어떤 문제를 해결할 것인가? (사용자 경험에서 시작)
- 테스트 주도 개발: 테스트를 먼저 작성할 때의 장점(문제 해결 확인, 소프트웨어 동작 결과를 미리 이해)
- 테스트 과정에는 보안 검수 과정을 포함
- 배포 환경 구축
- 오픈소스 개발 커뮤니티와의 관계
- 솔루션 구현 계획을 결정하고 문서화, 공유
- 개별 팀원들이 능동적인 합의 지향 개발할 수 있는 환경 조성
- 팀원마다 선호하는 작업 방식이 다르다: 개별 팀원을 생산적으로 만들 전략 공유
- 사고의 세 차원(창조적 사고, 이해하는 사고, 결정하는 사고) + 개인의 정신
- 개인이 특정한 사고 전략을 고집하면 팀이 무너질 위험이 있음.
- 상상력, 재구성, 브레인스토밍, 통찰력, 도전, 집중 등의 특성
- 예상치 못한 문제 해결 방법을 찾아냄
- 워크플로우를 개선하고 큰 문제를 해결
- 상황 파악(조사, 정보수집), 명료한 인식, 구조화(정리), 듣는 자세, 공감, 표현
- 정보에 대한 이해 / 사람에 대한 이해
- 분석적인 사고
- 패턴을 인식, 상황을 명확하게 인식하고 설명
- 핵심 파악, 결정력, 결론 입증, 경험, 가치 기반 결정, 직감
- 최선의 해법을 찾아내는 능력
- 인내심 부족
- 시작-진행-끝 시퀀스(시작, 진행, 결론): 회의할 때는 먼저 무엇을 할 것인지 정하고, 진행하고, 결정한 것을 정리
- 공동 시작 회의에는 모든 팀원을 참가(대면)시키는 것이 좋다.
- 정기적인 팀 회의
- 일주일 단위의 짧은 스프린트의 장점: 문제를 숨기기 어려움
- 일정 회의(스탠드업 회의): 매주 여러 차례 같은 시간에 진행. '약속'을 결과물로 내야 함. "다음 일정 회의까지 제출할 부분이 무엇인가?"
- 프로젝트 딥다이브 회의
- 스프린트 데모: 매주 한 번 작업 현황 공유
- 스프린트 회고: 스프린트가 끝날 때마다 팀을 모아 작업 과정 논의
- 전사적 스탠드업
- 일대일: 추첨을 통해 전화 통화 등으로 편하게 자유 주제로 대화
- 같이 일하는 사람들에 대한 충분한 관심
- 이야기 수집: 사람들에게 무슨 일이 있는지 묻기
- 의식적으로 듣기: 딴짓 없이 들어야 함. 말을 끊지도 말 것.
- 되묻기: 이전에 들은 이야기의 최신 상황 물어보기
- 결과 회의와 회고 회의
- 프로젝트의 잘 된 점과 개선할 점이 무엇인지 토론
- 부끄러워하거나 비난하지 않고 잘 안 된 점을 말할 수 있어야 함
- 로컬 사본
- 코드 호스팅, GitHub
- clone(fork)
- upstream: 제품의 공식 버전
- pull: fetch + merge
- push
- 서로 신뢰하고 공감하는 팀
- 상황에 따라 적절한 사고 전략이 다르다
- 자신의 작업을 투명하게 공개
- 중요한 시기에 이해당사자를 팀에 포함
- 저자의 권리와 프로젝트 저장소 관리자의 책임
- 저작권: 특정한 산물을 사용하고 배포할 수 있는 배타적 권리. 양도가능.
- 직무저작물: 노동자(또는 프리랜서)가 돈받고 고용주에게 만들어 준 것.
- 구현물에 대해서만 저작권을 가질 수 있다. 아이디어는 저작권 안 된다.
- 오픈소스에 참여할 때 고용 문제가 얽혀 있으면 저작권 문제가 복잡해질 수 있다.
- 기업들의 저작권 동의서 문제: 오픈소스 정신에 위배됨
- 배포 라이선스: 프로젝트를 어떻게 사용하면 되고 어떻게 사용하면 안 되는지 명확히 하는 것.
- MIT 라이선스
- 아파치 라이선스
- GPL
- CCL
- 자비로운 종신독재자(BDFL): 리더가 모든 최정 결정 권한을 가짐.
- 합의 기반, 리더 승인: 가장 능동적인 커뮤니티 구성원들이 적절한 솔루션을 찾도록 독려. 승인된 이슈는 RTBC로 표시됨.
- 기술 검토진 또는 프로젝트 관리 위원회
- 커뮤니티가 잘 굴러가도록 하는 규칙을 정해서
- 프로젝트 지원 사이트에 행동 수칙 문서를 추가.
- Git은 작업자들이 중앙 저장소에 종속되어 일하는 것이 아니라, 독립적으로 개별 로컬 사본에서 작업한다.
- MBTI로 보면: Git은 INTP, Subversion은 ESFJ다.
- Git에는 접근을 통제하는 기능이 없다. 별도의 로그인 기능을 통해 제한.
- 작업자는 Git 호스팅에 수정 권한을 갖거나, pull 요청을 통해 기여.
- 다음으로 세 가지 유명한 접근 모델을 다룬다.
- 각 작업자는 diff로 패치를 생성하여 다른 개발자들에게 메일을 보낸다.
- 메일을 받은 개발자는 로컬 소스코드에 patch 명령어로 패치를 적용하고, 수정사항을 검토한다.
- 코드 공유를 메일로 하기 때문에 갱신 전에 최대한 꼼꼼한 작업을 위해 노력하게 되고, 리뷰어들이 검토한 내용만이 서로 병합된다.
- 최근의 대부분 프로젝트에는 별로 적합하지 않은 방식이다.
- bitsect, rebase 같은 명령어가 왜 필요한지 이해할 수 있는 모델.
- "업스트림" 프로젝트가 주 프로젝트가 됨
- 개별 기여자는 그 프로젝트를 clone, fork하여 코드 호스팅 시스템 내 자신의 저장소에 생성
- 기여자들은 복사본을 수정한 후 수정 사항을 merge 요청하거나 pull 요청 하는 방식으로 제출.
- 다수 기여자가 참여하는 오픈소스 프로젝트에서 많이 사용되는 모델.
- GitHub를 통해 유명해진 모델.
- GitHub를 통한 기여 방법 자세한 설명 필요 (p59)
- 내부 팀(비공개 팀), 1인 팀이 가장 일반적으로 사용하는 권한 모델.
- 팀원 간의 신뢰를 전제: "누구든 코드를 메인 프로젝트 브랜치에 커밋할 때는 먼저 검토를 할 것이다."
- 하나의 공유 저장소가 있고, 모든 사람은 그 저장소에 쓰기 권한을 공유한다.
- Git 자체에는 승인 기능이 없다. 저장소 쓰기 권한 허용/거부는 다른 시스템 (Git 호스팅 플랫폼 또는 SSH 계정)에 의존한다.
- Git에는 특정 브랜치를 수정하지 못하게 고정하는 기능도 없다. 테스트 없이 수정사항을 커밋하지 않게 합의하는 수밖에 없다. Bitbucket, GitLab은 브랜치별 접근 제한을 지원한다.
- 커밋은 부모를 참조하는 방식으로 서로 연결되어 있다.
- 브랜치는 특정 커밋에 대한 이름 있는 포인터.
- 커밋은 생성된 로컬 영역에 속하고, 생성한 사람만의 것이다. 커밋하면 자동으로 업로드되는 중앙화된 버전 관리 모델과의 차이.
- 브랜치 네이밍 충돌을 방지하기 위한 규약이 필요함.
- 일반적인 규약에는 장기 공개 브랜치와 단기 비공개 브랜치가 있다. 장기 브랜치는 여러 개발자가 기여한 코드의 중심점이 되고, 단기 브랜치는 실험을 위한 샌드박스 구실을 한다.
- 브랜치를 공유한 이후에는 다른 사람도 그 브랜치를 수정해서 병합 충돌이 있을 수 있다.
- 규약이란 작업을 보통 어떤 식으로 할지에 대한 합의된 표준
- 규약을 문서화하면 새로운 참여자에게 도움이 됨
- 적절한 브랜치 전략을 선택하려면 팀원들이 원하는 작업 릴리스 방식에 관해 대화해야 한다.
- 일반적인 두 가지 접근법: 항상 통합, 완료된 작업을 모아 한 번에 릴리즈
- 개발자들은 검토 완료한 작업을 하나의 중앙 브랜치에 지속적으로 커밋.
- 중앙 브랜치는 항상 배포 준비 상태로 유지.
- 자동 빌드 과정을 사용하는 팀이 하나의 작업 브랜치로 일하는 경우가 많다. (연속 통합, 연속 전달, 연속 배포)
- 브랜치 수가 적어 혼란이 적다.
- 코드 베이스에 추가되는 커밋 분량이 비교적 적어 문제 해결이 쉽다.
- 긴급 수정이 필요한 경우가 적다.
- 테스트 환경이 갖춰지지 않을 경우 위험하다.
- 배포는 웹사이트의 경우에 더 적합하다. 최종사용자가 매번 패치를 받게 하는 경우 불편하다.
- 플래그를 사용해 코드를 숨길 경우 삭제되지 않은 쓰레기 코드가 쌓일 우려가 있다.
- 기능 브랜치와 통합 브랜치를 추가
- 새로운 모든 작업은 기능 브랜치에서 이루어짐
- 기능 브랜치는 통합 브랜치에서 수정사항을 가져와 최신 상태를 유지
- 기능 브랜치 하나하나는 하나의 온전한 아이디어를 담을 만큼의 크기로 한정
- 소프트웨어를 릴리즈할 때는 빌드에 포함시킬 기능을 선택하여 새로운 통합 브랜치를 생성해 배포
- 메인라인 개발처럼 빠른 배포가 가능
- 메인라인 개발과 달리, 선택적인 빌드 단계가 있다
- 기능 브랜치에 있는 코드가 마스터에 추가되지 않으면 계속 추가로 유지보수하여 최신 상태로 유지해야 한다.
- 의미 있는 브랜치 이름이라고 해도 새로 참여하는 사람은 파악하기 힘들다.
- 마스터에 추가된 오래된 브랜치를 삭제하는 관리 업무가 추가 발생
- 브랜치 네이밍 규약을 통해 어떤 환경(개발/준비/출시)을 위한 커밋인지 명시
- Git 프로젝트의 브랜치 네이밍 규약: maint(최신 안정 릴리즈 버전), master(다음 릴리즈에 추가될 커밋), next(master에 포함되기 전, 안정성 테스트 대상), pu(업데이트 제안. 통합 준비를 마치지 못한 커밋을 포함)
- 브랜치 이름으로 구체적 작업 상황이 설명됨
- 작업을 어느 브랜치에 병합해야 하는지 쉽게 파악 가능
- 이름이 아무리 구체적이어도 모호성이 남을 수 있다
- 브랜치 이름이 매우 구체적이어서 일관성을 유지하기 어렵다
- 배포가 자동화되지 않고, 때때로 배포해야 하는 경우. (타인이 배포 과정을 통제하는 상황)
- 하나의 브랜치 develop에서 출발
- 개발자들은 develop에서 갈라지는 브랜치를 생성하고 기능을 추가
- 티켓을 통해 이슈를 설명하고, 브랜치의 이름은 티켓 이름으로 붙임.
- 기능 동결 상황에서는 개발 브랜치에서 새로운 브랜치(release)를 생성. 이 브랜치에는 버그 수정 커밋만을 허용.
- 기능 동결 후에 추가로 개발되는 기능은 여전히 develop 브랜치에 커밋. 버그 수정은 release에서 이뤄진 후 develop에 병합.
- release에서 모든 버그가 수정되면 새로운 브랜치 master에 커밋. 소프트웨어 버전을 태그.
- 핫픽스는 제품 브랜치(master)에서 분기해서 만든다. 이후 develop에 병합.
- 대규모 테스트 기반이 필요하지 않다
- 일반적인 소프트웨어 개발 과정(개발, 품질 보증, 완성)과 합치된다.
- 규약을 충실히 지키면 작업을 시작할 브랜치를 쉽게 파악할 수 있다.
- 정기적으로 버전업하는 소프트웨어(앱스토어의 앱 등. 즉, 수시로 업데이트하는 웹 사이트의 반대) 개발에 잘 어울린다.
- 소프트웨어 배포를 경험해보지 않은 개발자들이 익숙해지기 어렵다.
- 잘못된 브랜치에서 작업을 시작할 경우 복구가 힘들다.
- 연속 배포 모델보다 구식이다.
- 브랜치들은 자동으로 최신 상태를 유지하지 않는다.
- 브랜치를 업데이트하는 전략은 병합(merge)과 리베이스(rebase) 두 가지다.
- 다른 저장소의 브랜치를 가져온 후 커밋을 추가하게 되면, 이 브랜치의 동기화 상태가 깨진다. fetch를 통해 원격의 수정사항을 업데이트할 수 있다.
- pull은 fetch와 merge 또는 fetch와 rebase의 조합이다. (기본은 merge)
- rebase는 브랜치의 히스토리를 수정하여 수정사항이 원래 있었던 것처럼 보이게 함
- merge의 빨리감기 전략을 적용하면 결과가 rebase와 사실상 동일하다.
- 두 브랜치에서 모두 수정사항이 발생한 경우 빨리감기 전략을 사용할 수 없다. 이 경우 merge는 수정사항을 각각 양방향에서 연결한다. 히스토리 그래프가 복잡해지는 문제가 있다.
- 이 동기화 문제 때문에 프로젝트에 다시 합칠 작업은 추적 브랜치에서 하지 않는다. 추적 브랜치는 master, release 등의 장기적 브랜치가 되고, 작업 브랜치는 기능 브랜치나 티켓, 핫픽스 브랜치가 된다.
- 병합 방식은 사용이 용이하고, 리베이스 방식은 히스토리 그래프가 보기 좋다.
- 브랜치 전략을 결정해야 한다.
- 브랜치 병합 전략을 결정해야 한다.
- Git의 사용법은 사용자에게 달려 있다. 여러 사람이 일관성있게 버전관리를 하도록 하려면 규칙/체크리스트를 문서화한다.
- 워크플로우에는 프로젝트 매니저, 개발 사이트 URL, 배포 브랜치 등이 포함 (예제 4-1)
- 공동 작업을 할 때는 코드 권한 분할 다이어그램을 그려보는 것도 좋다.
- 이슈 추적을 위해 티켓 시스템(중앙화된 이슈 추적기), 화이트보드/포스트잇, 간단한 스프레드시트 등이 이용된다
- 어떤 시스템을 사용하더라도, 쉽게 읽을 수 있고 검색 가능한 시스템을 이용해 특정 기능을 추가한 이유를 추적할 수 있게 기록해야 한다.
- 특정 티켓 시스템을 이용하면 해당 시스템에 지나치게 의존적이 될 수 있다.
- 여러 Git 호스팅 플랫폼이 티켓 시스템을 추가로 제공한다.
- 마감기한이 없는 내부 프로젝트라도 작업을 짧은 시간 단위로 쪼개는 것이 좋다. (1주 단위 스프린트를 추천) 임의의 마감기한은 작업 진척의 동기가 된다.
- 마감된 작업의 데모 시연을 하는 것도 좋다. 데모 시연에는 Hangout, GoToMeeting 등이 편리하다.
- 티켓 상태의 분류: 나중 작업(진행하면 안된다), 작업 준비 완료, 진행 중, 완료
- 티켓 상태 분류를 너무 많이 만들어서는 안 된다. 시스템이 복잡할수록 개발자들의 판단비용/소통비용이 증가한다.
- 대화가 중요하다: 작업 완료에 방해가 되는 것은 무엇인지, 실제 어떤 작업을 정확히 하고 있는지 등.
- 기본 워크플로우: 1-2인의 작은 팀에 적합. GitFlow의 간소화 버전.
- 거버넌스 모델: 공유된 유지 보수 기여자
- 통합 병합: 원 개발자가 수행
- 통합 브랜치: develop
- 티켓을 시작할 때 티켓 추적기에서 티켓의 상태를 진행 중으로 갱신하고 티켓 작업 브랜치 생성 번호를 발급받는다.
- 티켓 브랜치를 만들 때는 develop 브랜치로부터 새로운 브랜치를 생성한다. [#티켓번호]를 브랜치 이름에 사용한다.
- 티켓 브랜치를 master 브랜치에 통합된 모든 변경사항을 적용해 최신 상태로 유지한다.
- 테스트를 통해 기본적인 오타/오류를 점검한다. (그 외 필요한 테스트를 포함)
- 작업이 끝나면 최종 커밋을 하며 Resolves #티켓번호를 적는다.
- 티켓 브랜치를 코드 호스팅 저장소에 push 한다.
- 티켓 추적기에서 티켓에 코멘트를 추가하여 작업 방식과 이유를 메모한다. 이를 통해 작업이 끝난 증명을 남긴다. 스크린샷도 추가할 수 있다.
- 티켓 브랜치를 최신 상태로 유지하고 티켓 브랜치 작업을 develop 브랜치에 병합한다. 충돌을 해결한 후 push 한다.
- 새 작업으로 인한 새로운 문제가 없으면 티켓을 닫을 수 있다.
- 마지막으로 로컬과 원격의 티켓 브랜치를 삭제한다.
- 기본 워크플로우에 상호 검토 과정을 추가한 것.
- 자동화된 테스트가 아니라 상호 검토 테스트를 하는 이유는 8장에서 설명함.
- 거버넌스 모델: 공유된 유지 보수 기여자
- 통합 병합: 검토자가 수행
- 통합 브랜치: develop
- 티켓을 시작하면 티켓 추적기에서 티켓의 상태를 진행 중으로 갱신한다.
- develop 브랜치 로컬 사본에 새로운 브랜치를 생성한다.
- 작업을 하면서 리베이스를 통해 해당 브랜치를 최신 상태로 유지한다. 모든 커밋 메시지는 [#티켓번호] 또는 Resolves #티켓번호를 넣는다.
- 기본 테스트를 진행한다.
- 작업 브랜치를 코드 호스팅 저장소에 push한다.
- 티켓 작업이 끝나면 develop 브랜치의 변경사항을 적용해 작업 브랜치를 최신으로 갱신하고 코드 호스팅 시스템에 올린다.
- 티켓의 설명에 따라 해당 작업을 검토한다.
- 티켓 브랜치의 작업을 develop 브랜치에 병합한다. 충돌이 없으면 브랜치를 중앙 저장소로 push한다.
- 성능 저하가 없다면 검토자는 티켓을 닫고 개발자에게 병합을 알린다. 개발자와 검토자는 브랜치 사본을 삭제할 수 있다. 해당 브랜치의 원격 사본은 검토자가 삭제해야 한다.
- 개발자를 믿지 않고, 메인 브랜치 병합을 QA팀이 수행.
- 거버넌스 모델: 공동 저장소 기여자
- 통합 병합: 검토자가 수행
- 통합 브랜치: develop 브랜치
- 티켓을 시작하면 티켓 추적기에서 상태를 진행중으로 갱신한다.
- develop 브랜치 로컷 사본에 사로운 브랜치를 생성한다.
- 티켓을 작업하면서 작업 브랜치를 리베이스를 통해 최신 상태로 유지한다.
- 기본 테스트를 진행한다.
- 티켓 작업이 끝나면 develop 브랜치의 변경사항을 적용해 작업 브랜치를 최신으로 갱신하고 저장소 사본에 push한다. 그 후 pull request 한다.
- 티켓 설명에 따라 작업을 검토한다.
- 저장소 진본에서 pull 요청을 승인한다.
- 성능 저하가 없다면 티켓을 닫는다.
- 릴리즈를 위해 공개 안정 버전과 개발자들의 불확실 버전으로 구분
- 공인된 커밋으로부터 master라는 이름의 새 브랜치를 생성
- 해당 공인 커밋에 버전번호를 태그로 단다.
- 업데이트된 저장소를 중앙 호스팅 시스템에 push한다.
- 소프트웨어를 공식 릴리즈하면 두 가지 다른 작업을 동시에 해야 하는 상황이 된다. 라이브 코드의 안정성을 감시하고, 개발을 지속하는 일이다.
- 1주일 단위로 설정, 테스트, 출시하는 루틴이 쓸만하다.
- 출시일에서 하루 이틀 후에 최신 기능과 수정사항 공지를 개발 블로그에 올린다.
- 배포한 코드에 오류가 있을 때 다음 버전 이전에 수정해야 할 수 있다. 배포 주기를 벗어난 패치가 핫픽스다.
- 핫픽스는 develop이 아니라 master 브랜치에서 시작한다.
- 소프트웨어 외의 작업에도 Git을 활용할 수 있다.