Git

GIT - cherry-pick & rebase

마닐라 2021. 9. 22. 18:53

cherry-pick은 특정한 커밋 하나만 픽업해서 다른 커밋 뒤에 붙일 수 있는 기능이다.

rebase는 두 개의 다른 브랜치가 병렬적으로 표시된 것을 일렬로 보이게 하여 보는 사람으로 하여금 이 작업이 어떻게 진행되었는지를 훨씬 더 직관적으로 표현할 수 있는 기능이다.

base가 공통의 조상이므로 rebase는 해당 브랜치의 조상을 바꾼다는 의미이다.

 

커밋들의 순서와 관계를 마음대로 조정하게 해준다.

 

git의 상태를 그림으로 표현

 

git rebase

 

 

git log

 

t2에서 작업한 내용을 m2에도 적용시키고 싶을 수도 있다.

그걸 가능하게 하는게 cherry-pick 이다.

 

git cherry-pick 명령어

 

 

위와 같이 git cherry-pick 뒤에 픽업하고 싶은 커밋의 아이디를 적으면 t2에서 작업했던 내용인 t2 파일의 추가라는 내용이 m2에 적용된 걸 확인할 수 있다. 그리고 로그를 다시 확인해보면 m1, m2라는 메세지를 가진 커밋이 위로 올라오고 그 위에 t2라는 메세지를 가진 커밋이 새롭게 하나가 더 추가가 된다.

파일은 init.txt, m1, m2, t2 총 4개가 된다.

 

git rebase 명령어

master 브랜치에서 t3를 rebase 명령어로 실행시키면 원래 master 브랜치의 base였던 init이 t3으로 변경이 된다.

파일같은 경우도 init과 t3브랜치의 t1,t2,t3 작업 내용이 m2로 합쳐지게 된다.

파일은 init.txt, t1, t2, t3, m1, m2 총 6개가 된다.

원래 topic 브랜치의 t3와 master 브랜치의 m2가 가리키는 공통의 조상(base)이 init 이었는데, 이제는 t3는 기존대로 init이 base이고 m2는 t3이 base가 된 것이다.

 

같은 상태에서 cherry-pick, rebase를 진행했을 때 차이점이 명확하게 드러나고있다.

cherry-pick은 새로운 커밋이 추가가 되고 rebase는 현재 브랜치에 해당 내용을 적용시키는 것이다.

 

merge 와 rebase의 차이

 

rebase를 할 수 있는 시기는 버전들이 push 하기 이전이다..

현재 그림에서 merge와 rebase의 결과로 만들어진 mt3와 m2의 결과는 과정만 다르고 내용은 완전히 같다.

 

그리고 cherry-pick과 rebase는 서로 다르기 때문에 충돌 상황에서의 해결 방법도 서로 다르다.

 

먼저 cherry-pick 충돌 상황이 나게 하기위해 같은 파일에 대해서 수정 작업을 했다.

그리고 master의 m3 버전에서 t3 버전의 변경 사항만을 cherry-pick 할 것이다.

 

 

cherry-pick을 하려고 하면 같은 파일의 같은 라인을 수정했기에 충돌이 일어난다.

 

 

툴을 이용해서 보면 왼쪽의 현재의 버전이고 가운데가 cherry-pick 대상의 이전 버전이고 오른쪽이 cherry-pick 대상이다.

2,3번째에서는 변경내역이 t3밖에 없고 현재의 버전에서 해당 라인에는 m2가 들어가 있어서 t2를 작업하지 않은 cherry-pick 대상에 있는 t2 보다 현재 버전의 m2가 우세하다고 판단을 내려서 m2를 채택한 상태다.

문제는 cherry-pick 대상의 된 버전에서의 t3와 현재 버전의 m3이다.

이 부분은 어떤식으로 할지 처리를 해주어야 한다.

 

그리고 충돌을 해결 했다는 git cherry-pick --continue 라는 명령어를 이용해서 충돌을 해결했다고 git에게 알려야한다.

 

