본문 바로가기

Git

Rebase

한 브랜치에 다른 브랜치의 내용을 적용시키려면 흔히들 쓰는, 그리고 내가 지금까지 쓰던 명령어는 Merge 이다.

 

Master 브랜치에 내 작업내용 PR 을 적용시키려면, Merge 명령어를 썼다.

 

그리고 Master 의 변경내용을 내 작업브랜치에 적용시킬때는 pull ( 원격 저장소의 내용을 가져오는 Fetch + Merge) 를 썼다.

 

 

오늘은 코드를 깔끔하게 병합할 때 쓰는 Rebase 라는 명령을 알아보도록 한다.

 

 

 

 


 

 

내가 깃을 이용한 협업과 gitflow라는 개념을 처음 알게 되었던 글은 우아한 형제들의 블로그였는데, 

https://techblog.woowahan.com/2553/

 

우린 Git-flow를 사용하고 있어요 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요. 우아한형제들 배민프론트개발팀에서 안드로이드 앱 개발을 하고 있는 나동호입니다. 오늘은 저희 안드로이드 파트에서 사용하고 있는 Git 브랜치 전략을 소개하려고 합

techblog.woowahan.com

 

당시에는 그 글에서의 Rebase 가 어려워서 넘어갔던 기억이 든다.

 

Rebase, Squash 등을 이용해서 깃의 로그를 깔끔하게 하는 방법을 알기 위해 Rebase 라는 것에 먼저 공부를 해본다.

 

 

 


 

Rebase

git 에는 HEAD 라는 포인터가 있다.

이 포인터는 현재 작업중인 커밋을 가리킨다.

다르게 말하면, 내가 작업할 커밋에 HEAD 를 놓게 되는 것이다.

우리는 어떠한 작업을 할때, 항상 HEAD 가 가르키는 커밋에서 작업을 이어간다.

 

rebase 명령은 이 HEAD 를 re - base 재 배치하는 명령이다.

 

이를 기억하면서 Rebase 로 병합하는 과정을 거쳐보자.

그리고 Rebase 를 하지 않고, 그냥 Merge 도 해보면서 차이를 보자.

 

 

 

1. 일반적인 Merge

c 는 commit 의 약자. 숫자는 커밋한 시간적 순서에 따라 지정.

Master 브랜치에서 C1이 커밋된 시점에 내가 Branch1 이라는 이름으로 브랜치를 따서 C3 이라는 작업을 커밋했다.

 

그리고 내가 작업하는 사이 C2 의 커밋이 마스터에 적용되었다. (Conflict 는 없다 치자.)

 

이후 내 브랜치도 Master 에 적용시키고 싶을때 아래의 명령어를 사용한다.

 

// 현재 내 작업 브랜치에서 작업하고 있을테니 checkout
$ git checkout master
$ git merge Branch1

 

git GUI 의 로그처럼 그렸다. 한칸에 하나씩 시간적인 순서로 로그를 찍으니까.

 

브랜치에서 작업한 C3 의 내용을 마스터가 이제 보고 있게 되었고, 변경 사항이 잘 적용 되었다.

 

 

하지만

  • 지금은 브랜치가 한개지만, 브랜치가 여러개라면?
  • 지금은 브랜치에서 작업한 내용이 한개지만, 수십 커밋한 브랜치를 병합하면?

길~고 복잡한 깃 로그를 가지게 될 것이다.

 

이에 도움을 줄 수 있는 방법이 Rebase 이다.

 

 

 

 

2. Rebase

다시 아까의 처음 상태로 돌아가보자.

c 는 commit 의 약자. 숫자는 커밋한 시간적 순서에 따라 지정.

 

이번에는 작업 브랜치가 master 로 옮기지 말고 branch1 인 상태에서 아래 명령어를 실행한다.

 

$ git rebase master

결과를 그림으로 먼저 보자면 아래와 같다.

 

이 명령어를 친걸 직접적으로 해석해보면 다음과 같을 것이다.

"master 브랜치를 branch1 브랜치에 rebase 해라!"

 

