Skip to content

Instantly share code, notes, and snippets.

@bakyeono
Last active December 9, 2023 09:01
Show Gist options
  • Save bakyeono/938972ed416df06f7f55ead6cbc6959a to your computer and use it in GitHub Desktop.
Save bakyeono/938972ed416df06f7f55ead6cbc6959a to your computer and use it in GitHub Desktop.

《팀을 위한 Git》 독서 노트

책은 3개 부로 구성

  • 1부 워크플로우 작성하기(1장 - 4장)
  • 2부 워크플로우에 명령어 적용하기(5장 - 9장)
  • 3부 Git 호스팅(10장 - 12장)
  • 부록: 몇몇 Git 관련 도구 사용법

1장 팀으로 일하기

1.1 팀원들

  • "끝을 생각하며 시작하라": 어떤 문제를 해결할 것인가? (사용자 경험에서 시작)
  • 테스트 주도 개발: 테스트를 먼저 작성할 때의 장점(문제 해결 확인, 소프트웨어 동작 결과를 미리 이해)
  • 테스트 과정에는 보안 검수 과정을 포함
  • 배포 환경 구축
  • 오픈소스 개발 커뮤니티와의 관계
  • 솔루션 구현 계획을 결정하고 문서화, 공유
  • 개별 팀원들이 능동적인 합의 지향 개발할 수 있는 환경 조성

1.2 사고 전략

  • 팀원마다 선호하는 작업 방식이 다르다: 개별 팀원을 생산적으로 만들 전략 공유
  • 사고의 세 차원(창조적 사고, 이해하는 사고, 결정하는 사고) + 개인의 정신
  • 개인이 특정한 사고 전략을 고집하면 팀이 무너질 위험이 있음.

창조적 사고

  • 상상력, 재구성, 브레인스토밍, 통찰력, 도전, 집중 등의 특성
  • 예상치 못한 문제 해결 방법을 찾아냄
  • 워크플로우를 개선하고 큰 문제를 해결

이해하는 사고

  • 상황 파악(조사, 정보수집), 명료한 인식, 구조화(정리), 듣는 자세, 공감, 표현
  • 정보에 대한 이해 / 사람에 대한 이해
  • 분석적인 사고
  • 패턴을 인식, 상황을 명확하게 인식하고 설명

결정하는 사고

  • 핵심 파악, 결정력, 결론 입증, 경험, 가치 기반 결정, 직감
  • 최선의 해법을 찾아내는 능력
  • 인내심 부족

1.3 팀 회의

  • 시작-진행-끝 시퀀스(시작, 진행, 결론): 회의할 때는 먼저 무엇을 할 것인지 정하고, 진행하고, 결정한 것을 정리

1.3.1 시작

  • 공동 시작 회의에는 모든 팀원을 참가(대면)시키는 것이 좋다.

1.3.2 진척 상황 추적

  • 정기적인 팀 회의
  • 일주일 단위의 짧은 스프린트의 장점: 문제를 숨기기 어려움
  • 일정 회의(스탠드업 회의): 매주 여러 차례 같은 시간에 진행. '약속'을 결과물로 내야 함. "다음 일정 회의까지 제출할 부분이 무엇인가?"
  • 프로젝트 딥다이브 회의
  • 스프린트 데모: 매주 한 번 작업 현황 공유
  • 스프린트 회고: 스프린트가 끝날 때마다 팀을 모아 작업 과정 논의
  • 전사적 스탠드업
  • 일대일: 추첨을 통해 전화 통화 등으로 편하게 자유 주제로 대화

1.3.3 공감대 구축하기

  • 같이 일하는 사람들에 대한 충분한 관심
  • 이야기 수집: 사람들에게 무슨 일이 있는지 묻기
  • 의식적으로 듣기: 딴짓 없이 들어야 함. 말을 끊지도 말 것.
  • 되묻기: 이전에 들은 이야기의 최신 상황 물어보기

1.3.4 결과와 회고

  • 결과 회의와 회고 회의
  • 프로젝트의 잘 된 점과 개선할 점이 무엇인지 토론
  • 부끄러워하거나 비난하지 않고 잘 안 된 점을 말할 수 있어야 함

