13 min read

[책 소개] 토미의 Git with 소스트리

[책 소개] 토미의 Git with 소스트리

[책 구매 링크]


목 차

1. 페이지 소개

2. 이 책의 대상 독자

3. 목차

4. 샘플 챕터(리베이스)

5. 책 구매 링크


1. 페이지 소개

이 페이지에서는 책 내용 중 1. 이 책의 대상 독자, 2. 목차, 3. 샘플 챕터 미리 보기를 제공합니다. Full 버전의 미리보기를 보고 싶으신 분은 토미의 Git with 소스트리 (미리보기) 를 다운로드 해서 보시기 바랍니다.

토미의 Git with 소스트리 (미리보기).pdf

2. 이 책의 대상 독자

이 책은 다음에 해당하는 분들을 위해 쓰여졌습니다.

  1. Git을 처음 접하시는 분
  2. Git을 제대로 알고 싶으신 분
    • 브랜치의 정의
    • 머지와 리베이스의 차이
    • 리셋과 리버트의 차이
    • 머지시 충돌 발생 이유와 해결 방법
    • 로컬저장소와 원격저장소
    • 원격저장소 추적 브랜치
    • 잃어버린 커밋 복원하기
  3. Git의 내부 구조를 알고 싶으신 분
    • Git이 어떤 객체로 구성돼 있는지
    • 저장소의 구조와 역할
    • 커밋의 해시는 어떻게 생성되는지
  4. Git을 더 잘 활용하고 싶으신 분
    • 레프로그
    • 리베이스를 사용한 풀 - 패치
    • 어멘드

3. 목차

Part I. Git 개념 이해하기 (Understanding Git Concepts)

1) 버전 관리 시스템의 역사 (History of Version Control System)

2) 델타 모델과 스냅샷 모델 (Delta Model and Snapshot Model)

3) Git의 객체 (Git Object Types)

4) 저장소 구조 (Repository Structure)

Part II. Git 사용 하기 (Using Git)

5) Git 사용 환경 (Environment for Git)

6) 브랜치 (Branch)

7) 변경 사항 되돌리기 (Undoing Changes)

8) 머지 (Merge)

9) 충돌처리 (Resolve Conflicts)

10) 리베이스 (Rebase)

11) 원격저장소 (Remote Repository)

12) 잃어버린 커밋 복원하기 (Reflog)

13) 팁 & 트릭 (Tip & Trick)

4. 샘플 챕터(리베이스)

“토미~ 안녕하세요?”

“네~ 안녕하세요?”

“다음 배포 때, 그동안 개발했던 자율주행 이동 수단을 포함해 나갈 수 있을까요?”

“자율주행 이동 수단이라면 택시, 버스, 배, 비행기, 자전거 말씀하시는 거죠?”

“네 맞아요. 모든 이동 수단을 사용할 수 있도록 서비스에 반영하고 싶어요. 가능할까요?”

“네~ 물론이죠.”

토미는 이동 수단별로 각기 다른 브랜치에서 개발했기 때문에 배포시 필요에 따라 모든 기능을 포함시키거나 일부만 포함시킬 수 있었습니다.

‘자~ 그럼 각 기능 브랜치를 배포할 브랜치에 머지 해볼까?’

‘짜잔~ 머지 완료! 이렇게 배포할 브랜치에 머지가 끝났으니 배포 준비 완료됐네?’

‘역시! 나 토미야! ᄏ’

토미는 스스로 대견해하며 만족스러운 미소를 띠었습니다. 하지만 이내 한 가지가 눈에 들어 왔습니다.

‘가만있자! 이거 기능적으로는 문제가 없는데, 여러 브랜치가 하나의 브랜치에 머지되니 히스토리가 복잡해 보이네. 이걸 개선할 수 있는 방법은 없을까?’

토미는 성공적으로 각 기능을 배포 브랜치에 머지 했지만, 머지된 후 Git의 커밋 히스토리가 마음에 들지 않았습니다.

‘아… 이거 보면 볼수록 복잡해 보인다. 정리하고 싶은데, 이것도 무슨 방법이 있겠지? 어떤 방법이 있는지 한번 알아봐야겠다.’

10.1 개요

