(git) rebase의 함정

rebase를 하면 안되는 상황
“다른 동료가 작업 중인 외부에 공개 된 저장소 브랜치를 대상으로 리베이스하면 안된다.”
- 초기상태
나와 동료가 같은 브랜치에서 작업중이다.
A—B—C (origin/main)
- 각자 작업 시
나: C에서 시작해 D와 E 커밋을 만들었다.
동료: C에서 시작해 X와 Y 커밋을 만들었다.
당신: A---B---C---D---E (local)
동료: A---B---C---X---Y (local)
원격: A---B---C (origin/main)
- 동료가 먼저 푸시
동료가 먼저 작업을 완료하고 푸시했다.
당신: A---B---C---D---E (local)
원격: A---B---C---X---Y (origin/main)
- 🔥 내가 Rebase를 사용 🔥
나는 최신 변경 사항을 반영하기 위해 rebase를 사용했다.
# 이전
A---B---C---D---E (local)
# rebase 후
A---B---C---X---Y---D'---E' (local)
D’와 E’는 D와 E와 같은 변경사항이지만 새로운 해시값을 가진다.
- 강제 푸시
내가 강제로 푸시하면
원격: A---B---C---X---Y---D'---E' (origin/main)
- 문제발생
다른 동료들이 git pull을 하면 혼란스러운 상황이 발생한다.
이미 X,Y를 기반으로 작업중이던 사람들은 충돌이 발생한다.
히스토리가 재작성되어 추적이 어려워진다.
대안 : merge를 사용한다.
4번에서 rebase가 아닌 merge를 사용했다면,
# merge 후
D---E
/ \
A---B---C---X---Y---M (local)
모든 커밋이 보존되고 병합커밋 (M)이 생성된다.
원래 커밋 해시가 유지되어 히스토리 추적이 가능해진다.
결과
이미 원격저장소(origin)에 push한 커밋들을 rebase하는 것을 지양하고 merge를 사용하자.
rebase는 내용은 같지만, 새로운 해시를 가진 커밋을 생성한다.
*rebase 이후 push가 되지 않는 이유
동료가 작업한 최신사항을 반영하기 위해 나의 local/main 에서 git pull을 받고, 작업 브런치로 이동해 git rebase main을 한 다음, 작업 브런치의 origin으로 보내기 위해 git push oirgin feat/xx
을 하면 push를 할 수 없다.
왜 일까?
- 결론적으로 말하면 git의 안전 메커니즘때문에 거부당하는 것이다.
origin/feat/xxx
입장에서 자신의 현재 커밋 내역은 아래와 같다.
A--B--C
\
D--E (origin/your-branch)
근데 local/main 으로부터 rebase 한 local/feat/xxxx의 커밋내역은 아래와 같다.
A--B--C--F--G
\
D'--E' (your-branch)
즉, git은 origin와 local의 히스토리가 다르다고 판단하여 push를 거부하는 것이다. 더 정확히 말하자면 rebase를 하면서 부모 커밋이 변경(C에서 G로) 되면서 모든 후속 커밋의 해시도 변경이 되었기때문에 거부를 당하는 것이다.
이러한 이유로 feat/xxx
브런치가 origin에 push가 한번이라도 된 상태라면 rebase 이후 push가 되지 않고, origin에 올라가 있지 않다면 push가 되는 것이다.
하지만 작업 브랜치가 여전히 “나”만 사용하고 있다고 보장할 수 있다면 git push —force
를 통해서 강제 push를 해도 상관 없으나, 어쨋든 해시가 변경되기에 애초에 rebase 보다는 merge를 통해서 local/main을 작업 브랜치 쪽으로 병합시키는게 좋다.
Subscribe to my newsletter
Read articles from sangkiye directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
