[Troubleshooting] - Git rebase 시 중복 커밋 존재

청주는사과아님·2024년 11월 7일
0

Troubleshooting

목록 보기
1/7

프로젝트를 진행하던 중 git rebase 시 중복된 커밋이 존재 하는 상황을 맞이하였고, 이 원인과 해결하는 방법을 설명하고자 합니다.


📝 상황 설명

다수의 인원이 동시에 개발하다보면 종종 현재 개발중인 특정 기능들이 필요한 상황이 발생하곤 합니다.

저희 프로젝트의 경우 Controller 구현 중, 이전 commit 의 취약점을 발견해 Service, Persistence 계층의 규약 (interface) 이 변경되는 상황이 있었습니다.

저는 이 때 rebase 를 유용하게 사용한다 들었습니다. 현 브랜치의 base commit 을 변경해 필요한 commit 위에 현 브랜치를 다시 세울 수 있기 때문입니다.

그래서 rebase 를 진행했지만 아래 그림처럼 예상치 못한 상황을 맞이하였습니다.

위 그림을 보면 필요한 commit(초록색) 이 포함되긴 했지만, rebase 이전의 commit(빨간색) 이 중복된 것을 알 수 있습니다.

그래서 제가 rebase 를 잘 못 알고있는 건가 헷갈렸고 위 현상의 원인을 분석하였습니다.


❗️원인 분석

결론부터 말하자면 rebase 의 개념을 잘 못 알고 있는 것은 아니었습니다.
다만 Local 에서의 rebase 가 반드시 remote 에서의 rebase 로 이뤄지는 것은 아니었습니다.
(한마디로 Local 과 Remote 는 "다른 것" 임을 까먹었던 것...)

다음과 같은 상황을 생각해 보겠습니다.

저희는 개발하며 commit a1, 2, 3 를 생성해 remotepush 하였습니다. 그런데 작업 도중 다른 브랜치의 T1, T2 가 필요함을 느껴 Another Branchrebase 를 하고자 합니다.

우리가 rebase 를 진행할 때는 대게 git bashIDE 의 도움을 받습니다.

그런데 이들의 동작 그 자체는 remote branch 에 적용되지 않고 오직 local branch에서만 작용합니다.
즉, 우리가 개발하며 remote branch 에 영향을 주는 행동은 commitpush 할 때 뿐입니다.

그래서 LocalAnother Branch 위에 rebase 하면 Local 은 위 그림처럼 "새로운 형태" 를 갖게 됩니다.

문제는 LocalA1, A2, A3 commit 은 기존 a1, a2, a3 와 다른 commit 이라는 점 입니다.
commit 의 식별자로 사용되는 SHAcommit 생성 시각, 변경점, 생성자 등 다양한 정보를 포함해 생성됩니다.
즉, A1, ...a1, ... 은 모두 같은 변경점을 담고 있지만 서로 다른 commit 인 것입니다.

이 점이 문제되는 원인입니다. 확실히 Local 에서는 rebasea1, a2, a3 가 사라지고 A1, A2, A3 가 새로 만들어지는 것은 어떠한 문제가 되지 않습니다.

하지만 Remote 어떨까요?
RemoteLocal 에서 push 시에만 변경되니 Remote 에는 기존 커밋 a1, a2, a3 가 그대로 남아 있습니다.
때문에 Localrebasepush 를 진행하면 Remote 위 그림의 형태를 갖게 됩니다.

즉, 우리 눈에는 중복된 commit 으로 보였지만, Remote 입장 에서는 확연히 다른 commit 들이었던 것 입니다.


✅ 문제 해결 방법

결국 문제의 원인은 a1, a2, a3A1, A2, A3 가 다른 commit 이었기 때문에 발생했습니다.
이 원인을 파악했으므로 이를 해결하는 방식은 매우 다양합니다.


I. Rebasepush --force

push --force 를 이용할 경우 현재 Local branch 의 형태 그대로 Remotepush 하게 됩니다.
때문에 Remotea1, a2, a3 는 삭제되고 T1 -> T2 -> A1 ... 형태로 Remote 가 변화됩니다.

이 방법은 가장 강력하지만 (당연하게도) 아주 조스럽게 행해져야 합니다. Remote 의 형태를 확인도 없이 변경하기 때문입니다.
때문에 이는 Remote 에서 여러명이 작업하거나 Rebaseconflict 이 일어날 경우 그렇게 추천하지 않습니다.


II. Rebase 대신 Cherry pick or Merge

애초에 Rebase 를 사용하지 않는 방법 또한 존재합니다. 우리 Rebase 의 목적은 특정 기능이 포함된 commit 이 필요했기 때문 이었습니다.

그래서 꼭 필요한 commitCherry pick 하거나 LocalAnother BranchMerge 하는 것으로도 목적은 달성됩니다.

특히 Merge 는 브랜치간 병합이 일어났다는 commit 을 남길 수 있어 추후 commit tracking 에 용이할 수 있습니다.


III. 새로운 Local branch 에서 rebase & push

아니면 Remote 와 동일한 새로운 Local-2 브랜치를 만드는 방법도 존재합니다.

새로운 Local-2 브랜치를 만들게 되면 (이름 그대로) 로컬 브랜치이기 때문에 아직 Remote-2 브랜치가 존재하지 않습니다.
때문에 Local-2 브랜치에 Target branchRebase 하면 git fast-forward 로 인해 A1, A2, A3 같은 "새로운 commit" 이 생성되지 않습니다.

물론 처럼 진행할 경우, Remote-1, Remote-2 2 개의 브랜치가 저장소에 만들어질 것입니다.


어떤 방법이든 말 그대로 방법이 다를 뿐 목적은 동일합니다.
각자 현재 놓여진 상황에 따라 어느 방법이든 잘 선택해 사용하면 될 듯 합니다.

개인적인 추천은 2 번


📝 Reference

profile
나 같은게... 취준?!

0개의 댓글