챕터 8에서 브랜치를 합치는 방법 중 하나인 머지에 대해 살펴보았습니다. 때때로 브랜치를 합칠 때 머지 대신 다른 방법을 사용해야할 때가 있습니다. 이번 챕터에서는 리베이스에 대해 살펴보겠습니다. 앞에서 토미가 겪었던 상황을 예를들어 보겠습니다.

아래 [그림 10-1]과 같이 머지 시킬 브랜치(develop)와 이 브랜치에 여러 기능을 포함시키기 위해 머지할 FeatureA, FeatureB, FeatureC 세 개의 브랜치가 있습니다.

[그림 10-1] develop에 머지 할 세개의 Feature 브랜치

FeatureA, FeatureB, FeatureC 브랜치를 각각 순서대로 develop 브랜치에 머지시키면 Git 의 커밋 히스토리는 [그림 10-2]와 같은 모습이 됩니다.

[그림 10-2] develop에 세 개의 Feature 브랜치를 머지한 후 커밋 히스토리

develop 브랜치에는 FeatureA, FeatureB, FeatureC 각 브랜치의 변경사항이 반영된 상태입니다. 그래서 기능상으로는 문제가 없습니다. 하지만 히스토리가 조금 복잡해 보입니다. 만약 develop에 머지된 브랜치가 3개가 아니라 5개 혹은 10개라면 히스토리는 훨씬 더 복 잡하게 보일 것입니다.

이런 상황에서 머지대신 리베이스를 사용하면 아래 [그림 10-3]과 같이 브랜치를 머지커밋 생성없이 일렬로 된 형태로 브랜치를 합칠 수 있어서 Git의 커밋 히스토리를 간결하게 관리 할 수 있습니다.

[그림 10-3] 세 개의 Feature 브랜치를 develop 브랜치에 리베이스로 반영 후 커밋 히스토리

이번 챕터에서는 이 리베이스에 대해 알아 보겠습니다.

10.2 리베이스란?

일반적으로 브랜치는 브랜치의 시작점이 되는 base(부모)가 존재 합니다. 리베이스는 브랜치의 base를 변경해 브랜치를 합치는 방법입니다.

[그림 10-4] 리베이스 전/후 커밋 히스토리

위 [그림 10-4]의 왼쪽 리베이스 전 그림에서 Feature 브랜치의 base는 C1 커밋입니다. Feature를 develop와 합치기 위해 리베이스를 수행합니다. 리베이스를 하면 [그림 10-5]의 오른쪽 그림 같이 Feature의 base가 C1에서 C7로 변경되고 두 브랜치가 일렬로된 형태로 합쳐집니다.

10.3 리베이스의 동작

리베이스를 수행하면 내부적으로는 각 커밋별로 패치를 생성해 순서대로 다른 브랜치에 적용합니다. 리베이스 후 마치 커밋이 원본 브랜치에서 다른 브랜치로 base만 바뀌어서 이동 한 것 처럼 보이지만 실제로는 같은 메시지와 변경사항을 포함한 새로운 커밋이 생성돼 재적용된 것입니다.

[그림 10-5] 리베이스의 동작 과정

위 [그림 10-5]는 Feature 브랜치를 develop 에 리베이스하는 과정입니다. Feature 브랜치를 develop에 리베이스 해서 C2, C3, C4 커밋이 develop 에 적용됐습니다. 여기서 주의깊게 보실 것은 C2, C3, C4 커밋이 develop에 그대로 옮겨진 것이 아니라 각각 C2’, C3’, C4’ 로 변경됐다는 것입니다.

앞서 설명드린바와 같이 리베이스를 수행하면 커밋이 그대로 이동하는 것이 아니라 새로 생성됩니다. 그렇기 때문에 리베이스로 생성된 커밋은 원본 커밋과 해시가 다른 커밋이 됩니다. 커밋의 해시가 다르기 때문에 Git이 봤을때 C2, C3, C4는 C2’, C3’, C4’와 각각 다른 커밋 입니다. 커밋을 새로 생성하면 왜 다른 커밋이 되는걸까요? 커밋 메시지나, 커밋 작성자 등 정보는 동일한데 말이죠?

