[Git] 묵은 커밋을 새 커밋으로 이력 조작하기(rebase)

2022. 4. 20. 15:14Git

rebase의 필요성

컨트리뷰터가 된 너구리는 '티셔츠 찜하기' 기능을 코딩하였습니다. 그리고 풀 리퀘스트를 보냈지만 코드 충돌이 발생하였습니다. 이때 내 브랜치로 먼저 병합을 하고 충돌을 해결한 다음 다시 풀 리퀘스트를 보내면 충돌이 발생하지 않을 것입니다. 하지만 그러면 풀 리퀘스트에서 내가 추가한 코드 이외에도 충돌을 해결하느라 생긴 병합 커밋이 발생할 것입니다. 이를 해결하기 위해서 rebase 기능이 필요합니다.

 

실습 계정 정보

  • yonghwankim-dev : git_study 원격저장소 소유자 역할, iTshirt-cat 폴더를 사용함
    • 본계정이라고 지칭
  • yonghwankim-dev2 : git_study 원격저장소를 포크한 기여자 역할, iTshirt-raccoon 폴더를 사용함
    • 부계정이라고 지칭

 

1. 원본저장소에 새로운 커밋이 있는데, 포크한 내 원격저장소에는 안 보여요!

실습 내용은 본계정의 원본저장소와 부계정의 원격저장소가 서로 같은 코드를 고쳐서 병합할때 충돌이 발생하는 상황을 만들겠습니다.

 

1.1 [부계정], iTshirt-raccoon/like.md 파일 수정

1.2 [부계정], iTshirt-raccoon/like.md 파일을 커밋 및 푸시

1.3 [본계정] iTshirt-cat 로컬 저장소 pull 수행

1.4 이제 부계정의 like.md 파일과 충돌이 나는 상황을 발생시키기 위해서 소스트리의 계정 설정을 본계정으로 변경

1.5 [본계정], iTshirt-cat/like.md 파일 수정

1.6 [본계정], iTshirt-cat/like.md 커밋 및 푸시

1.7 [본계정], iTshirt-cat/hello.txt 수정

1.8 [본계정], iTshirt-cat/hello.txt 커밋 및 푸시

본계정의 원본저장소에서 커밋을 두개 푸시하였고 부계정의 원격저장소에서도 like.md 파일을 수정하여 푸시하였으므로 부계정의 원격저장소에서 본계정의 원본저장소로 pull request를 전송합니다.

 

1.9 GitHub 부게정(yonghwankim-dev2)으로 로그인하여 git_study 원격저장소에서 New pull request를 클릭합니다.

위의 그림을 보면 부계정이 포크한 원격저장소에서 푸시한 커밋을 원본저장소에 pull request하려 했지만 코드가 충돌이 발생한 것을 확인할 수 있습니다.

 

2. 여러 원격저장소 히스토리를 한눈에 보기 : 리모트 추가(Add remote)

리모트 추가의 필요성

부계정은 본계정의 원본저장소를 포크하여 새로운 원격저장소를 생성하였습니다. 그래서 부계정은 포크한 시점까지의 모든 히스토리는 부계정이 알 수 있었지만 그 다음에는 원본 저장소에 무슨일이 일어났는지 확인할 수 없었습니다. 왜나하면 원본저장소와 포크한 원격저장소는 주소까지 바뀐 서로 다른 원격저장소가 되었기 때문입니다. 하지만 포크한 내 원격저장소에서 원본 저장소의 히스토리도 함께 보고 싶다면 리모트 추가가 필요합니다.

 

이전장까지의 원본저장소와 부계정의 원격저장소의 히스토리는 다음과 같습니다.

 

소스트리가 원본저장소와 원격저장소를 동시에 추적하면 다음과 같이 됩니다.

 

2.1 소스트리에서 부계정으로 변경합니다.

2.2 [부계정] iTshirt-raccoon 탭 이동 -> 저장소 -> 원격 저장소 추가 버튼 클릭 -> 왼쪽 하단 추가 버튼 클릭

2.3 [부계정] 원본 저장소 정보 입력 -> 확인

원격 저장소를 지칭하는 관용적인 닉네임을 upstream이라고 합니다.

2.4 upstream 오른쪽 버튼 클릭 -> [upstream 에서 가져오기] 메뉴 클릭 (패치)

 

3. 묵은 커밋을 방금 한 커밋처럼 : 리베이스(Rebase)

포크한 원격저장소에서 원본저장소로 풀 리퀘스트를 전송했을때 충돌이 발생하면 두가지 방법이 있습니다.

  • 첫번째 방법, 현재 커밋과 병합하고 싶은 커밋을 미리 내 브랜치에서 병합해서 병합 커밋을 만들고(병합 커밋을 만들어 코드 충돌을 해결한 커밋) 풀 리퀘스트를 보내는 방법
    • 첫번째 방법의 아쉬운 점은 충돌을 해결하고 풀 리퀘스트를 보내면 충돌을 해결한 병합 커밋의 이력이 남는 아쉬움이 있습니다. 나의 변경점은 커밋 1개 뿐이지만 충돌을 해결하느라 쓸데없는 충돌 해결한 병합 커밋이 더 늘어난 것입니다.
  • 두번째 방법, 리베이스를 사용하여 묵은 커밋을 방근한 커밋처럼 이력을 조작하는 방법

