협업을 통해 배운 Git
배경 이야기
협업 과정에서 git 사용 미숙으로 인해 동료 개발자의 최신 커밋을 반영하는 과정에서 빈번한 충돌이 발생했다.
당시 git 충돌에 대한 두려움으로 인해 반복적으로 동료에게 도움을 요청하게 되었다.
이에 따라 협업 효율과 개인 작업 속도 모두가 저하되는 부정적인 영향을 미쳤는데, 이러한 계기로 git에 대해 찾아보고 정리한 내용을 기록하려 한다.
-
need to specify how to reconcile divergent branches
-
git merge vs git rebase
-
git rebase --interactive
- pick
- reword
- edit
- squash, fixup
- break
- drop
need to specify how to reconcile divergent branches
혼자 repository를 사용할 때는, local branch와 origin branch간의 conflict이 날 경우는 거의 없다. 하지만 협업을 하면서부터, 아래와 같은 경고 메세지를 만나게 된다.
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward onlydiergent branches 문제를 해결하는 설정 방식에는 3가지가 있다.
- pull.rebase false -> merge
- pull.rebase true -> rebase
- pull.ff only -> fast-forward only
나의 경우 첫 번째 경우는 소거했다. 협업 과정 개발에 들어가기 앞서, 팀 컨벤션 룰로 깔끔한 선형의 git history를 지향하기로 했기 때문에, merge 방식 대신 rebase를 사용하기로 합의했기 때문이다. 또한, ff only 설정 방식을 통해 fast forward가 불가능한 경우 병합 자체를 차단하도록 설정하여 각 팀원들이 conflict 직접 해결한 뒤에만 병합할 수 있는 전략을 취했다. 이로 인해 커밋 추적과 관리가 수월해졌다.
git merge vs git rebase
git rebase를 더 선호하는 경험적 이유
task: task-designSystem-Button
subtasks:
- subtask-designSystem-Button-variants (sp 2)
- subtask-designSystem-Button-color (sp 2)
- subtask-designSystem-Button-size (sp 1)
jira를 통해 브랜치를 생성하고, 각 subtask 브랜치에 스토리 포인트를 적용해 작업을 진행했다. 작업량 진척도를 공유하고, 꼼꼼한 코드 리뷰를 위해 작은 단위의 subtask 브랜치를 만들어 작업했지만, 작업을 완료 직후 바로 pr 리뷰를 받을 수 없는 경우가 많았다. 이 붕 뜨는 시간 동안에는 새로운 subtask 브랜치를 만들어 다른 작업을 병렬적으로 진행하게 되었다.
문제는, 리뷰가 대기 중인 브랜치와 작업 중인 여러 subtask 브랜치가 동일한 task 브랜치에서 파생된다는 점이다. 이 때문에 subtask 브랜치 작업을 할 때마다 상위 task 브랜치에 변경된 최신 커밋을 반영하는 과정에서 conflict가 빈번히 발생하게 된다.
거두절미하고 하고 싶었던 말은 conflict를 해결하기 위해 git merge로 병합을 하게 되면 새로운 merge commit이 프로젝트에 무수히 쌓이게 된다는 점이다. 이러한 merge commit들은 히스토리를 복잡하게 만들어, 작업 내용을 추적하기 어렵게 만들게 된다.
이러한 문제점으로, 나의 경우는 git rebase를 사용하여 최신 커밋 메세지를 반영하는 방식을 더 선호하게 되었다.
git rebase --interactive
pr리뷰를 해주는 팀원 입장에서 내가 작성한 커밋 메세지 퀄리티에 따라 팀원에게 불쾌감을 줄 수도 있다 생각한다. 불필요한 커밋으로 코드와 일관성이 없는 내용은 팀원에게 혼란을 주고 협업 작업 속도에 악영향을 준다. 이러한 문제를 해결하기 위해 git rebase --interactive를 사용해 브랜치 히스토리를 정리해왔다.
참고: 재그지그 블로그 - Git Rebase --Interactive 옵션 알아보기
🔍 interactive rebase 사용 방법
git rebase -i {수정할 커밋의 직전 커밋}b6052d43 feat: variants에 관해 히스토리를 수정하고 싶다 하면, dad8e5f (dev) chore: setting 커밋을 선택하면 된다. (dad8ef5 해시값 또는 HEAD~3 HEAD 포인터)
🔍 pick
1) 순서 재정렬과 2) 삭제가 가능한 옵션이다.
1. 순서 재정렬
size와 color의 커밋 순서를 바꿔 저장해 보자
작업 순서: variants -> size -> color
변경 순서: variants -> color -> size
$ git rebase -i HEAD~3size작업 전으로 color 커밋이 들어오므로 size 작업내용을 지운 color 작업물을 작성한다.
마지막으로 스왑된 color 작업물을 작성해준다.
변경된 순서가 variants -> color -> size 임을 확인할 수 있다.
2. 삭제
이번에는 pick 명령어를 가지고 dev브랜치에서 작업한 chore: setting 커밋을 삭제해보자.
$ git rebase -i HEAD~4첫번째 라인을 삭제해주고 저장시킨다.
로그를 확인해보니
chore: setting커밋이 사라졌음을 확인할 수 있다.
🔍 reword
커밋 메세지를 변경 가능한 옵션이다.
feat: variants 커밋 내용이 명확하지 않으므로 더 자세하게 작성해보자.
로그를 통해 variants 커밋이 변경되었음을 확인할 수 있다.
🔍 edit
1) 커밋 메세지 수정과 2) 작업 내용 수정이 가능한 옵션이다.
2418d25 feat: color: 'blue' | 'red' | 'slate' 단색 작업에 그라데이션 작업을 추가해보자.
git rebase -i HEAD~2button에 그라데이션 작업을 추가한다.
git rebase --continue를 통해 다음 커밋과 conflict가 발생한 내용을 수정해준다.
로그를 통해 작업을 수정하고 수정된 커밋 내용을 확인할 수 있다.
🔍 squash, fixup
해당 커밋과 이전 커밋을 병합이 가능한 옵션이다.
squash는 커밋 메세지가 합쳐지는 것이고, fixup은 이전 커밋 메세지만 남기는 차이점이 있다.
squash를 통해 color 단색과 그라데이션 커밋을 합쳐보자.
$ git rebase -i HEAD~3이전 커밋에 병합되어질 커밋을 squash 옵션으로 선택해주면 된다.
로그를 통해 두개의 커밋이 병합되었음을 확인할 수 있다.
🔍 exec
리베이스 도중에 쉘 커멘드를 실행 가능한 옵션이다.
edit를 통해 작업물을 변경하고 echo "변경된 파일 목록: " && git show --name-only HEAD를 통해 변경된 파일 목록을 출력 시켜보자.
git rebase --continue를 통해 HEAD 포인터를 이동시킨다.
로그를 통해 exec 옵션으로 변경된 파일 목록이 출력 되었음을 확인할 수 있다.
🔍 break
HEAD 포인터 이동을 강제적으로 break 시킬 수 있는 옵션이다.
로그를 통해 conflict이 없음에도
git rebase --continue를 강요하는 경고문을 확인할 수 있다.
🔍 drop
커밋 삭제가 가능한 옵션이다.
pick 옵션을 제거하는 방식과 차이가 없다.
로그를 통해 해당
size와 관련된 커밋이 삭제되었음을 확인할 수 있다.