앞의 챕터3.6에서 커밋의 아이디인 SHA-1가 어떻게 만들어지는지 살펴봤었습니다. Git은 커밋을 SHA-1로 구분하는데 커밋의 SHA-1을 생성하는데 사용하는 요소에 커밋 생성시간과 부모 커밋이 포함된다고 말씀드렸습니다. 위 [그림 10-5] 에서는 리베이스를 수행해서 커밋이 재생성됐는데 커밋을 재생성 했기 때문에 커밋 생성시간이 변경 되었고, base가 변경 됐기 때문에 C2, C3, C4 커밋의 부모 커밋도 각각 C1, C2, C3에서 C7, C2’, C3’ 으로 바뀌었습니다. 리베이스 되면서 커밋의 두 가지 정보가 변경 됐기 때문에 리베이스 된 커밋은 이전 커밋과 SHA-1가 다른 완전히 다른 커밋입니다.

10.4 리베이스시 주의사항

리베이스시 원본 커밋이 버려지고 새로운 커밋이 생성되기 때문에 리베이스는 일반적으로 개인저장소에서만 수행해야 합니다. 만약 다른 팀원과 함께 사용하는 공용저장소의 커밋을 리베이스하면 공용저장소의 커밋 히스토리가 꼬이게 됩니다.

A라는 사람은 리베이스 전의 커밋에 이어서 커밋을 생성하고, B라는 사람은 리베이스 후의 커밋에 이어서 작업을 했다면 나중에 두 커밋 히스토리는 일반적인 방법으로는 합칠 수 없는 상태가 돼 버립니다. 그렇기 때문에 리베이스는 공용저장소에 푸시된 적이 없는 커밋에만 사용해야 합니다. 그렇다면 공용저장소에 푸시된 커밋은 절대 리베이스를 하면 안되는걸 까요?

꼭 그렇지는 않습니다. 여럿이 협업을 하다보면 공용저장소의 내용을 리베이스 하고 싶을 때 가 생기는데 그때는 먼저 동료들에게 리베이스할 브랜치에 아직 푸시하지 않은 내용이 있다면 푸시해 달라고 요청합니다. 그 후 리베이스를 완료하기 전에 그 브랜치에 새로운 커밋을 푸시하지 말라고 요청합니다. 이렇게 서로 합의를 한 후 리베이스를 진행하고, 리베이스가 완료되면 공용저장소에 푸시를 하고 동료들에게 리베이스가 완료됐다고 상황을 공유합니 다. 이 후 다른 동료들은 해당 브랜치를 로컬에서 삭제 후 다시 체크아웃해서 사용하면 됩니다.

비록 이렇게 공용저장소에 반영된 커밋을 리베이스 할 수 있지만, 특수한 상황을 제외하고 리베이스는 공용저장소에 푸시된 적이 없는 커밋에 대해서만 수행해야 합니다.

10.5 머지와 리베이스의 차이점

머지와 리베이스 두 명령 모두 결국 브랜치를 합치는 일을 하는 것인데, 두 명령어는 어떤 차이가 있을까요?

첫째, 머지는 커밋 히스토리를 변경하지 않습니다. Fast Forward 머지인 경우 커밋을 변경 하거나 새로운 커밋을 추가하지 않습니다. Three Way 머지는 새로운 커밋을 추가하지만 이전 커밋을 변경하지는 않기 때문에 언제든 예전 커밋의 상태로 돌아갈 수 있습니다. 반면 리베이스는 옛날 커밋을 버리고 새로운 커밋을 생성하기 때문에 일반적인 방법으로는 예전의 커밋으로 되돌아 갈 수 없습니다

둘째, 머지는 한번에 수행되는 명령입니다. 그래서 머지 중 충돌이 발생한 경우 한번의 처리로 충돌 해결이 가능합니다. 반면 리베이스는 리베이스 되는 커밋을 각각 재생성해 적용하기 때문에 리베이스시 충돌이 발생한 경우 충돌 처리를 여러번에 걸쳐 나눠서 처리해야 하는 상황이 발생할 수 있습니다.

셋째, Three Way 머지를 사용하는 경우 리베이스를 했을 때 보다 커밋 히스토리가 복잡합니다. 이 점이 보통 브랜치를 합칠 때 머지 대신 리베이스를 사용하는 가장 큰 이유입니다.

10.6 리베이스의 활용 (Interactive Rebase)

(이후 생략…)

5. 책 구매 링크



[책] 토미의 Git with 소스트리

Git을 제대로 알고 싶으신 분들께 추천드립니다.



[온라인 강의] 토미의 Git & Github

Git을 제대로 알고 싶으신 분들께 추천드립니다.