오랜만에 포스팅으로 돌아왔습니다! 인턴을 시작한 지도 거의 2달이 지났네요. 역시나 실무에선 모르는 것도, 배우는 것도 많네요,,, ㅎㅎ 이런 내용들은 회사에서 반복적으로 수행하다 보면 자연스럽게 체득할 수도 있겠지만, 그렇다고 온전히 제 것이냐 라는 질문에는 선뜻 그렇다 대답할 수 없을 것 같습니다.
결국 내 것으로 만들기 위해선 한 번은 꼭 정리해 보는 시간이 필요하다 느껴집니다. 앞으로 쓰고 싶은 내용들이 무지막지하게 많지만 그중에서도 가장 먼저, 그리고 가장 충격(?)을 먹었던 실무 `Git` 사용법 관련에 대한 포스팅을 진행해보려 합니다.
그동안 나는 어떻게 코드 리뷰 대응을 하고 있었을까?
저는 이전 애플 디벨로퍼 아카데미에서 팀원들과 적극적으로 PR 작성, 코드 리뷰 문화를 도입해 협업한 경험이 있었습니다. 이와 관련해 포스팅까지 작성하며 효용성에 대해 공유하려 하기도 했었죠!
위 방식에 대해 간단히 정리해 보자면 아래와 같습니다.
- feature 브랜치 생성 후 첫 번째 commit 작성 시, 곧바로 원격 저장소 push + PR 작성.
- commit 단위로 내가 작성한 코드에 대한 코멘트 작성.
- 모든 작업이 끝난 후 Label을 통해 팀원들에게 코드 리뷰 요청.
- 코드 리뷰 중 수정 사항 발생 시, 새로운 commit으로 코드 리뷰 내용 반영.
- 최종 코드리뷰 완료 후 develop(production) 브랜치로 merge.
여기서 강조 표시한 부분이 오늘 포스팅할 내용의 핵심 포인트입니다. 코드 리뷰 중 수정 사항이 발생했을 때 새로운 commit으로 내용을 반영하는 것이 어떤 문제를 만들어낼 수 있을까요? 이를 확인해 보기 위해 간단한 예제를 준비해 봤습니다.

위 PR에는 5개의 commit이 포함되어 있습니다. 코드 리뷰 중 문제가 없다면 곧바로 develop 브랜치에 merge 돼도 괜찮을 겁니다! 하지만 현실은 그렇지 않습니다. 고심 끝에 작성한 코드라도 놓치거나 실수하는 부분은 언제나 생길 수 있습니다. 코드 리뷰가 있는 이유이기도 합니다.
팀원들이 꼼꼼히 코드 리뷰를 해 준 결과, 역시나 수정 사항이 발생하고 말았습니다. 회원가입 및 로그인 Repository를 구현하는 'A' 커밋에서 작성한 파일이 문제였습니다. 간단한 변경사항이었기 때문에 A 파일을 빠르게 수정하고 이를 반영하는 commit을 추가했습니다. 이때 commit history는 아래와 같아질 것입니다.

다시 신나게 develop에 merge 하려는 그때,,,! 불길한(?) 소식이 들려옵니다. 기획 팀에서 회원가입 정책이 바뀌어서 비즈니스 로직과 UI 구현을 수정해 달라는 요청이 들어온 것입니다. 이번엔 수정해야 할 내용들이 더 많아져서 commit을 몇 개 더 추가하게 되었습니다. 이때 commit history는 아래와 같아질 것입니다.

PR 예제 돌아보기
자 이쯤에서 PR을 다시 돌아보겠습니다. 기존 PR 내용은 A, B, C, D, E 5개의 commit으로 구성되어 있었습니다. 하지만 코드 리뷰 및 수정 사항이 들어올 때마다 commit을 쌓다 보니 최종적으로는 9개의 commit으로 늘어나게 되었습니다. 이렇게 코드 리뷰가 진행될수록 commit이 쌓이게 되면 발생할 수 있는 문제들을 예상해 보겠습니다.
1. CASE 1: 코드 리뷰 중간에 참여한 동료
만약 코드 리뷰 중간에 참여한 동료가 commit 단위로 처음부터 코드 리뷰를 시작한 상황을 가정해 보겠습니다. 처음에는 5개의 commit만 확인해도 됐었던 PR이 9개로 늘어나게 되었습니다. 같은 파일이지만 두 번, 혹은 그 이상 수정된 파일을 코드 리뷰해야 한다면 리뷰어의 생산성과 피드백 퀄리티는 떨어질 수밖에 없을 것입니다.