내부적으로는 아래와 같은 일이 일어난다.

  1. 두 브랜치가 나뉘기 전 공통 브랜치 C1 로 이동.
  2. 공통 브랜치 C1 에서 현재 브랜치의 C3 까지의 Diff 를 임시 저장.
  3. Branch1를 master 가 있는 곳을 가리키게 이동.
  4. 아까 임시 저장한 C1-C3 의 Diff 커밋들을 적용.

곰곰히 생각해보면 위의 그림이 결과로 나온다.

 

 

이후 master 브랜치로 이동해서 master 를 merge 한다.

$ git checkout master
$ git merge branch1

Branch1 을 Master 브랜치로 병합할때, Branch1 의 이력은 rebase 로 인해 Master 의 이력을 그대로 가지고 있다.
따라서, Master 브랜치로 병합할때, Master 가 가리키는 방향만 그대로 옮기면 된다.

이런 병합을 Fast-Forward 병합 이라고 한다.

 

작업내용을 병합한 결과가 위의 Merge 만 사용한 것과는 다르게 한줄로 간단하다.

또 merge 커밋 하나도 줄었다.

 

이런 식으로 간단한 깃 로그를 만들 수 있다.

 

 

 

 

 

 

3. Rebase 시 충돌 - continue

c 는 commit 의 약자. 숫자는 커밋한 시간적 순서에 따라 지정.

이 상황에서 C2, C3 가 같은 부분을 수정하여 Conflict 가 발생할 수 있다.

 

 

그때는, merge 시 충돌처럼 충돌부분을 적당히 수정하고, 수정부분을 스테이징하는 것 까진 똑같지만

 

commit 으로 적용하는 것이 아니다.

 

$ git add .
$ git rebase --continue

 

 

 

 

 

4. Rebase Checkout 하지 않고 간단히 쓰기.

c 는 commit 의 약자. 숫자는 커밋한 시간적 순서에 따라 지정.

우리는 이 상황에서 아래와 같이 rebase 했다.

  1. branch1 로 Checkout 
  2. master rebase
  3. master 로 Checkout
  4. branch1 merge
$ git checkout branch1
$ git rebase master
$ git checkout master
$ git merge branch1

 

 

굳이 checkout 을 하지 않고 한줄로도 가능하다.

$ git rebase <basebranch> <topicbranch>

토픽(server) 브랜치를 Checkout 하고 베이스(master) 브랜치에 Rebase 한다.

쉽게 말해서, 로그상으로 생각해봤을때, 적혀진 순서대로
<basebranch>-<topicbranch> 가 된다.

 

 

따라서, master 브랜치에서

$ git rebase branch1 master

를 하게 되면,

가 된다. 대신, 시간 순서대로 커밋이 정렬되지 못한다.

 

 

반대로, branch1 브랜치에서

$ git branch master branch1

을 하게 되면,

가 된다. master 브랜치로 checkout 후 fast-forward merge 를 해야 할 것이다.

 

 

 

 

5. Rebase 시 주의점.

이미 공개 저장소에 Push 한 커밋을 Rebase 하지 마라

Rebase 명령은 사실, 변경사항은 같지만 다른 커밋을 만든다.

 

변경사항을 복사해서 새로운 커밋을 만든다라고도 할 수 있겠다.

 

따라서, 공개 저장소에 이미 올라간 커밋을 가져와서 Rebase 하면, 새로운 커밋들로 이루어진 로그를 만들게 된다.

 

이를 다시 공개저장소에 push 하려면, force 명령어를 써서 하게 될 텐데, 이렇게 올려버리면 문제가 생기는 것이다.

 

왜냐면, 이미 공개 저장소에 올라간 커밋들을 팀원들은 쓰고 있을텐데, 새로운 커밋으로 구성된 브랜치를 내가 강제로 올려버리면 다른 팀원들은 merge 할때 문제가 생기기 때문이다.

'Git' 카테고리의 다른 글

squash 머지 한 브랜치에서 계속 작업할 경우  (0) 2021.10.06
upstream vs origin  (0) 2021.10.06
.gitignore  (0) 2020.12.11
Commit Convention  (0) 2020.11.30
Git .gitignore 이용하기  (0) 2020.11.23