CS/Git & Github

[Git] Squash and Merge 후 Rebase를 할 때 발생하는 문제

Tigris 2022. 4. 26. 18:43

Squash and Merge(이하 Squash Merge) 이후 Branch간 충돌로 인해 Rebase가 불가능한 경우가 있습니다. 충돌이 일어나는 이유와 해결 방법을 알아보겠습니다.

문제 상황

우선 Branch1에서 B, C commit 이후 다른 작업을 위해 Branch2를 만든 후 Branch 별로 각기 다른 작업을 진행했다고 가정하겠습니다.

그림1

Branch1의 작업이 끝나 Squash Merge 후 Main 브랜치를 Fast-Forward했습니다.

그림2

Branch2도 작업이 끝났습니다. 깔끔한 Commit history를 위해 Rebase를 진행하려고 합니다.

git checkout branch2
git rebase main

 

그림3

이렇듯 의식의 흐름대로 Rebase를 진행하면 여러분은 빨간색 글씨로 적힌 충돌 메세지를 맞이하게 되실 겁니다. 😫

문제 원인

Rebase는

  1. 두 Branch 사이의 공통 조상을 찾고,
  2. 공통 조상으로부터 Rebase할 Branch 내의 Commit들 사이의 변경사항을 저장해둔 후,
  3. Base가 될 Commit부터 2번에서 저장해둔 변경사항을 차례대로 적용합니다.

저희가 사용한 방식은 두 Branch 사이의 공통 조상이 C이니 Base Commit(G)부터 D와 E, E와 F 사이의 변경사항이 차례대로 적용될 것이라는 생각을 기반으로 합니다. 하지만 다시 한 번 생각해보면 Squash Merge 이후에 Branch1과 관련된 정보는 모두 G라는 Commit 하나에 담기지만, 외부에서는 G라는 Commit이 B와 C라는 Commit을 포함하고 있다는 사실을 알 방법이 없습니다. 그렇기 때문에 Git은 Rebase를 할 때 C가 아닌 A를 두 Branch의 공통 조상으로 인식하게 됩니다. 따라서 아래 그림4와 같이 이미 B, C Commit이 담긴 G Commit 이후에 다시 B, C Commit을 적용하게 되어 충돌이 발생하게 되는 것입니다.

그림4

해결 방법

간단하게 생각해보면 저희는 이미 G Commit이 B, C Commit을 포함하고 있는 것을 알고있기 때문에 Branch2에서 Rebase를 할 Commit을 E, F로만 한정한다면 위 문제를 해결할 수 있을 것 같습니다. 다행히 Git에서는 —onto라는 옵션을 통해 현재 HEAD를 포함한 N개의 Commit만 Rebase를 수행할 수 있습니다. 위 경우 Branch2의 HEAD인 F를 포함해 2개의 Commit만 Rebase할 때 이용하면 되기 때문에 아래 명령어를 통해 Rebase를 진행할 수 있습니다.

git rebase --onto main HEAD~2

만약 Squash Merge 이후에도 Branch1을 삭제하지 않은 경우 Commit 범위를 직접 지정하는 대신 아래 명령어를 통해 Main branch를 기준으로 Branch1에 존재하지 않으면서 Branch2에는 존재하는 Commit들만을 rebase해줄 수 있습니다.

git rebase --onto main branch1 branch2

잘못된 내용, 오타, 부정확한 문장 등 어떤 피드백이든 환영합니다. 감사합니다.


References

https://vagabond95.me/posts/git-rebase-onto/