Git-flow 전략과 프로젝트 예시(feat. Kuring)
(포스팅 최초 작성) 2022.06.10
(포스팅 수정) 2024.08.29
- 커밋 내역 관리하는 방법 수정
✅ Kuring에서 사용하는 Git-flow 분석과 Git-flow에 대해서 공부하며, Kuring에서 내가 사용하는 커밋 규칙을 정리하고자 포스팅합니다.
🥕 목차 🥕
1. 우아한 형제들 Git-flow 전략에 대해서 알아보기
2. Kuring의 Git-flow 전략 분석 (소규모 팀에서의 Git-flow 전략)
3. Git-flow 전략을 개인 레포에 적용하고 연습해보기
4. git 충돌 해결 방법
✅ 1. 우아한 형제들 Git-flow 전략에 대해서 알아보기
우아한 형제들 기술 블로그를 참고하여 Git-flow 전략에 대해서 공부해 봅니다.
기술 블로그는 포스팅 최하단에 링크를 걸어두었습니다.
🟠 Git Repositiry 구성 살펴보기!
Repository는 Upstream Remote Repository(이하 Upstream Repository)와 Origin Remote Repository(Origin Repository), Local Repository로 구성됩니다.
Upstream Repository이란 모든 개발자들이 공유하는 저장소로 최신 소스코드가 저장되어 있는 원격 저장소입니다.
Origin Repository는 UpStream Repository를 Fork한 원격 개인 저장소 입니다. Local Repository는 내 컴퓨터에 저장되어 있는 개인 저장소 입니다.
위의 그림은 Git Repository 구성과 워크 플로우에 대해서 설명하고 있습니다. Local Repository에서 작업을 완료한 후 작업 브랜치를 Origin에 push합니다. 그리고 Github에서 Origin Repository에 Push한 브랜치를 merge하도록 PR을 생성하고 코드 리뷰를 거친 후 merge합니다. 다시 새로운 작업을 진행할 때, Local Repository에서 Upstream Repository를 Pull 합니다!
🟠 Git-flow 전략 살펴보기!
Git-flow를 사용했을 때 작업을 어떻게 하는지 살펴보기 전에 우선 Git-flow에 대해서 알아보도록 하겠습니다.
Git-flow에는 5가지 종류의 브랜치가 존재하빈다. 항상 유지되는 메인 브랜치들(main, develop)과 일정 기간 동안만 유지되는 보조 브랜치들(feature, release, hotfix)가 있습니다.
( * NOTE: master 브랜치의 이름은 main으로 변경되었습니다. )
👉 main: 제품으로 출시될 수 있는 브랜치
👉 develop: 다음 출시 버전을 개발하는 브랜치
👉 feature: 기능을 개발하는 브랜치
👉 release: 이번 출시 버전을 준비하는 브랜치
👉 hotfix: 출시 버전에서 발생할 버그를 수정하는 브랜치
🟠 Git-flow를 설명하는 그림
위 그림은 일반적인 개발 흐름으로 살펴보겠습니다. 처음에는 main 브랜치와 develop 브랜치가 존재합니다. 물론 develop 브랜치는 main 브랜치 안에서 시작한 브랜치입니다.
develop 브랜치에서는 상시로 버그를 수정한 커밋들이 추가됩니다. develop 브랜치에서는 상시로 수정한 코드가 추가됩니다. feature 브랜치는 언제나 develop 브랜치에서 시작합니다. 기능 추가 작업이 완료되었다면, feature 브랜치는 develop 브랜치로 PR을 통한 코드리뷰 이후 merge됩니다. develop브랜치는 이번 버전에 포함되는 모든 기능이 merge 되었다면 QA를 하기 위해서 develop 브랜치에서 release 브랜치를 생성합니다. QA를 진행하면서 발생한 버그들은 release 브랜치에 수정됩니다. QA를 무사히 통과하였다면 release 브랜치를 develop 브랜치와 main 브랜치로 merge합니다. 그리고 마지막으로 출시된 main 브랜치에서 버전 태그를 추가합니다.
🟠 rebase와 squash의 필요성에 대한 그림
rebase와 squash를 했을 때 얼마나 단순해 지는지 확인할 수 있습니다.
불필요한 커밋의 경우에는 코드리뷰를 도와주지도 못할 뿐더라, 그렇기에 하나로 합치는 것은 좋습니다. 물론 항상 합쳐야 하는 것은 아니지만, 분리되어 있는게 하나의 커밋을 낫다면 오히려 나눌 수도 있습니다. 그러나 대부분 이러한 경우는 작업을 상세하게 나누지 못한 경우가 많습니다.
✅ 2. Kuring의 Git-flow 전략 분석 (소규모 팀에서의 Git-flow 전략)
🟠 여기에서는 실제로 Kuring에서 어떻게 작업하는지 분석해 보도록 합시다.
Kuring에서는 Git-flow 전략을 적용하여, develop, main 브랜치를 두고 있습니다.
Kuring-app-ios 부분의 원격 레포지토리 부분입니다.
develop branch는 하나의 Upstream Remote Repository입니다.
Origin Remote Repository는 그렇다면 어떻게 될까요?
feature 부분입니다.
프로젝트에서 feature 개발을 진행한다면 프로젝트 팀에서 저희는
[feature/이름/내용] 이런식으로 브랜치를 분기하여서 사용하고 있습니다.
그리고 Origin Remote Repository에서 작업을 마치면 develop branch로 Pull Request를 열고 코드 리뷰를 요청합니다.
이후 코드 리뷰가 끝났다면 merge하고 해당 브랜치를 원격에서 delete하고 있습니다.
그렇지만 저는 프로젝트에서는 현재 작업 진행상황을 공유하고자 PR을 open하고 work in progress 레이블을 설정하여 둡니다.
PR을 통해 코드 리뷰를 요청할 때는 일정한 규칙이 있습니다.
저의 경우에는 작업 중에 PR을 open하고 wip를 Label을 달아두어서, 위에 창을 자주 활용하고 있습니다.
기본적인 틀은 지키고 하위에는 제가 작업하는 내용에 대한 사항을 적어두어서 이 부분만 확인하고 작업을 이어갑니다.
위에 창에 [DONE], [FIXME], [ISSUE], [확인할사항], [다음 작업] 등을 글로 기록하고 있습니다.
아래는 PR 내용 중 일부분입니다.
🟠 Kuring을 통해서 정립한 나의 commit 규칙
그동안 코드를 작성하면서 어떻게 할지 고민이 많았는데, 이제는 나름 확실히 정립하여 사용하고 있습니다.
아래에 그 예시가 있습니다.
이전에는 [삭제], [이슈] 등을 더 다양하게 사용하고 있었는데, 작업을 진행하면서 제게 가장 잘 맞는 규칙을 정립하여 사용하고자 합니다.
커밋 작성 내용은 다른 개발자가 보았을 때도 확실하게 인지할 수 있어야 합니다.
👉 [추가] 개발한 사항에 대해 커밋합니다.
👉 [수정] 주석 정리, 파일 삭제, 네이밍 변경 등을 커밋합니다.
👉 [기록] 이슈를 주석을 통해 기록하고 커밋합니다.
크게 3가지를 사용합니다. 경험상 아직까지는 이 세개가 가장 효율적이고 직관적으로 다가오는 것 같습니다.
이 외에 다른 개발자 분께서 작업하신 내용 중 채택하고자 하는 부분
👉 [버전] 버전을 커밋합니다.
그 외에 고민중인 커밋 규칙
👉 [리뷰] 코드 리뷰 변경 사항을 커밋합니다.
- 고민하는 이유는 [수정]으로도 충분히 사용 가능할 것 같고, 개발적인 추가사항이 있으면 [추가]와 [리뷰] 사이에서 충돌할 것 같습니다. 다른 방법으로는 '[리뷰] 1차 리뷰 후 변경 사항을 반영합니다.' 로 한 줄의 기록을 남길까 하는데, 이 부분도 결국은 [기록]에서 처리가 가능할 것 같습니다. '[수정] PR리뷰 - {내용}' 도 고려해 보았으나, 이 경우에는 PR리뷰 부분을 작성하지 않고 커밋을 올릴 수 있어서 이 경우에는 커밋 기록을 수정해야하는 문제가 발생해서 오히려 생산성이 떨어질 수 있습니다.
- 결론: [리뷰] 키워드는 사용하지 않습니다.
(사용 예시)
- [추가] notifications을 위한 테스트 코드를 추가합니다.
- [추가] bookmarkList의 UI구성을 완료하였습니다.
- [추가] bookmarkList에서 NoticeWebView 로직을 구현하였습니다.
- [수정] searchView의 engine의 access level을 수정합니다.
- [수정] 불필요한 코드 및 파일을 정리합니다.
- [수정] 사용하지 않는 스토리보드를 삭제합니다.
- [수정] UserDefaultsManager를 app에서 sdk로 이전하여 통합합니다.
- [기록] 토글링 이슈에 대한 FIXME를 기록합니다.
- [기록] 디자이너의 요청에 따른 UI변경 사항을 기록합니다.
- [기록] 1차 리뷰 완료
(2024.08.29 커밋관련 규칙 수정)
- 커밋 규칙을 수정
- 사유 깃 이슈 및 PR에 자동으로 기록이 남기도록 하여, 스쿼시 머지를 해도 커밋 단위로 히스토리 파악이 더 쉬움.
커밋 규칙에 따른 예시
이슈번호 331이라고 할 경우
- #331 필요하지 않은 주석 삭제
- #331 from combine to swift concurrency
3. Git-flow 전략을 개인 레포에 적용하고 연습해보기
해당 연습은 아래의 레포에서 진행합니다. 왜냐하면 앞으로 SwiftUI를 지속적으로 공부하고 업데이트 할 예정이기 때문에 현재로써 가장 적합한 레포라고 생각됩니다..
https://github.com/lgvv/SwiftUI
🟠 세팅방법 - 터미널을 사용하기 보단 소스트리를 활용합니다.
👉 1. develop branch 만들기
- 소스트리에서 develop이란 이름으로 새로운 브랜치를 만듭니다.
- 원격에 push합니다.
- 해당 레포에서 Settings - Code and automation - Branches에서 Default branch를 develop 브랜치로 변경합니다.
아래의 사진처럼 나타난다면 정상적으로 수행이 된 것입니다.
👉 2. develop 브랜치를 만들었다면 소스트리에서 수행할 작업에 대한 브랜치를 생성합니다.
- 소스트리에서 learning/git/flow 브랜치를 만듭니다.
- 실제 개발에서는 기능 개발이라면 { feature/이름/작업 }으로 하겠지만 저는 { 학습/주제/내용 } 으로 Git-flow를 사용합니다.
- 변경사항을 만든 후, 커밋을 생성합니다.
- 저는 README.md 파일을 수정하여 커밋 2개를 생성하였습니다.
👉 3. Origin Remote Repository에 push하고 PR을 생성합니다.
- 원격에서 PR을 오픈하고 코드 리뷰를 진행한 후 merge합니다. merge한 브랜치는 삭제합니다.
- merge이후 소스트리를 열어서 페치 후 히스토리를 확인합니다.
- 위와 같은 모습으로 바뀐 걸 확인할 수 있습니다.
- learning/combine/encoding-decoding은 8번 stash 예제를 위해 여기에 위치합니다. 나중에 다시 보아주세요.
👉 4. rebase에 대해서 알아보려고 합니다.
위의 작업 이후에 위와 같은 flow를 만들었습니다.
작업의 시간 순서는 rebaseA -> rebaseB -> develop 순서입니다.
여기서 이제 우리는 리베이스를 활용해서 브랜치를 예쁘게 바꿔봅시다.
- 우선 리베이스를 할 작업한 브랜치로 체크아웃합니다.
- 우리는 rebaseA 브랜치를 리베이스할 것이기 때문에 rebaseA로 체크아웃합니다.
- 이후에 rebaseA를 붙이고 싶은 장소(develop)를 우클릭하여 재배치를 클릭합니다.
- 아마 충돌이 없다면 재배치가 정상적으러 수행되어서 깔끔하게 브랜치가 합쳐질 것이다.
하지만 충돌이 있다면 아래의 그림처럼 되는데, 충돌 사항을 해결해보자!
- 충돌을 해결하려고 했는데, 결국은 develop 브랜치와 rebaseA가 같은 파일에서 수정을 가해서 발생한 문제였다. 따라서 develop 브랜치에서 작업한 rebaseA와 겹치는 부분을 삭제했다.
- rebase를 정상적으로 끝냈는데, develop보다 rebaseA가 더 앞서 있습니다. develop 브랜치를 rebaseA와 동일한 위치로 옮겨 주어야 합니다.
- 방법은 develop(부모) 브랜치로 체크아웃 한 다음에 rebaseA 브랜치를 metge rebaseA into develop을 수행하면 됩니다.
👉 5. 리베이스의 결과를 확인해봅시다. 커밋이 훨씬 깔끔한 것을 확인할 수 있습니다!
👉 5. 원격 develop이 local develop 보다 앞서 있는 경우 해결하기
아래 그림과 같은 경우가 발생할 수 있다. 현재 Uncommitted changes가 되어 있는 이유는 rebase(재배치)를 하려고 했으나 충돌이 났기 때문이다.
- 우선 rebase를 통해 rebaseB와 로컬 develop을 합친다.
- 충돌을 해결하고 병합하였더니 위처럼 수정됩니다. rebase를 했기에 브랜치가 다수여도 깔끔하게 깃을 정리할 수 있습니다.
👉 6. Git-flow 전략에서 release 브랜치를 만들어서 확인해 봅니다.
- develop 브랜치를 다 만들고 release 브랜치를 생성하여 사용하는데, 문제가 있습니다.
- 그런데, QA도중 버그를 발견했습니다. 원격에 푸시했는데, 커밋에 오타가 있어서 revert후 다시 push했습니다.
👉 7. 태그를 설정하고 develop과 release를 세팅합니다.
👉 8. hotfix를 알아봅시다.
- 위의 사진처러 develop이랑 main을 올리고 devleop을 전부 마친 상황입니다. 그런데, 갑자기 hotfix를 해야할 일이 생겼습니다.
- hotfix를 해봅시다.
hotfix도 성공했습니다!
👉 8. stash를 알아봅시다.
- develop 시점을 바꾸면, develop이 uncommitted 상태라서 stash를 진행해야 합니다.
- 소스트리 우측 상단에 있는 스태시를 클릭해서 스태시 해 둡니다. (치워둔다.)
- 그 다음에 재배치하면 끝!
- 그리고 스태시 한 정보를 불러와 줍니다.
스태시 적용 완료!
사실 내가 조금 실수해서, stash만 했어야 하는데 develop으로 그냥 merge했다,,
크게 문제가 되지 않아서 유지하는데 다음부터는 조심하자.
4. git 충돌 해결 방법
(2022.06.13) [1.2.2] 버전에서 SwiftUI로 코드를 전환하면서 발생한 문제.
아주 힘든 문제를 만났다. 우선 왜 스토리보드를 사용하지 않는지 절실히 느낀 시간이었다. 스토리보드는 조금만 움직여도 변화가 생기는데 변화된 부분이 깃에 반영되고, 이로 인해서 충돌을 잡아야하는 문제가 발생했다.
이번에 같이 작업하시는 분께서 많은 도움을 주셨는데, 대부분의 문제는 git에서 해결이 가능하다고 한다.
PR을 통해 코드리뷰를 마친 후 Approved되었다면 merge가 가능하게 초록색 버튼이 활성화 되는데, 불가능한 경우애는 conflict난 부분을 보여주고 이를 해결하라고 한다.
일단 기본적으로는 git에서 해결 가능하고, git에서 충돌나는 파일을 찾아서 어떤 브랜치의 파일을 선택할건지 고른 후 다른 브랜치의 작업물을 지우면 된다.
그런데 만약, 스토리보드처럼 너무 복잡하게 꼬여서 도저히 찾기가 어려울 때는 어떻게 해야할까??
이 상황에서는 내가 작업한 스토리보드 파일을 날리고 develop 브랜치의 스토리보드 파일을 선택해서 merge했다.
그 이후 함께 코드리뷰를 진행하면서 develop 브랜치를 함께 보면서 수정사항을 다시 작성해 push해 이런 방식으로 조정했다!!
같이 작업하시는 분 덕분에 엄청나게 속도가 붙고 개발에 재미를 더 재미를 붙이고 있다. 그리고 무엇보다도 이제는 UIKit + RxSwift보다는 SwiftUI + Combine을 1순위로 사용하는데, 코드가 간결해지고 너무나도 좋다!
여기까지 Kuring에서 적용되는 Git-flow를 전부 알아보았습니다. 앞으로 Git에도 오너십을 가져가 봅시다.
부족한 부분이나 잘못된 점은 언제든지 댓글을 남겨주세요!
(참고)
https://techblog.woowahan.com/2553/
'project > Kuring(공지알림)' 카테고리의 다른 글
iOS SPM No Such Module (0) | 2022.08.24 |
---|---|
[iOS] SPM 프로젝트 이름 변경시 오류 (0) | 2022.08.24 |
[SwiftUI] UIActivityViewController를 SwiftUI로 (0) | 2022.05.31 |
[SwiftUI] List accessory (feat. disclosure indicator) (0) | 2022.05.31 |
[SwiftUI] List Row 선택하기(TableView didSelectRow) (0) | 2022.05.30 |