첫번째 방법을 그림으로 표현하면 다음과 같습니다. 아래 그림은 1번 커밋과 2번 커밋을 병합하려고 하니까 충돌이 발생한 상황입니다.

위와 같은 상황에서 충돌을 해결한 병합 커밋을 부계정의 원격저장소에 올리면 다음과 같은 그림으로 표현이 가능합니다.

위와 같이 충돌을 해결한 3번 커밋은 풀 리퀘스트를 보내서 2번 커밋과 병합이 가능합니다. 하지만 위와 같이 수행하면 병합 커밋(3번)의 이력이 남아서 아쉬움이 듭니다. 이러한 경우 두번째 방법을 사용합니다.

 

 

두번째 방법은 묵은 커밋을 방금 한 커밋처럼 이력을 조작합니다. 이러한 행위를 리베이스(Rebase)라고 합니다.

다음 그림에서 0번 커밋을 베이스로 1번 커밋을 생성하였습니다. 0번 커밋이 옛날 커밋이어서 최신 커밋인 2번 커밋과 병합하려면 충돌이 발생합니다. 하지만 만약 1번 커밋이 0번 커밋이 아니라 2번 커밋을 베이스로 만들었다면 어떻게 되는가? 결과는 빨리 감기(Fast-forward) 병합이 되는 상태가 될 것입니다. 이렇게 커밋의 베이스를 뚝 떼서 다른 곳으로 붙이는 것이 리베이스(rebase, 베이스를 다시 잡다)입니다. 두번째 방법을 사용하면 병합 커밋이 생기는 앞의 방법과는 달리 병합 커밋의 이력을 남기지 않고 풀 리퀘스트를 보낼 수 있습니다.

 

 

3.1 [부계정], 소스트리 iTshirt-raccoon 탭의 그래프 확인

부계정의 원격저장소의 찜하기 기능 추가 커밋의 베이스 커밋이 '좋아요 기능 추가' 커밋인 것을 확인할 수 있습니다.

 

3.2 새로운 베이스로 삼고 싶은 커밋인 '개발자 목록에 너구리 추가' 커밋을 클릭 -> 오른쪽 마우스 버튼 -> 재배치(리베이스) 버튼 클릭 -> 확인 버튼 클릭

위 경고는 리베이스를 하려면 다른 개발자가 이 변경사항을 사용하고 있지 않아야 한다는 의미입니다. 현재 있는 부계정 원격저장소의 main 브랜치를 부계정 혼자만 사용하는 것이냐고 묻는 것입니다. 리베이스는 히스토리를 강제로 조작하기 때문에 다른 사람이 만약 이 히스토리를 보고 있다면 꼬이고 말것입니다. 그렇기 때문에 리베이스는 반드시 혼자만 쓰는 브랜치에서 수행해야 합니다.

 

베이스 커밋으로 삼고자 하는 커밋('개발자 목록에 너구리 추가')과 붙이고자 하는 커밋('찜하기 기능 추가') 커밋간의 코드 충돌이 발생했다는 경고문입니다. 닫기를 클릭하고 코드 충돌을 해결해야 합니다.

 

3.3 [부게정] iTshirt-raccoon/like.md 코드 수정

before

after

 

3.4 소스트리에서 충돌이 해결된 파일인 like.md 파일을 스테이지에 올립니다.

 

3.5 다시 베이스 커밋으로 하고 싶은 '개발자 목록에 너구리 추가' 커밋을 대상으로 재배치를 진행합니다. 액션 탭-> 재배치 계속 버튼 클릭

 

3.6 리베이스 결과 확인

위 결과를 보면 [부계정]의 로컬 저장소의 main 브랜치의 '찜하기 기능 추가 커밋'의 베이스 커밋이 '개발자 목록에 너구리 추가' 커밋이 된 것을 볼 수 있습니다. 하지만 위의 결과를 보면 부계정의 원격저장소의 main 브랜치의 베이스 커밋이 아직도 '좋아요 기능 추가' 커밋을 가리키고 있는 것을 볼 수 있습니다. 이는 아직 로컬 저장소의 main 브랜치가 원격 저장소로 푸시하지 않았기 때문입니다.

 

3.7 [부계정] 로컬 저장소의 main 브랜치 푸시 수행

이 단계에서 주의할 점은 리베이스는 이력을 조작하는 행위이기 때문에, 일반 푸시로는 수행할 수 없습니다. 강제 푸시를 수행해야 합니다.

 

3.7.1 소스트리 도구 탭 -> 옵션 -> Git 탭 -> 강제 푸시 가능 체크박스 체크 -> 확인

 

3.7.2 push 버튼 클릭 -> 강제 푸시 선택 -> push 버튼 클릭

충돌을 리베이스로 해결하였으므로 부계정의 원격저장소에서 본계정의 원본저장소로 풀 리퀘스트를 보냅니다.

 

3.8 Github 부계정, git_study 원격저장소 이동 -> pull request 탭 -> New Request -> create pull request 클릭

3.9 Github 본계정, git_study 저장소 이동 -> pull request 탭 -> 들어온 pull request 클릭 -> Merge pull request 버튼 클릭 -> Confirm Merge 버튼 클릭

 

 

3.10 GitHub 본계정 git_study 원본 저장소의 like.md 파일 확인

 

References

source code : https://github.com/yonghwankim-dev/git_study
                  https://github.com/yonghwankim-dev2/git_study
팀 개발을 위한 Git Github 시작하기, 정호영 진유림 저