rebase같은 경우에는 git은 일단 HEAD를 옮긴다.

master를 rebase한다고 하면 rebase하고 싶은 곳으로 HEAD를 옮긴다.

그리고 master 이전 버전과 변경된 현재 HEAD와 base를 비교한다.

master 이전 버전과 변경된 현재 HEAD에서 충돌이 일어날 수 있다.

 

git rebase conflict 과정1

 

git rebase conflict 해결1

 

master 이전 버전에서 conflict는 해결이 됐지만 master 버전에서도 충돌이 날 수 있다.

 

git rebase conflict 과정2
git rebase conflict 해결2

 

 

툴을 이용해서 보면 가운데가 base이다.

master에서 m2가 추가되고 topic에 t2가 추가 됐으므로 이 부분에서 conflict가 일어난다.

해결을 해주고나서 git rebase --continue를 입력해준다. conflict1은 해결 됐으나 conflict2가 남았다.

 

 

첫번째의 해결 conflict 문장인 mt2가 m2 대신 그대로 채택되었고 이번에는 master 버전에서 추가한 부분인 m3와 t3가 충돌이 났다.

해결을 해주고 나서 git rebase --continue를 입력해주면 conflict가 모두 해결돼서 HEAD가 다시 master를 가리키면서 m3 버전이 된것을 확인할 수 있다.

 

git log의 변화1

 

첫번째 로그는 rebase를 입력했을 때 HEAD가 topic으로 바뀌는 것을 보여주고

두번째 로그는 conflict를 한번 해결되고 나서 m2로 HEAD가 변경된 것을 보여주고

세번째 로그는 conflict가 두번 해결되고 나서 원래 버전인 m3 메세지와 HEAD가 master를 가리키고 있음을 보여주는 로그이다.

 

git log의 변화2

 

로그를 확인해보면 conflict 해결시에 수정한 mt2와 mt3 라는 내용이 각각의 해당 master 버전과 master 이전 버전에 들어가게 된다.

 

그리고 로컬브랜치와 원격브랜치에 대해서도 숙지할 필요가 있다.

 

위 로그에서 origin/master가 원격브랜치를 가리키고 HEAD -> master가 현재 로컬브랜치를 의미한다.

현재는 commit만 하고 push는 하지 않았기 때문에 원격 브랜치가 1버전 아래로 표시가 된다.

 

그리고 다른 컴퓨터에서 pull이 아니라 fetch라는 명령어로 받아오면 아래와 같이 원격 브랜치가 위에 있고 로컬 브랜치가 아래에 있다.

 

git fetch 명령어

 

로컬브랜치와 원격 브랜치를 동일하게 맞춰주기 위해서는 merge 명령어를 사용하면 된다.

 

git merge 명령어

 

그리고 서로 하나의 원격 브랜치에서 각자 다른 작업을 하고있을 때 병렬적으로 커밋이 많이 생기게 된다.

작업 중에 다른 사람이 push를 했을 경우 fetch 명령어를 사용하게 되는데 로그는 아래와 같다.

 

git fetch 명령어

 

그리고 merge 명령어로 병합을 하면 merge commit이라는 버전으로 커밋이 하나더 생성이 된다.

 

git log 명령어

 

병렬적으로 표시되는 것들이 많아지면 로그를 확인하기가 어려워진다.

 

git log 명령어

 

위와 같이 merge 명령어를 사용해서 해결은 할 수 있겠지만 병렬적으로 표시되는 것을 막진 못한다.

이 때 로그를 깔끔하게 해주기 위해서는 git rebase를 사용하면 된다.

 

git rebase 명령어

 

 

'Git' 카테고리의 다른 글

GIT - reset & revert  (0) 2021.09.23
GIT - branch & conflict  (0) 2021.09.21
GIT - backup  (0) 2021.09.20
GIT - Version Control  (0) 2021.09.19