개요
코드 리뷰는 소프트웨어 개발에서 매우 중요한 과정으로, 여러 개발자가 협업하는 환경에서 코드의 품질을 유지하고, 버그를 줄이며, 코드의 일관성을 확보하는 데 필수적인 역할을 합니다.
우리는 코드 리뷰를 통해 코드의 문제점이나 개선점을 사전에 발견하고 해결할 수 있습니다. 코드 리뷰 과정을 통해 최종적으로 품질 높은 코드를 배포하는 것을 목표로 합니다.
코드 리뷰란?
개인이 코드를 푸시하면, remote 코드 저장소에서 품질 관리가 어려워질 수 있습니다. 특히 여러 개발자가 동시에 작업하면 다음과 같은 문제가 생깁니다:
- 코드 충돌
- 중복 기능
- 코드 스타일 불일치
- 품질 저하
이러한 문제를 방지하기 위해, 프로젝트별로 코드 리뷰 정책을 수립하고 GitHub의 PR(Pull Request) 기능을 통해 코드 리뷰를 진행합니다. 리뷰를 마친 후에는 Merge, Squash, Rebase 등의 병합 전략 중 하나를 선택하여 main 브랜치에 반영합니다.
코드 리뷰 프로세스
1. 작업 공간 설정 (Workspace)
fork, branch 생성 등 방법으로 프로젝트를 개인 작업 공간에 upstream 코드를 로컬에서 작업합니다.
Fork
외부 프로젝트의 저장소를 자신의 GitHub 계정으로 복제하는 작업입니다. 다른 사람의 저장소에서 작업할 때 주로 사용됩니다. Fork 후, 로컬에서 작업을 시작할 수 있습니다.
브랜치 생성
같은 프로젝트 내에서 작업할 때 사용합니다. main 또는 master 브랜치에서 새로운 브랜치를 생성하여 작업을 시작합니다.
2. 커밋 후 원격 저장소에 Push
로컬에서 작업한 코드를 커밋하고 원격 저장소로 푸시합니다.
$ git commit -m "Add login page feature"
$ git push origin feature/login-page
3. PR(Pull Request) 생성 및 요청
푸시한 브랜치에서 origin(자신의 저장소)에서 upstream(주 저장소)으로 Pull Request(PR)을 요청합니다.
4. code review
PR이 제출되면, 팀원들이 해당 PR을 확인하고 코드에 대해 검토합니다.
코드 리뷰 과정에서 기능의 정확성, 코드 품질, 최적화 가능성 등을 확인하며, 코드에 문제가 있다면 피드백을 줄 수 있습니다 개발자는 이를 수정하여 다시 커밋하고 푸시 후 PR을 요청 합니다.
5. Upstream 저장소에 Merge
리뷰가 완료되면, PR이 upstream 저장소에 병합됩니다. 병합이 이루어지면, 원본 저장소의 해당 브랜치에 개발한 기능이나 버그 수정 내용이 반영됩니다.
Merge 방식 정리
일반 Merge
Merge는 두 브랜치를 병합할 때 사용하는 방법으로, 병합 커밋(merge commit)을 생성합니다. 즉, feature 브랜치를 main 브랜치에 병합하면 새로운 커밋이 생성되며, 두 브랜치의 변경 사항을 결합합니다.
장점
모든 커밋을 보존하면서 병합됩니다. 변경 사항을 그대로 기록할 수 있기 때문에, 추후 병합된 커밋 내역을 추적할 수 있습니다.
단점
병합 커밋이 생성되므로 커밋 히스토리가 복잡해질 수 있습니다. 많은 병합 커밋이 쌓일 수 있습니다.
방법
병합하려는 브랜치로 체크아웃하고, main 브랜치를 병합합니다.
git checkout main
git merge feature/my-feature
git push origin main
Fast-Forward 방식
Fast-Forward Merge는 현재 브랜치가 다른 브랜치의 변경 사항을 모두 포함하고 있을 때, 병합할 필요 없이 단순히 해당 브랜치의 HEAD를 이동시키는 방식입니다.
만약 feature 브랜치가 main 브랜치에서 직접적으로 이어지는 경우, main 브랜치의 HEAD가 feature 브랜치의 끝 커밋을 가리키도록 이동됩니다.
Recursive 방식
Recursive Merge는 두 브랜치가 서로 다른 커밋을 가지며 병합 시 충돌이 발생할 가능성이 있을 때 사용하는 방식입니다. Git은 이 방식으로 충돌을 해결하며, 병합할 때 새로운 커밋을 생성합니다.
main 브랜치와 feature 브랜치에 각각 다른 변경 사항이 있다면, Git은 recursive 방식을 사용하여 병합하고, 충돌이 없으면 새로운 커밋을 생성합니다.
Squash and Merge
Squash and Merge는 여러 커밋을 하나의 커밋으로 압축하여 병합하는 방식입니다. 즉, feature 브랜치에서 여러 개의 커밋을 하나로 합친 후, 이를 main 브랜치에 병합합니다.
장점
커밋 히스토리가 깔끔해지며, 불필요한 커밋들이 하나로 묶이기 때문에 프로젝트 히스토리가 더 깔끔합니다.
단점
여러 작업을 하나로 합치는 과정에서 원본 커밋 정보가 사라지기 때문에 어떤 작업이 이루어졌는지 추적이 어려울 수 있습니다. 특정 기능의 변경사항을 찾을 때 불편할 수 있습니다.
Squash and Merge 방법
GitHub PR 페이지에서 Squash and Merge 버튼을 사용하여 커밋을 스쿼시할 수 있습니다. 로컬에서는 git rebase -i를 사용해 여러 커밋을 스쿼시할 수 있습니다.
git checkout upstream
git merge --squash mp-app
Rebase And Merge
Rebase는 브랜치의 기반을 변경하여, 커밋 해시를 새로 생성하는 방식입니다. Rebase는 Fast-Forward Merge와 비슷한 구조로, 커밋 히스토리가 직선적으로 이어지게 만들어 깔끔한 히스토리를 유지합니다.
장점
선형적인 커밋 히스토리를 유지할 수 있습니다. merge commit 없이 깔끔한 히스토리를 보존할 수 있습니다.
직선적인 커밋 히스토리를 유지하므로, 전체 개발 흐름을 한눈에 파악하기 용이합니다.
여러 커밋이 하나의 커밋처럼 보일 수 있지만, 실제로는 커밋 해시가 변경되어, 그 변화를 추적하는 데 유리합니다.
병합 과정이 깔끔하게 처리되며, 충돌을 미리 해결할 수 있는 장점이 있습니다.
단점
리베이스 중 충돌이 발생할 수 있으며, 리베이스를 완료한 후 force-push가 필요할 수 있습니다.
Rebase And Merge 방법
git checkout feature/my-feature
git rebase main
# 충돌 해결 후
git push origin feature/login-page --force
git checkout main
git pull --rebase upstream main
git push origin main
Merge 사용시 로컬 브랜치 동기화 및 Push 방법
로컬 브랜치에서 병합을 사용하여 최신 상태로 동기화합니다.
git checkout main
git pull origin main
로컬 브랜치(main)를 원격 저장소(origin)에 푸시합니다.
git push origin main
Squash/Rebase 사용시 로컬 브랜치 동기화 및 Push 방법
먼저 upstream 저장소의 최신 상태를 로컬에 반영합니다. rebase는 커밋을 재배치하여 히스토리를 선형으로 만들고,
reset --hard는 로컬 커밋을 모두 덮어씌웁니다.
git checkout main
git fetch upstream
git rebase upstream/main
# 또는
git reset --hard upstream/main
Rebase로 origin 기준 최신화합니다. origin은 여러분의 GitHub 저장소, upstream은 원본 저장소입니다.
git checkout main
git pull --rebase origin main
로컬 브랜치(main)를 원격 저장소(origin)에 푸시합니다. 이때 오류가 발생할 수 있습니다:
! [rejected] main -> main (non-fast-forward)
git push origin main
Push 오류 해결: non-fast-forward 에러
origin/main이 로컬보다 더 최신 커밋을 가지고 있는 경우 발생합니다. 즉, 누군가 먼저 push했거나, GitHub에서 Squash Merge 후 히스토리가 달라진 상황입니다.
error: failed to push some refs to ...
hint: Updates were rejected because the tip of your current branch is behind...
충돌이 해결되면 변경사항을 git add로 스테이징하고, git rebase --continue나 git merge --continue로 리베이스나 병합을 계속 진행합니다.
git add .
git rebase --continue # rebase 중이라면
# 또는
git merge --continue # merge 중이라면
충돌 없이 완료되면 다시 푸시합니다.
git push origin main
그래도 안되는 경우 강제로 푸시를 통해 push 할 수 있습니다. 이는 원격 저장소의 커밋 히스토리를 덮어쓰므로 협업 중에는 신중하게 사용해야 합니다.
git fetch origin
git reset --hard origin/main
git push origin main --force
'Git' 카테고리의 다른 글
자주 사용하는 Git CLI (0) | 2024.06.17 |
---|---|
Git 저장소 구조 이해 및 프로젝트 시작하기 (0) | 2024.05.24 |
Git 저장소 크기 관리 도구 | Git-sizer (0) | 2024.05.22 |
Commit Message를 활용한 Git log 관리 (0) | 2024.05.22 |
Git Branch 전략: Gitflow와 네이밍 규칙의 중요성 (1) | 2023.12.27 |