바꿔 말하면, 수정하는 commit이 늘어날 수록 리뷰어의 부담이 증가할 수 있습니다. 이는 코드 리뷰가 많아지고, 수정 사항이 많아질 수록 더 빠르게 증가할 수 있습니다.
2. CASE 2: 시간이 지난 후 commit을 찾아보는 동료
또 만약 develop 브랜치에 merge 후 시간이 지나 다시 commit history를 찾아보는 상황을 가정해 보겠습니다. '회원가입 비즈니스 로직이 처음 작성'된 부분을 찾아보려면 어떤 commit을 봐야 할까요?(여기서 처음은 develop 브랜치에 처음 merge 되었을 때를 가정합니다.)
이때 당시 PR의 맥락을 모르는 사람이 제목만으로 정확한 commit을 찾아볼 수 있을까요? 위 예시보다 훨씬 더 많은 회원가입 비즈니스 로직 구현, 수정, 2차 수정 등 수많은 commit이 있다면 복잡도는 더 올라갈 것입니다.

바꿔 말하면, 이렇게 작성되고 상위 브랜치로 merge 된 commit은 프로젝트 관점에서 효용성을 크게 떨어트릴 수 있습니다. commit 단위로는 코드 흐름을 추적하기 쉽지 않을 것이고, 어떤 PR에 속해 있는지를 기준으로 판단해야 하기 때문에 이에 대한 이해가 필수적으로 요구됩니다.
어떻게 개선할 수 있을까?
코드 리뷰 및 수정 사항에 대한 새로운 commit을 PR 내 계속 쌓게 되었을 때의 문제점을 간단히 살펴봤습니다. 어떻게 하면 commit을 늘리지 않으면서도 리뷰어의 부담을 낮추고, 효용성을 늘릴 수 있을까요?
바로 기존 commit을 수정하는 것입니다! 사실 곰곰히 생각해 보면, 위 PR에서 코드 리뷰 중 추가된 commit들은 새롭게 작성될 필요가 없었습니다. 코드 리뷰와 수정 사항 내용들은 '기존' commit 안에 '원래' 포함되어있어야 할 내용들인 것이죠.

즉, 만약 회원가입 Repository DTO를 수정해야하는 코드 리뷰가 들어왔다면, 새로운 commit을 추가하는 것이 아닌 'A' commit에 수정 사항을 반영하는 것으로 문제를 해결할 수 있습니다.
이렇게 commit을 반영하게 되면 같은 파일 내 몇 번이고 수정사항을 반영해도 개수는 늘지 않을 것이며, commit 그 자체로서의 효용성도 올라갈 것입니다!
interactive rebase로 commit 수정하기
그럼 commit은 어떻게 수정할 수 있을까요? 바로 이전 commit이라면 `ammend` 명령어를 활용해 쉽게 수정할 수 있겠지만, 5번째 앞에 있는 commit은 새로운 방법이 필요합니다.
여기서 등장하는 개념이 바로 `interative rebase`입니다. 이는 대화형 rebase라고도 불리며, 단순히 기준점을 옮기는 일반 rebase와 다르게 커밋의 내용을 직접 조작할 수 있게 만들어줍니다.
백문이 불여일견! 위에서 살펴봤던 예제의 첫 번째 요구 사항인, '회원가입 Repository DTO 수정' commit의 내용을 'A' commit에 추가하는 것으로 시작해 보겠습니다.

A. CLI로 수정하기
1. 수정할 위치에서 Interative Rebase
우리가 수정하고 싶은 commit은 'A'입니다. 이곳에서 interative rebase를 시작하기 위한 HEAD 지정, 혹은 commit 해시를 이용해 명령어를 입력합니다.
# 직접 HEAD 지정하는 방식(기준점부터 5번째)
git rebase -i HEAD~5
# 혹은 commit 해시 이용(수정하려는 커밋보다 한 단계 이전 커밋 해시)
# 즉, 여기서는 A 이전의 커밋 해시 작성
git rebase -i <커밋 해시>
2. 수정할 commit 옵션 지정
interactive rebase를 시작하면 범위 및 옵션을 지정하는 텍스트 편집창이 보입니다. 우리는 'A' 커밋을 수정하고 싶기 때문에, 커밋 앞의 `pick` 옵션을 `edit`으로 변경해 줍니다.