1.4 팀 작업 관련 Git 용어

  • 로컬 사본
  • 코드 호스팅, GitHub
  • clone(fork)
  • upstream: 제품의 공식 버전
  • pull: fetch + merge
  • push

1.5 요약

  • 서로 신뢰하고 공감하는 팀
  • 상황에 따라 적절한 사고 전략이 다르다
  • 자신의 작업을 투명하게 공개
  • 중요한 시기에 이해당사자를 팀에 포함

2장 지시통제

  • 저자의 권리와 프로젝트 저장소 관리자의 책임

2.1 프로젝트 거버넌스

2.1.1 저작권과 저작권 동의서

  • 저작권: 특정한 산물을 사용하고 배포할 수 있는 배타적 권리. 양도가능.
  • 직무저작물: 노동자(또는 프리랜서)가 돈받고 고용주에게 만들어 준 것.
  • 구현물에 대해서만 저작권을 가질 수 있다. 아이디어는 저작권 안 된다.
  • 오픈소스에 참여할 때 고용 문제가 얽혀 있으면 저작권 문제가 복잡해질 수 있다.
  • 기업들의 저작권 동의서 문제: 오픈소스 정신에 위배됨

2.1.2 배포 라이선스

  • 배포 라이선스: 프로젝트를 어떻게 사용하면 되고 어떻게 사용하면 안 되는지 명확히 하는 것.
  • MIT 라이선스
  • 아파치 라이선스
  • GPL
  • CCL

2.1.3 리더쉽 모델

  • 자비로운 종신독재자(BDFL): 리더가 모든 최정 결정 권한을 가짐.
  • 합의 기반, 리더 승인: 가장 능동적인 커뮤니티 구성원들이 적절한 솔루션을 찾도록 독려. 승인된 이슈는 RTBC로 표시됨.
  • 기술 검토진 또는 프로젝트 관리 위원회

2.1.4 행동 수칙

  • 커뮤니티가 잘 굴러가도록 하는 규칙을 정해서
  • 프로젝트 지원 사이트에 행동 수칙 문서를 추가.

2.2 접근 모델

  • Git은 작업자들이 중앙 저장소에 종속되어 일하는 것이 아니라, 독립적으로 개별 로컬 사본에서 작업한다.
  • MBTI로 보면: Git은 INTP, Subversion은 ESFJ다.
  • Git에는 접근을 통제하는 기능이 없다. 별도의 로그인 기능을 통해 제한.
  • 작업자는 Git 호스팅에 수정 권한을 갖거나, pull 요청을 통해 기여.
  • 다음으로 세 가지 유명한 접근 모델을 다룬다.

2.2.1 분산 기여 모델

  • 각 작업자는 diff로 패치를 생성하여 다른 개발자들에게 메일을 보낸다.
  • 메일을 받은 개발자는 로컬 소스코드에 patch 명령어로 패치를 적용하고, 수정사항을 검토한다.
  • 코드 공유를 메일로 하기 때문에 갱신 전에 최대한 꼼꼼한 작업을 위해 노력하게 되고, 리뷰어들이 검토한 내용만이 서로 병합된다.
  • 최근의 대부분 프로젝트에는 별로 적합하지 않은 방식이다.
  • bitsect, rebase 같은 명령어가 왜 필요한지 이해할 수 있는 모델.

2.2.2 공동 기여 저장소 모델

  • "업스트림" 프로젝트가 주 프로젝트가 됨
  • 개별 기여자는 그 프로젝트를 clone, fork하여 코드 호스팅 시스템 내 자신의 저장소에 생성
  • 기여자들은 복사본을 수정한 후 수정 사항을 merge 요청하거나 pull 요청 하는 방식으로 제출.
  • 다수 기여자가 참여하는 오픈소스 프로젝트에서 많이 사용되는 모델.
  • GitHub를 통해 유명해진 모델.
  • GitHub를 통한 기여 방법 자세한 설명 필요 (p59)

