❒ Description
회사에서 일하다가 중간에 집에서 이어서 일해야할 때 종종 사용했었다.
# 회사에서 작업 (커밋 2개)
git commit -m "Entity 작업"
git commit -m "API 개발 (WIP)"
# 집에서 작업
git commit -m "new API (DONE)"
# rebase
git rebase -i HEAD~3
git push ~
오늘은 git rebase에 대해서 알고 있는 부분을 정리해보자. 면접 때 물어 볼 수도 있느니!
❒ Rebase vs Merge
rebase와 merge 모두 한 브랜치에서 다른 브랜치로 변경 사항을 통합하도록 설계됐다는 공통점이 있다.
하지만 그 방식에는 차이가 있다.
merge는 non-destructive 작업이라는 장점이 있다. 반면에 이는 upstream 변경 사항을 통합해야 할
때마다 작업 브랜치에 불필요한 병합 커밋이 발생한다는 의미이기도 하다.
이제 rebase를 살펴보자. rebase를 하면 전체 기능 브랜치가 메인 브랜치의 끝에서 시작하도록 이동하여
새롭게 생긴 모든 커밋을 메인 브랜칭 효과적으로 통합할 수 있다. 여기서 rebase는 원래 브랜치의 각 커밋에
대해 새로운 커밋을 생성하여 프로젝트 히스토리를 다시 작성한다.
Rebase의 장점
- 깔끔한 커밋 이력 관리
- 불필요한 merge 커밋이 없음.
- 하나의 선형 히스토리로 인해 커밋이력 탐색이 더 쉬움.
Rebase의 단점
- Golden Rule of Rebasing을 따르지 않으면, 협업 workflow에 치명적
- merge 커밋이 사러져 언제 upstream 기능이 merge 됐는지 트랙킹이 안됨.
❒ Interactive Rebase
Interactive rebase를 사용하면 rebase할 때 보다 유연하게 커밋을 관리할 수 있다.
git rebase -i ${branch_name}
어떻게 유연하게 관리할 수 있는지 확인해보자. 위 커맨드를 입력하면 아래와 같이 에디터 창이 열린다.
pick 33d5b7a Message for commit#1
pick 9480b3d Message for commit#2
pick 5c67e61 Message for commit#3
commit#2 커밋은 commit#1의 주석 오타를 수정한 사소한 커밋이다.
해당 커밋은 불필요한 커밋으로 판단할 수 있고, rebase 할 때 이를 없앨 수 있다.
(1) enter command
git rebase -i HEAD~3
(2) edit text and save
pick 33d5b7a Message for commit#1
fixup 9480b3d Message for commit#2
pick 5c67e61 Message for commit#3
`fixup`을 사용하면 commit#1과 commit#2는 하나의 커밋으로 통합이 된다.
이렇게 불필요한 커밋을 제거할 수 있다.
만약 커밋 메시지를 변경하고 싶으면 `reword` 키워드를 사용하면 된다.
(1) enter command
git rebase -i HEAD~3
(2) edit text and save
reword 33d5b7a Message for commit#1
fixup 9480b3d Message for commit#2
pick 5c67e61 Message for commit#3
(3) edit text and save
${new_commit_message}
❒ Golden Rule of Rebase
Rebase는 public branch(공용 브랜치)에서는 절대 사용해서는 안된다.
rebase는 커밋 히스토리를 재작성하여 기존 커밋의 ID를 새롭게 하기 때문에 이미 다른 사람과 공유된
커밋을 rebase하면 다른 사람의 로컬 저장소와 충돌이 발생할 수 있다.
이러한 충돌은 협업 시 복잡한 문제를 일으킬 수 있으며, 해결하는 데 시간이 많이 걸릴 수 있다.
이를 잘 실천하기 위해서 rebase는 자신만 사용하는 브랜치에서 사용하는 것이 좋다.
아직 원격 저장소에 푸시되지 않았거나, 혼자 작업 중인 브랜치에서만 rebase를 사용하는 것이 안전하다.
만약 이미 푸시된 커밋을 수정하거나 rebase해야 한다면, 그 브랜치를 사용하고 있는 팀원들과 협의하거나,
`git push --force(강제 푸시)`를 신중하게 사용해야 한다.
❒ Conflict
Rebase를 하는 과정에서도 conflict가 발생할 수 있다. 이때 해결 순서는 다음과 같다.
- rebase
- (conflict) solve conflict
- git commit - m "~~"
- git rebase --continue
❒ git push --force & --force-with-lease
다음과 같은 상황을 보자.
- 회사에서 커밋 후 퇴근
- 집에서 이어서 작업 후 커밋
이 상황에서 commit#1과 commit#2를 합치려면 위에서 했던 방식으로 rebase를 하면된다.
하지만 commit#1은 이미 push가 된 상태이기 때문에 rebase를 하게 될 경우 집에서 push를
또 해줘야 하는데 이 때 사용하는 명령어가 --force 또는 --force-with-lease이다.
--force의 경우 무조건 적으로 push 하는 것이기 때문에, remote에 있던 모든 변경 사항을 덮어씌운다.
협업하는 상황에서 위 명령어를 사용하면 동료 개발자의 commit이 누락될 위험이 큰 명령어이다.
반면에 --force-with-lease는 remote 브랜치가 예상한 상태와 일치할 경우에만 push를 진행하며,
그렇지 않은 경우에는 push를 거부한다.
나는 보통 개인 브랜치에서만 rebase를 사용했기 때문에 --force를 사용하곤 했다.
※ 참고 링크
https://www.atlassian.com/git/tutorials/merging-vs-rebasing