3. 코드 리뷰 내용 반영하기
이제 interactive rebase가 시작되었습니다! 현재 상태는 `edit`으로 설정한 'A' commit을 추가한 시점으로, 프로젝트를 확인해 보면 해당 시점의 코드를 확인해 볼 수 있습니다. 여기서 코드 리뷰 내용, 즉 회원가입 Repository DTO를 수정하는 코드를 프로젝트에 반영합니다.
4. 수정사항 반영하기
코드 리뷰 내용을 모두 추가하고 이를 interative rebase에 반영하기 위해 변경 사항을 스테이징 합니다.
git add .
그리고 현재 HEAD가 'A' Commit이 추가된 시점에 위치해 있기 때문에 바로 이전 commit을 수정하는 명령어를 입력합니다.
git commit --amend
commit을 완료하면 다음과 같이 'A' 커밋에 수정 사항이 반영됩니다.

5. Rebase 계속 진행하기
아직 interactive rebase가 끝나지 않았습니다. 왜 edit과 동시에 rebase가 끝나지 않을까?라는 생각이 들 수 있지만, 작업 순서를 생각해 보면 이는 안전한 장치입니다.
보통 앞서 작성한 commit을 기반으로 뒤 코드가 작성되는 경우가 많기 때문에, 충돌(conflict)의 위험이 남아있기 때문입니다. 앞서 회원가입 Repository DTO를 수정했기 때문에 회원가입 비즈니스 로직을 작성하는 부분에서 충돌이 일어날 수도 있는 것입니다.
이를 위해 interative rebase는 시작 지점부터 commit을 하나하나 확인하며 충돌 여부를 확인하고, 발생 시 사용자에게 어떤 작업 내용을 선택할 것인지 안내하게 됩니다.
우선 다시 돌아와, rebase를 계속 진행해 보겠습니다.
git rebase --continue
만약 충돌이 없다면, 성공했다는 안내와 함께 rebase가 종료되지만 충돌 발생 시 다음과 같은 경고를 발생시킵니다.

6. 충돌 해결하기
위 상황에서 선택할 수 있는 옵션은 3가지입니다.
- 충돌을 직접 해결하기(`git add` + `git rebase --continue`)
- 충돌난 commit 버리기(`git rebase --skip`)
- 지금까지 rebase 하면서 변경한 내용 다 원래대로 돌리기(`git rebase --abort`)
아몰랑 무서워 나 돌아갈래
우리는 대부분 용감하게 충돌을 직접 해결해야 할 것이기 때문에 1번 옵션으로 진행해 보겠습니다.(사실 전 처음에 rebase 하다 많이 꼬여서 `--abort` 애용하긴 했습니다,,,)
IDE 마다 다르겠지만, VSCode 등에서는 충돌 해결을 위한 UI를 제공하기도 합니다. 하지만 iOS 개발자의 영원한 친구 Xcode는 그런 거 없고 그냥 화살표 띡띡 그려주고 에러를 던져주기 때문에 직접 충돌을 해결해 볼 수 있습니다.

프로젝트에서 충돌을 모두 해결했다면, 똑같이 변경사항을 스테이징 합니다.
git add .
그리고 다시 rebase 프로세스를 진행합니다.
git rebase --continue
만약 성공했다면 그대로 rebase가 종료되고, 다음 commit에서 또 다른 충돌 발생 시 같은 프로세스로 충돌을 해결할 수 있습니다.

7. 원격 저장소에 강제 push
interactive rebase 완료 후 모든 코드 리뷰 내용이 반영되었다면, 이제 PR을 최신화할 차례입니다. 원격 저장소에 올라가 있는 PR은 현재 local에서 rebase 한 작업 내용과는 다르기 때문에, 이를 업로드하기 위해선 강제 push가 필요합니다.
보통 feature 브랜치 작업 + PR 작성은 1인으로 진행하기 때문에 강제 push가 문제 될 일이 적지만, 만약 함께 사용하는 브랜치나 develop, production 등에 강제 push 하는 것은 매우 위험할 수 있습니다.
그러니 혼자서 사용하는 브랜치 + PR 단위에만 rebase 및 강제 push 작업을 권장드립니다!