2.2.3 공유된 유지보수 모델

  • 내부 팀(비공개 팀), 1인 팀이 가장 일반적으로 사용하는 권한 모델.
  • 팀원 간의 신뢰를 전제: "누구든 코드를 메인 프로젝트 브랜치에 커밋할 때는 먼저 검토를 할 것이다."
  • 하나의 공유 저장소가 있고, 모든 사람은 그 저장소에 쓰기 권한을 공유한다.
  • Git 자체에는 승인 기능이 없다. 저장소 쓰기 권한 허용/거부는 다른 시스템 (Git 호스팅 플랫폼 또는 SSH 계정)에 의존한다.
  • Git에는 특정 브랜치를 수정하지 못하게 고정하는 기능도 없다. 테스트 없이 수정사항을 커밋하지 않게 합의하는 수밖에 없다. Bitbucket, GitLab은 브랜치별 접근 제한을 지원한다.

2.2.4 커스텀 접근 모델

2.3 요약

3장 브랜치 전략

3.1 브랜치 이해하기

  • 커밋은 부모를 참조하는 방식으로 서로 연결되어 있다.
  • 브랜치는 특정 커밋에 대한 이름 있는 포인터.
  • 커밋은 생성된 로컬 영역에 속하고, 생성한 사람만의 것이다. 커밋하면 자동으로 업로드되는 중앙화된 버전 관리 모델과의 차이.
  • 브랜치 네이밍 충돌을 방지하기 위한 규약이 필요함.
  • 일반적인 규약에는 장기 공개 브랜치와 단기 비공개 브랜치가 있다. 장기 브랜치는 여러 개발자가 기여한 코드의 중심점이 되고, 단기 브랜치는 실험을 위한 샌드박스 구실을 한다.
  • 브랜치를 공유한 이후에는 다른 사람도 그 브랜치를 수정해서 병합 충돌이 있을 수 있다.

3.2 규약 선택하기

  • 규약이란 작업을 보통 어떤 식으로 할지에 대한 합의된 표준
  • 규약을 문서화하면 새로운 참여자에게 도움이 됨
  • 적절한 브랜치 전략을 선택하려면 팀원들이 원하는 작업 릴리스 방식에 관해 대화해야 한다.

3.3 규약

  • 일반적인 두 가지 접근법: 항상 통합, 완료된 작업을 모아 한 번에 릴리즈

3.3.1 메인라인 브랜치 개발

  • 개발자들은 검토 완료한 작업을 하나의 중앙 브랜치에 지속적으로 커밋.
  • 중앙 브랜치는 항상 배포 준비 상태로 유지.
  • 자동 빌드 과정을 사용하는 팀이 하나의 작업 브랜치로 일하는 경우가 많다. (연속 통합, 연속 전달, 연속 배포)
장점
  • 브랜치 수가 적어 혼란이 적다.
  • 코드 베이스에 추가되는 커밋 분량이 비교적 적어 문제 해결이 쉽다.
  • 긴급 수정이 필요한 경우가 적다.
단점
  • 테스트 환경이 갖춰지지 않을 경우 위험하다.
  • 배포는 웹사이트의 경우에 더 적합하다. 최종사용자가 매번 패치를 받게 하는 경우 불편하다.
  • 플래그를 사용해 코드를 숨길 경우 삭제되지 않은 쓰레기 코드가 쌓일 우려가 있다.

3.3.2 기능별 브랜치 배포 (GitHub Flow)

  • 기능 브랜치와 통합 브랜치를 추가
  • 새로운 모든 작업은 기능 브랜치에서 이루어짐
  • 기능 브랜치는 통합 브랜치에서 수정사항을 가져와 최신 상태를 유지
  • 기능 브랜치 하나하나는 하나의 온전한 아이디어를 담을 만큼의 크기로 한정
  • 소프트웨어를 릴리즈할 때는 빌드에 포함시킬 기능을 선택하여 새로운 통합 브랜치를 생성해 배포
장점
  • 메인라인 개발처럼 빠른 배포가 가능
  • 메인라인 개발과 달리, 선택적인 빌드 단계가 있다
