2014년 1월 27일 월요일

Concept git rebase and example

오전 6:47 Posted by jonnung 1 comment
git으로 코드의 버전관리를 하면서 브랜치 작업을 많이 하게 되는데 사실 난 브랜치 생성을 좀 즉흥적으로 하는 감이 없지 않아 있다.

무언가 작은 것이라도 개발을 할 때는 브랜치 계획을 어느정도 수립해 놓게 되면 느닷없는 브랜칭으로 커밋 로그가 복잡해지는 일은 없을 것 같는 생각이 든다.

브랜치를 사용하면서 개발을 하다 보면 어느 순간에는 머지(merge)를 하기 마련이다.
그런데 예전에 Git 브랜치 배우기을 해보면서 git에 merge와 결과는 같지만 동작 방식이 다른 리베이스(rebase)라는 기능이 있다는 사실을 알게 되었다.
그때 rebase 예제를 풀어보면서 개념 부족으로 상당히 오랜 삽질을 했던 기억이 난다. 윽..

아무튼 일단 rebase와 merge의 차이에 대한 결론부터 정리하자면 아래와 같다.


Merge는 결과를 합치고

Rebase는 과정을 비교하여 결과와 같이 합친다.

rebase와 merge의 차이를 간략하게 알았다면, 언제 rebase를 써야하는 지가 가장 중요하다.

위에서 말 했듯이 브랜치를 merge 하게 되다보면 히스토리가 복잡해지기 마련이다.
rebase를 사용하면 이런 히스토리를 깔끔하게 정리할 수 있는 효과가 있다고 보면 된다.

간단한 예제를 직접 해보면서 rebasemerge의 차이와 명령어를 좀 더 자세히 알아보겠다.


Base History


일단 merge와 rebase를 비교하기 위해 적당한 히스토리를 만들어 보겠다.
number.txt 라는 새로운 파일을 하나 만든다.
적당히 내용을 입력하고, master 브랜치의 stage영역에 추가(add) 후 커밋(commit)을 했다.
그리고 또 한번 number.txt 파일의 2번 줄의 문장을 변경 하고, 다시 한번 commit을 한다.

123456789
Number content.

이제 2명의 개발자가 각각 브랜치를 만들어 내용을 수정하는 과정을 진행 하겠다.
첫번째 개발자의 브랜치명은 dev-1, 두번째 개발자의 브랜치명은 dev-2로 정했다.

일단 dev-1 개발자가 먼저 파일을 2번 수정하고 각각 2번 commit 했다.

0123456789
Number content!!!

아직까지 dev-2 개발자는 파일을 수정하지 않았다. 그런데 이번에는 master 브랜치에서 파일의 수정이 한번 더 발생 했다. (파일 내용은 생략)

그리고 이제 dev-2 개발자가 자신의 브랜치에서 파일을 수정한다

0123456789
9876543210
10 Numbers contents.

그리고 마지막으로 다시 master 브랜치로 돌아와 새로운 내용을 한번만 더 추가 했다.

123456789
987654321
192837465
Number content.

자 이제 모든 수정이 완료 되었다. 횟수는 적지만 약간 복잡하게 파일 수정이 발생했고, 중간 중간에 master 브랜치의 내용도 수정이 되면서 상황은 점점 악화 되고 있다.

벌써부터 conflict의 그림자가 발밑까지 와있는 느낌이다.

제가 이렇게 히스토리를 만든 이유는 히스토리 그래프를 이해하기 쉽게 만들기 위함과 conflict 발생시 해결하는 과정 그리고 merge와 rebase의 차이점 모두를 담기 위함이 였습니다. 돌 던지지는 마세요. ㅠ_ㅠ)a

현재 상태에서 merge와 rebase를 각각 진행 해보겠다.


Merge


일단 현재 브랜치가 master 인지 확인하고, dev-1 브랜치를 merge 한다.

$ git branch
  dev-1
  dev-2
* master


Cap 2014-01-25 13-27-29-679



$ git merge dev-1

위와 같이 master와 dev-1브랜치 사이에 conflict가 발생했다고 알려준다. 그렇다면 에디터를 열고 number.txt 파일을 원하는 형태로 직접 수정을 해주고 계속 진행을 해야 한다.

<<<<<<<< HEAD
123456789
987654321
192837465
Number content.
=======
0123456789
Number content!!!
>>>>>>> dev-1

'======='을 중심으로 위쪽은 master 브랜치쪽 내용, 아래쪽은 dev-1 브랜치쪽 내용 이다.
123456789
987654321
192837465
Number content!!!

위 결과처럼 dev-1 브랜치의 내용 중 마지막 'Number content!!!'만 병합 하도록 수정 했다.
conflict를 해결하고 머지를 마무리하는 머지 커밋(Merge commit)을 한다.

$ git add number.txt
$ git commit
[master bc64d16] Merge branch 'dev-1'

Cap 2014-01-25 13-58-35-547

그리고 dev-2 브랜치도 위와 동일한 방법으로 master브랜치에 merge 한다.

$ git merge dev-2 
# 에디터에서 Conflict를 해결하고 다시 커밋!

$ git add number.txt
$ git commit
[master 2195143] Merge branch 'dev-2'

Cap 2014-01-25 14-09-07-136


Rebase


이제 rebase를 해보겠다.

이번에는 merge때와 위치하는 브랜치가 다르다는 것을 주의 해야 한다. 아래와 같이 rebase가 되는 토픽 브랜치(Topic)로 checkout 하고 master 브랜치로 rebase를 하도록 명령어를 실행 시킨다.

$ git branch
  dev-1
  dev-2
* master

$ git checkout dev-1
$ git rebase master

Cap 2014-01-25 14-21-04-841



여기서 rebase의 특징이 나오게 된다. Git은 변경 이력을 모두 비교하면서 병합을 시도 하기 때문에 위와 같이 conflict가 발생하는 것을 알려주고 처리 방법을 제안 한다.

123456789
<<<<<<< HEAD
987654321
192837465
Number content.
=======
Number content!!!
>>>>>>> 마침표를 느낌표 3개로 변경

저는 아래와 같이 수정하여 conflict를 해결하고 stage 영역에 올려놓고(add) 다음 rebase를 진행 한다.

123456789
987654321
192837465
Number content!!!


$ git add number.txt
$ git rebase --continue

다음 리비전에서의 conflict도 위와 동일한 방법으로 해결하고 계속 rebase를 진행 한다.

$ git add number.txt
$ git rebase --continue


$ git rebase --skip

Cap 2014-01-25 14-32-27-288
$ git checkout master
$ git merge dev-1

Cap 2014-01-25 14-32-56-525



dev-2 브랜치에 대해서도 위와 동일한 방법으로 master 브랜치에 rebase 한다.

$ git checkout dev-2
Switched to branch 'dev-2'

$ git rebase master


$ git add number.txt

$ git rebase --continue


$ git add number.txt
$ git rebase --continue
Applying: 더 자세한 내용 정의 문장으로 수정


$ git checkout master
Switched to branch 'master'


$ git merge dev-2
Updating bad6d94..258c855
Fast-forward
number.txt | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

Cap 2014-01-25 14-39-35-832

이제 필요 없어진 dev-1과 dev-2 브랜치는 삭제 한다.

$ git branch -d dev-1 dev-2
Deleted branch dev-1 (was bad6d94).
Deleted branch dev-2 (was 258c855).

Cap 2014-01-25 14-40-00-703

위에서 각각 해 본 rebase와 merge는 결과는 같지만 보여지는 커밋 트리들의 차이가 있는 것을 알 수 있다.

댓글 1개: