Git Rebase

seyong·2021년 12월 19일
0
post-thumbnail

main에 다른 브랜치를 병합할 때 쓰이는 방법이 두가지인데, 하나는
merge가 있고, 다른 하나는 rebase 가 있다.

여기서는 rebase 에 대해서 공부하며 글을 써보도록 하겠다.

Git rebase 알아야 하는 이유

git을 사용하면서 커밋을 할때 지난 커밋을 취소하거나 수정하고 싶을 때도 있고, 잘못된 브랜치에서 커밋해서 다른 브랜치로 커밋을 옮기고 싶은 경우도 있을 것이다.

이와 같이 이미 해버린 커밋을 수정하는 데에 유용하게 사용되는 커맨드가 바로 git rebase 이다.

git rebase 는 이전 커밋을 수정하고, 커밋을 다른 브랜치로 옮기는 일을 할 수 있다. 또 지저분한 커밋이력을 남기고싶지않고, 하나의 커밋으로 깔끔하게 만들고 싶을때 사용할 수 있다.

그렇기 때문에 협업을 할 때에는 반드시 git rebase를 알아야 하고 , 또 git rebase를 잘 쓸 수 있어야 비로소 git의 기능을 잘 활용할수 있다고 생각한다.

예를 들어 A라는 프로젝트를 clone받아서 수정을 하게 된다면
main에서 직접 수정하지 않고 브랜치를 분리해서 작업을 하고나서 커밋하기전에 git rebase 를 하고 푸시를 하는 방식을 취할 수 있다.
이렇게 할 경우 같은 내역을 다른 커미터가 먼저 커밋했을때 해당 커밋을 유지시키고 자신이 수정한 커밋은 생략되어서 히스토리를 깔끔하게 유지할 수 있고 불 필요한 merge commit 같은 것이 남지 않게된다.

merge 와 rebase를 했을 때 차이점

merge와 rebase를 했을 때 가장 큰 차이는 바로 "commit의 깔끔함" 이다.

쉽게 이해하기 위해서 아래 이미지를 참고해보자.

merge를 사용하면 모든 commit을 남기게 되지만, rebase를 이용하면 필요없는 commit을 생략시키기 때문에 master 브랜치에 commit은 항상 깔끔하게된다.

만약 feature/test라는 branch를 만들어서 열심히 작업을 하고 master에 merge를 사용해서 병합한다고하면, feature/test에서 기록한 모든 commit이 master의 commit으로 기록된다.

rebase 방식을 사용해서 병합한다면, 내 작업하면서 남겼던 commit 중 불필요한 것들은 생략시키고 필요한 commit만 남겨서 master에 병합하기 때문에 master의 commit은 항상 깔끔하게 관리된다는 장점이 있다.

똑같은 병합이지만, 나중에 master의 commit을 볼 때 깔끔하게 볼 수 있어서 여러 명이 협업할 때 유용하다.

git rebase 예시

  1. 예를들어 main 브랜치에서 feature/signup라는 회원가입 기능구현 branch를 따로 만들고 작업을 한다고 가정해보자. 작업을 마치기 전에 commit을 남겨면 아래와 같이 될것이다.
main > git checkout -b feature/signup
feature/test > git add .
feature/test > git commit -m '[ADD]: Sign up 기능구현'
  1. 그리고나서 다시 남은 작업들을 한다음, 다시 commit을 남긴다.
feature/test > git add .
feature/test > git commit -m 'wip' # WIP는 work in progress 의 약자로 작업중이라는 뜻이다
  1. 2번째 commit 까지 하고난 후 다 작업을 한것 같아 테스트를 해보니 버그가 발생했다. 버그를 수정한 후 마지막 commit을 남긴다.
feature/test > git add .
feature/test > git commit -m '[Modify]: bug fix'
  1. main 브랜치에 푸시하기전에 git rebase로 불필요한 commit을 squash 해준다.
feature/test > git rebase -i main
  1. 명령어를 입력한 후 아래와 같은 화면이 보일것이다. 필요 없는 commit은 pick을 지워주고 s(squash)옵션으로 바꿔준다.
    3개의 commit을 깔끔하게 1개로 남겨보겠다. vim 에서 쓰는 명령어로 편집하면 된다. (아래 내용 출처는 git-com 에서 가져온것을 수정한것이다.)
pick f7f3f6d [ADD]: Sign up 기능구현
pick 310154e wip                 // 여기서 pick을 s로 바꿔준다.
pick a5f4a0d [Modify]: bug fix  // 여기서 pick을 s로 바꿔준다.
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
  1. 편집하면 아래와 같은 모습이된다. 수정한 후 :wq로 vi를 빠져나온다.
pick f7f3f6d [ADD]: Sign up 기능구현
s 310154e wip                 
s a5f4a0d [Modify]: bug fix  
# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
  1. 빠져나오게 되면 아래와 같은 또다른 vi로 commit을 입력 할 수 있게 된다. 하나의 commit message만 남기고 나머지는 삭제한다. 이 하나의 commit message가 branch를 대표하는 commit message이므로 상세하고 신중하게 적는다.
# This is a combination of 3 commits.//이 위치에서 dd를 눌러 줄을 삭제한다.
# The first commit's message is: //이 위치에서 dd를 눌러 줄을 삭제한다.
[ADD]: Sign up 기능구현 //이 위치에서 dd를 눌러 줄을 삭제한다.

# This is the 2nd commit message: //이 위치에서 dd를 눌러 줄을 삭제한다.