단점
  • 기능 브랜치에 있는 코드가 마스터에 추가되지 않으면 계속 추가로 유지보수하여 최신 상태로 유지해야 한다.
  • 의미 있는 브랜치 이름이라고 해도 새로 참여하는 사람은 파악하기 힘들다.
  • 마스터에 추가된 오래된 브랜치를 삭제하는 관리 업무가 추가 발생

3.3.3 상태 브랜칭 (GitLab Flow)

  • 브랜치 네이밍 규약을 통해 어떤 환경(개발/준비/출시)을 위한 커밋인지 명시
  • Git 프로젝트의 브랜치 네이밍 규약: maint(최신 안정 릴리즈 버전), master(다음 릴리즈에 추가될 커밋), next(master에 포함되기 전, 안정성 테스트 대상), pu(업데이트 제안. 통합 준비를 마치지 못한 커밋을 포함)
장점
  • 브랜치 이름으로 구체적 작업 상황이 설명됨
  • 작업을 어느 브랜치에 병합해야 하는지 쉽게 파악 가능
단점
  • 이름이 아무리 구체적이어도 모호성이 남을 수 있다
  • 브랜치 이름이 매우 구체적이어서 일관성을 유지하기 어렵다

3.3.4 정기 배포 (GitFlow)

  • 배포가 자동화되지 않고, 때때로 배포해야 하는 경우. (타인이 배포 과정을 통제하는 상황)
  • 하나의 브랜치 develop에서 출발
  • 개발자들은 develop에서 갈라지는 브랜치를 생성하고 기능을 추가
  • 티켓을 통해 이슈를 설명하고, 브랜치의 이름은 티켓 이름으로 붙임.
  • 기능 동결 상황에서는 개발 브랜치에서 새로운 브랜치(release)를 생성. 이 브랜치에는 버그 수정 커밋만을 허용.
  • 기능 동결 후에 추가로 개발되는 기능은 여전히 develop 브랜치에 커밋. 버그 수정은 release에서 이뤄진 후 develop에 병합.
  • release에서 모든 버그가 수정되면 새로운 브랜치 master에 커밋. 소프트웨어 버전을 태그.
  • 핫픽스는 제품 브랜치(master)에서 분기해서 만든다. 이후 develop에 병합.
장점
  • 대규모 테스트 기반이 필요하지 않다
  • 일반적인 소프트웨어 개발 과정(개발, 품질 보증, 완성)과 합치된다.
  • 규약을 충실히 지키면 작업을 시작할 브랜치를 쉽게 파악할 수 있다.
  • 정기적으로 버전업하는 소프트웨어(앱스토어의 앱 등. 즉, 수시로 업데이트하는 웹 사이트의 반대) 개발에 잘 어울린다.
단점
  • 소프트웨어 배포를 경험해보지 않은 개발자들이 익숙해지기 어렵다.
  • 잘못된 브랜치에서 작업을 시작할 경우 복구가 힘들다.
  • 연속 배포 모델보다 구식이다.

3.4 브랜치 업데이트하기

  • 브랜치들은 자동으로 최신 상태를 유지하지 않는다.
  • 브랜치를 업데이트하는 전략은 병합(merge)과 리베이스(rebase) 두 가지다.
  • 다른 저장소의 브랜치를 가져온 후 커밋을 추가하게 되면, 이 브랜치의 동기화 상태가 깨진다. fetch를 통해 원격의 수정사항을 업데이트할 수 있다.
  • pull은 fetch와 merge 또는 fetch와 rebase의 조합이다. (기본은 merge)
  • rebase는 브랜치의 히스토리를 수정하여 수정사항이 원래 있었던 것처럼 보이게 함
  • merge의 빨리감기 전략을 적용하면 결과가 rebase와 사실상 동일하다.
  • 두 브랜치에서 모두 수정사항이 발생한 경우 빨리감기 전략을 사용할 수 없다. 이 경우 merge는 수정사항을 각각 양방향에서 연결한다. 히스토리 그래프가 복잡해지는 문제가 있다.
  • 이 동기화 문제 때문에 프로젝트에 다시 합칠 작업은 추적 브랜치에서 하지 않는다. 추적 브랜치는 master, release 등의 장기적 브랜치가 되고, 작업 브랜치는 기능 브랜치나 티켓, 핫픽스 브랜치가 된다.
  • 병합 방식은 사용이 용이하고, 리베이스 방식은 히스토리 그래프가 보기 좋다.

