2차 프로젝트 때 Git rebase를 처음해 보면서, 스스로 notion에 작성해 두었던 것을 계속 참고했는데 미래의 나를 위해 다시 한 번 잘 정리하여 블로그에 작성해본다.
git workflow란 한마디로 하자면, “브랜치를 관리하는 전략"이다.
실제 프로젝트를 운영하고 개발하는데, 깃 브랜치들을 어떻게 관리할 것인가에 대한 전략이 여러 개가 있다. 그 중에 가장 많이 쓰이고 있고 모든 전략의 근간이 되는 것이 git flow 이다.
자 만약에, 우리가 user에게 개발된 것을 배포하고 싶어. 그러면 그 때는 어떤 브랜치를 쓰느냐?
그런데 갑자기 나에게 전화가 와. 갑자기 로그인이 안된다고! 배포가 되었는데! 그런데 이거 고치는 것은 진짜 급한 상황이다. 이 때 급해 죽겠는데, 언제 develop따고 또 위와 같은 과정을 하기엔 너무 시간이 많이 걸린다. 그럴 때 쓰는게 Hotfix 브랜치이다.
Both of these commands are designed to integrate changes from one branch into another branch - they just do it in very differnet ways.
그러면 왜 rebase와 merge 두 개나 있을까?
둘이 하는 역할이 다르기 때문이다.
Q. main이 업데이트 되었다. 그럼 이제 뭐해야 하나?
A. 내 main git pull 하고 다시 내 브랜치로 이동해서 git merge main
명령어를 날릴 것이다.
Q. main 에 있던 새로운 다섯 개의 커밋은 어디로 들어갈까?
A. 시간 순서대로 내가 찍어놓은 커밋들 사이사이에 들어간다.
⛔️ 이렇게 되면 문제점이 있다.
1. 불필요한 merge commit이 생성된다.
2. history가 복잡해진다. 특정 커밋이 어떻게 생성되었는지 알아보기 어렵다.
위의 두 가지 문제점을 해결해 주는것이 바로 git rebase이다.‘Re-Base’ 다시 Base를 맞추어 주는 것이다! 다시 말해, 내 커밋의 base를 변경하여, commit history를 바꾸어준다.
git merge의 두 가지 단점을 아래와 같이 보완해준다.
1. 불필요한 merge commit이 제거된다.
2. 같은 작업을 진행한 commit끼리 모아주어, 최종적으로 특정 기능(커밋)이 어떻게 생겨났는지 확인할 수 있다.
⛔️ 그런데 Git rebase의 단점이 있다.
rebase를 하면서 옛날에 했던 커밋들을 다시 쓴다. 그래서 새로운 커밋이라고 생각해서 아이디를 다시 쓰는 것이다.
(0 - 1 에서 컨플릭트가 났는데, 해결했는데, 이제는 또다시 1-2에서 컨플릭트가 날 수 있다. 그 다음 2 - 3 ....) 따라서, 꼭! 반드시! 커밋이 두 세개 쌓였을 때, rebase를 한번씩 해야 한다!!! 자주 해야 conflict가 밀리지 않는다.
4-5개 있는 커밋을 하나로 합치는 것이다.
그러면 커밋을 왜 합쳐야 하나? 남길려고 커밋하는건데.
자. 내가 처음 커밋하나 하고, 리뷰반영을 하나 했어. 그런데 이게 다른 사람에게 보여주고 싶은 커밋은 아니잖아? 그래서 squash 라는 기능을 이용해서 하나로 합치고 메세지 한번 깔끔하게 정리하면 된다.
새로운 커밋을 받으러~
git checkout main
git pull origin main
git log // 잘 들어왔는지 확인
git checkout feature/minju
git rebase main // 두둥 충돌발생 - 실제로 Github에도 conflict가 떠있다.
//기존과 동일하게 conflict 해결 해준다.
//conflict 해결 후
git add .
git commit -m "Fix : conflict 해결"
git push origin feature/minju //오류 뜬다!!!
//rebase는 커밋을 다시 쓰는 것이기에 받아들일 수 없다고 내뱉는 거라,
--force블 붙여주면 된다.
git push origin feature/minju --force
//아직 squash는 안했다. 별도의 명령어가 있는게 아니다.
git rebase -i main
//맨 위에 커밋에 pick. 나머지는 s
//커밋 메세지도 맨 위에 커밋에 합쳐주고 나머지는 삭제해준다.
//Tip! i모드로 들어가지 않은 상태에서 지우고자 하는 커밋 앞에 커서를 두고
//dd를 두번 누르면 커밋이 삭제된다!
새로운 커밋을 받으러~
git checkout main
git pull origin main
git log // 잘 들어왔는지 확인
git checkout feature/minju
git rebase main // 두둥 충돌발생
실제로 위와 같이 PR에도 충돌 발생해 있다.
당황하지 말고 터미널에 뜬 메세지를 읽어봐라
// 1 2 3
// base 1 ⇒ 현재 이과정에서 문제발생!
base 1 2
base 1 2 3
어떻게 해결해야 할까? 🧐
✅ rebase 전으로 돌아가고 싶다면, git rebase --abort
✅ conflict 해결 후 push 하고 싶다면!
나는 커밋을 3개 남겼는데, 확인해보면 하나만 떠 있는 것을 볼 수 있다. 당황하지 말자! 첫 번째 커밋에서 컨플릭트 떴기 때문에 아직 그 뒤의 내용이 없는 것 뿐이다! 해결하면 나타난다.
conflict 해결 후, 다시
git add
git rebase --continue
git log를 쳐보면 base가 다시 변경된걸 볼 수 있다.
자 이제 git push 로 마무리
rebase는 커밋을 다시 쓰는 것이라고 했지! 그렇기에 받아들일 수 없다고 내뱉는 거라, -force하면된다.
다음과 같이 github 상의 conflict 메세지도 사라진 것을 알 수 있다.
그런데, 아직 squash는 안했다.
squash는 별도의 명령어가 있는게 아니다.
git rebase -i main
다음과 같은 터미널창이 뜬다
전에 커밋이랑 합쳐야 하니까 무조건 제일 위에꺼가 pick이 되어야 한다. vi 에디터에서 i 누르고 들어가서 첫번째를 제외하고는 s 를 입력해줌 ➡️ esc ➡️
:wq 엔터
그러면 커밋메세지 정리창이 나온다.
첫번째 커밋 메세지를 제외한 나머지 두 개는 지워주고 필요에 따라 첫 번째 커밋 메세지에 추가하여 작성해준다.(i 로 수정, esc + :wq 로 저장후 나오기)
git log를 쳐볼까?
자, squash가 잘 되었다. github에도, 세 개로 나뉘어 있던 커밋들이, 다음과 같이 하나로 정리된 것을 볼 수 있다.
👇 before & after