wip //이 위치에서 dd를 눌러 줄을 삭제한다.

# This is the 3rd commit message: //이 위치에서 dd를 눌러 줄을 삭제한다.

[Modify]: bug fix //나는 이 commit만 남기고 싶으므로 이건 냅둔다.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# rebase in progress;
  1. 이 상태에서 :w로 나오면 rebase가 끝나고 브랜치로 다시 돌아오게 된다. git push origrin feature/signup 로 push를 한다.

[Modify]: bug fix

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# rebase in progress;

이렇게 git rebase 를 하면 여러 커밋을 남겼어도 꼭 필요한 커밋만 남길 수 있다. rebase를 잘 성공시킨 후 main브랜치의 커밋기록을 보면 선형방식으로 깔끔하게 한줄로 정리되어있는것을 볼 수 있다.

주의할 점

  • 다른 사람들과 함께 쓰고 있는 브랜치에다가 git push를 한 경우에는 가급적 rebase를 쓰지 않는 것이 좋다. 내가 rebase한 내용을 다른사람이 git pull로 받게되면 엄청난 conflict를 만날 수 있기 때문이다.
    로컬에서 작업하고 origin으로 push하기 전에 깔끔하게 커밋을 정리하는 차원에서 이용하는것이 좋아보인다.

(참고: conflict는 commit과 commit 사이에서 일어나는 작업 내용 사이의 충돌을 말한다.)



최종정리

새로운 작업을 모두 마치고 push 하기 전에는

  1. Main branch로 이동하여 remote main을 pull 받는다.

  2. 내가 push할 Feature branch 로 이동한다.

  3. git rebase -i main를 진행한다.

Rebase 하는 동안 squash 진행할 때에는

  1. 가장 오래된 commit을 pick 한다.

  2. 다른 커밋메세지는 가장 오래된 commit을 기준으로 squash 한다.

  3. squash를 한다고 해서 다른 커밋의 작업 내역이 없어지는 것이 아니다.

  4. ESC 를 누른다음 :wq! 로 vi에서 빠져나온다.

  5. 빠져나오게되면 수정용 vi에디터가 하나 더 나타난다.

수정용 에디터에서의 작업

  1. 수정용 vi에디터는 최종적으로 이 rebase된 커밋의 내용을 작성하는 부분이다.

  2. 현재까지 적은 커밋메세지가 전부 나타난다.

  3. 불 필요한 내용은 제거하고, 현재 수정 내역에 대한 커밋메세지를 정성껏 작성한다.

  4. ESC 를 누른다음 :wq! 저장하고 에디터에서 빠져나온다.

  5. 성공했다면 Successfully rebased 라는 문장을 터미널에서 볼 수 있다. 이후 push 하면된다!

rebase 이후 push 하기

  1. rebase는 commit history를 정리하는 역할을 한다.

  2. 같은 브랜치에서 rebase를 할 때 마다 history가 달라질 수 있다.

  3. 수정 사항이 추가로 생긴 후 다시 rebase하면 history가 무조건 달라진다.

  4. git은 history가 다른 branch의 push를 허용하지 않는다.

  5. git push origin feature/signup -f -f 의 옵션을 사용하여 force push를 진행한다.

rebase 중 충돌 해결하기

  1. 충돌이 일어난 경우 rebase가 진행되지도, 끝나지도 않고 도중에 멈춰있어, 당혹스러울때가 있다.

  2. 터미널이 아래와 같은 메세지로 rebase가 진행중임을 알려주니 너무 겁먹지는 않도록 하자!

  3. 충돌은 충돌일 뿐, 해당하는 코드를 수정 후 git add . 한다.

  4. git commit은 하지않는다.(수정 사항이 없으니까)

  5. git rebase --continue를 진행하면 멈춰있던 리베이스가 다시 진행된다.

  6. 충돌이 여러번 나면 그 때마다 충돌을 해결하고
    git add . / git rebase --continue를 반복한다.

  7. 계속 해결이 안될경우, git rebase -- abort로 아예 rebase를 진행 하기 전 상황으로 돌아갈 수도 있다.(하지만 이 명령어를 사용할 때는 작업하던 내용들이 모두 사라지며 돌아갈 수도 있으니 확실하게 알아보고 사용하자.일종의 컴퓨터가 고장났을때 복원시키는방법과 유사한 느낌이다.)

Rebase vs Merge

rebase에 공부하고 복습하는 차원에서 이 글을 작성하긴 하였지만,
무조건 merge 보다 rebase를 사용해야한다고는 생각하진 않는다.

rebase를 사용하는것이 더 적절한 상황에서는 rebase를 사용하고,

merge를 사용하는것이 더 적절한 상황에서는 merge를 사용하는것이다 맞다고 생각한다.

rebase는 무엇이고 어떤역할을 하는지, 어떤 상황에서 써야하는지,

merge는 무엇이고 어떤역할을 하는지, 어떤 상황에서 써야하는지,

각각의 쓰임새를 정확하게 파악하여 알고 적절한 상황에서 알맞게 쓰는 것이 중요하다고 생각한다.

아래 글은 이글을 쓸 때 참고한 git-scm에서 나온 내용이다.
더 자세한 내용은 이글을 참고하길 권장한다.



. Reference

https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-Rebase-%ED%95%98%EA%B8%B0

https://flyingsquirrel.medium.com/git-rebase-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-ce6816fa859d

profile
# 불편함을 편리함으로 바꾸고싶은 주니어 Back-end 개발자

0개의 댓글