3.5 요약

  • 브랜치 전략을 결정해야 한다.
  • 브랜치 병합 전략을 결정해야 한다.

4장 효과적인 워크플로우

4.1 워크플로우 개선하기

4.1.1 과정 문서화하기

  • Git의 사용법은 사용자에게 달려 있다. 여러 사람이 일관성있게 버전관리를 하도록 하려면 규칙/체크리스트를 문서화한다.
  • 워크플로우에는 프로젝트 매니저, 개발 사이트 URL, 배포 브랜치 등이 포함 (예제 4-1)
  • 공동 작업을 할 때는 코드 권한 분할 다이어그램을 그려보는 것도 좋다.

4.1.2 암호화된 결정 문서화하기

  • 이슈 추적을 위해 티켓 시스템(중앙화된 이슈 추적기), 화이트보드/포스트잇, 간단한 스프레드시트 등이 이용된다
  • 어떤 시스템을 사용하더라도, 쉽게 읽을 수 있고 검색 가능한 시스템을 이용해 특정 기능을 추가한 이유를 추적할 수 있게 기록해야 한다.
  • 특정 티켓 시스템을 이용하면 해당 시스템에 지나치게 의존적이 될 수 있다.
  • 여러 Git 호스팅 플랫폼이 티켓 시스템을 추가로 제공한다.

4.2 티켓 진행

  • 마감기한이 없는 내부 프로젝트라도 작업을 짧은 시간 단위로 쪼개는 것이 좋다. (1주 단위 스프린트를 추천) 임의의 마감기한은 작업 진척의 동기가 된다.
  • 마감된 작업의 데모 시연을 하는 것도 좋다. 데모 시연에는 Hangout, GoToMeeting 등이 편리하다.
  • 티켓 상태의 분류: 나중 작업(진행하면 안된다), 작업 준비 완료, 진행 중, 완료
  • 티켓 상태 분류를 너무 많이 만들어서는 안 된다. 시스템이 복잡할수록 개발자들의 판단비용/소통비용이 증가한다.
  • 대화가 중요하다: 작업 완료에 방해가 되는 것은 무엇인지, 실제 어떤 작업을 정확히 하고 있는지 등.

4.3 기본 워크플로우

  • 기본 워크플로우: 1-2인의 작은 팀에 적합. GitFlow의 간소화 버전.
주요 특성
  • 거버넌스 모델: 공유된 유지 보수 기여자
  • 통합 병합: 원 개발자가 수행
  • 통합 브랜치: develop