2. GUI로 수정하기(feat: Fork)
이번엔 GUI로 interative rebase를 진행해 보겠습니다. 저는 꽤 오래 CLI를 사용하다 최근에서야 GUI로 갈아타게 되었는데, 앞선 시간들이 후회될 정도로 정말,,,, 편하더라고요,,,,
각자 사용하시는 Git GUI tool들에 따라 사용법이 조금씩 다를 수 있겠으나, 큰 맥락은 비슷할 거라 생각하며 전 무료 툴인 Fork로 진행해 보겠습니다.(개인적으로 다른 tool들 이것저것 사용해 봤을 때 Fork 만한 게 없다고 느꼈습니다!)
1. 수정할 위치에서 Interative Rebase ~ 수정할 commit 옵션 지정
수정할 위치인 '회원가입 및 로그인 Repository 구현' commit에서 우클릭 후 `Interactive Rebase` > `Edit`을 클릭합니다.

CLI에서 본 텍스트 편집기가 깔끔한 UI로 표현됩니다. 우리가 수정할 commit에 `Edit` 옵션이 켜져 있는 상태를 확인할 수 있습니다. 그대로 오른쪽 하단의 `Rebase` 버튼을 눌러 interactive rebase를 시작합니다.

2. 코드 리뷰 내용 반영하기 ~ 수정사항 반영하기
rebase 시작 시 Fork 앱에 rebase가 진행 중이라는 Alert 창이 출력됩니다. 현재 5개의 commit이 rebase 프로세스를 대기 중이며, 오른쪽엔 현재 rebase 프로세스 변경사항을 날림과 동시에 종료하는 `abort` 버튼과, 충돌 해결을 위한 도구를 제공하는 `Resolve` 버튼이 있습니다.

각자 사용하는 프로젝트의 IDE로 돌아가 코드 리뷰 내용을 반영하고 돌아와 스테이징 후 `Ammend` 체크 박스가 활성화된 상태로 `Ammend Last Commit` 버튼을 누르면 성공적으로 수정사항이 반영됩니다.

3. Rebase 계속 진행하기 ~ 충돌 해결하기
코드 리뷰 내용 반영 후, 아래 `Continue Rebase` 버튼을 눌러 rebase를 계속 진행합니다.

만약 충돌 발생 시, CLI에서 본 충돌 에러와 동일한 내용을 Fork에서 경고창을 출력해 줍니다.

이를 위해 기존 방법처럼 프로젝트 IDE(나의 경우 Xcode,,,)를 사용해 충돌을 해결할 수 있으나, Fork에서도 이를 쉽게 적용할 수 있는 도구를 제공합니다. 아래 Merge Conflict 화면에서, 둘 중 하나를 선택하거나 직접 작업 내용을 선택하는 `Merge in Fork` 기능을 활용할 수도 있습니다.


동일하게 모든 충돌을 해결하면 Fork의 rebase 진행 중 Alert가 사라지며 정상적으로 rebase가 마무리됩니다.
Rebase는 귀찮아. 하지만,,,
지금까지 PR에 왜 rebase를 통한 commit 관리가 필요한지와 그 방법에 대해 소개드렸습니다. 사실 rebase는 무지 귀찮습니다. commit을 하나 올릴 땐 신경 쓰지 않아도 되는 rebase 과정, 불필요한 충돌 등의 과정을 PR 작성자가 감수해야 하니까요.(또한 프로덕트와 상관없이 모든 수정 사항의 이력을 남기고 싶은 목적이라면 맞지 않을 수 있겠습니다)
하지만 rebase의 장점은 분명합니다. 동료들이 훨씬 수월하게 PR을 읽을 수 있게 되어 코드 리뷰의 퀄리티가 올라갈 수 있고, commit 단위의 프로젝트 history 추적 또한 용이해질 것입니다.
좋은 개발자가 되기 위해 가장 중요한 덕목 중 하나가 커뮤니케이션이라고 느끼는 요즘, PR 작성 및 Git 관리의 중요성을 다시금 깨닫게 됩니다! 🌱

'실무 내용 내껄로 만들기' 카테고리의 다른 글
| Firebase Remote Config로 배포 없이 값 "딸깍" 바꿔주기 (0) | 2025.11.23 |
|---|---|
| Firebase App Distribution + Fastlane으로 초간단 QA 빌드 뽑아보기 (0) | 2025.10.19 |
| Git Worktree로 브랜치 사이를 효율적으로 거닐기 (0) | 2025.09.13 |