과정
  1. 티켓을 시작할 때 티켓 추적기에서 티켓의 상태를 진행 중으로 갱신하고 티켓 작업 브랜치 생성 번호를 발급받는다.
  2. 티켓 브랜치를 만들 때는 develop 브랜치로부터 새로운 브랜치를 생성한다. [#티켓번호]를 브랜치 이름에 사용한다.
  3. 티켓 브랜치를 master 브랜치에 통합된 모든 변경사항을 적용해 최신 상태로 유지한다.
  4. 테스트를 통해 기본적인 오타/오류를 점검한다. (그 외 필요한 테스트를 포함)
  5. 작업이 끝나면 최종 커밋을 하며 Resolves #티켓번호를 적는다.
  6. 티켓 브랜치를 코드 호스팅 저장소에 push 한다.
  7. 티켓 추적기에서 티켓에 코멘트를 추가하여 작업 방식과 이유를 메모한다. 이를 통해 작업이 끝난 증명을 남긴다. 스크린샷도 추가할 수 있다.
  8. 티켓 브랜치를 최신 상태로 유지하고 티켓 브랜치 작업을 develop 브랜치에 병합한다. 충돌을 해결한 후 push 한다.
  9. 새 작업으로 인한 새로운 문제가 없으면 티켓을 닫을 수 있다.
  10. 마지막으로 로컬과 원격의 티켓 브랜치를 삭제한다.

4.3.1 신뢰하는 개발자들과 상호 검토

  • 기본 워크플로우에 상호 검토 과정을 추가한 것.
  • 자동화된 테스트가 아니라 상호 검토 테스트를 하는 이유는 8장에서 설명함.
특징
  • 거버넌스 모델: 공유된 유지 보수 기여자
  • 통합 병합: 검토자가 수행
  • 통합 브랜치: develop
과정
  1. 티켓을 시작하면 티켓 추적기에서 티켓의 상태를 진행 중으로 갱신한다.
  2. develop 브랜치 로컬 사본에 새로운 브랜치를 생성한다.
  3. 작업을 하면서 리베이스를 통해 해당 브랜치를 최신 상태로 유지한다. 모든 커밋 메시지는 [#티켓번호] 또는 Resolves #티켓번호를 넣는다.
  4. 기본 테스트를 진행한다.
  5. 작업 브랜치를 코드 호스팅 저장소에 push한다.
  6. 티켓 작업이 끝나면 develop 브랜치의 변경사항을 적용해 작업 브랜치를 최신으로 갱신하고 코드 호스팅 시스템에 올린다.
수동 테스트 과정
  1. 티켓의 설명에 따라 해당 작업을 검토한다.
  2. 티켓 브랜치의 작업을 develop 브랜치에 병합한다. 충돌이 없으면 브랜치를 중앙 저장소로 push한다.
  3. 성능 저하가 없다면 검토자는 티켓을 닫고 개발자에게 병합을 알린다. 개발자와 검토자는 브랜치 사본을 삭제할 수 있다. 해당 브랜치의 원격 사본은 검토자가 삭제해야 한다.

4.3.2 믿을 수 없는 개발자들과 QA 게이트키퍼

  • 개발자를 믿지 않고, 메인 브랜치 병합을 QA팀이 수행.
특징
  • 거버넌스 모델: 공동 저장소 기여자
  • 통합 병합: 검토자가 수행
  • 통합 브랜치: develop 브랜치
과정
  1. 티켓을 시작하면 티켓 추적기에서 상태를 진행중으로 갱신한다.
  2. develop 브랜치 로컷 사본에 사로운 브랜치를 생성한다.
  3. 티켓을 작업하면서 작업 브랜치를 리베이스를 통해 최신 상태로 유지한다.
  4. 기본 테스트를 진행한다.
  5. 티켓 작업이 끝나면 develop 브랜치의 변경사항을 적용해 작업 브랜치를 최신으로 갱신하고 저장소 사본에 push한다. 그 후 pull request 한다.
검토 과정
  1. 티켓 설명에 따라 작업을 검토한다.
  2. 저장소 진본에서 pull 요청을 승인한다.
  3. 성능 저하가 없다면 티켓을 닫는다.

4.4 일정에 따라 소프트웨어 릴리즈하기

4.4.1 안전화 릴리즈 버전 출시하기

  • 릴리즈를 위해 공개 안정 버전과 개발자들의 불확실 버전으로 구분
과정
  1. 공인된 커밋으로부터 master라는 이름의 새 브랜치를 생성
  2. 해당 공인 커밋에 버전번호를 태그로 단다.
  3. 업데이트된 저장소를 중앙 호스팅 시스템에 push한다.

4.4.2 지속적 개발

  • 소프트웨어를 공식 릴리즈하면 두 가지 다른 작업을 동시에 해야 하는 상황이 된다. 라이브 코드의 안정성을 감시하고, 개발을 지속하는 일이다.
  • 1주일 단위로 설정, 테스트, 출시하는 루틴이 쓸만하다.
  • 출시일에서 하루 이틀 후에 최신 기능과 수정사항 공지를 개발 블로그에 올린다.

4.4.3 출시 후 핫픽스

  • 배포한 코드에 오류가 있을 때 다음 버전 이전에 수정해야 할 수 있다. 배포 주기를 벗어난 패치가 핫픽스다.
  • 핫픽스는 develop이 아니라 master 브랜치에서 시작한다.

4.5 소프트웨어 이외 프로젝트 협업

  • 소프트웨어 외의 작업에도 Git을 활용할 수 있다.

4.6 요약

5장 1인 팀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment