rebase란?
Git merge와 rebase 둘 다 두 브랜치를 합친다는 점에서 같지만, 히스토리를 어떻게 남기는지에 따라 다르다.
- merge: 기존 히스토리를 그대로 유지하면서 새로운 merge commit을 만든다.
- rebase: 내 브랜치의 커밋들을 base 위에 다시 쌓는다.
이 설명만 보면 이해가 잘 안 될 것이다..^^;; 밑에서 자세히 설명하겠다.
이 글에서는 rebase의 동작 원리 그리고 rebase 후 push하는 법을 다룬다.
rebase가 하는 일
다음과 같이 main branch와 feature branch가 존재한다고 해보자.
main: A --- B --- C
\
feature: D --- E
이 상태에서 feature branch에서 다음 커맨드를 실행한다.
git rebase main
그러면 Git은 다음 과정을 수행한다.
- feature 브랜치의 커밋 D, E를 임시로 떼어낸다.
- main의 최신 커밋 C 위로 이동한다.
- 커밋 D, E를 다시 적용한다.
결과:
main: A --- B --- C
\
feature: D' --- E'
여기서 중요한 점은!!
rebase를 하면 기존 커밋이 그대로 유지되는게 아니다.
기존 커밋 D, E가 그대로 이동하는게 아니다. 얘네는 D', E'라는 다른 커밋이 된다. 내용은 같지만 해시가 다른 새로운 커밋이다.
Git에서 커밋의 identity는 해시이므로, 해시가 바뀌면 완전히 다른 커밋이다.
rebase 이후 발생하는 문제
rebase를 하면: 로컬 브랜치 히스토리 ≠ 원격 브랜치 히스토리 가 된다.
예를 들어 원격 저장소가 다음과 같다고 가정한다.
origin/feature
A --- B --- C
내가 로컬에서 rebase를 하면
feature (local)
A' --- B' --- C'
이 된다.
겉보기에는 같은 커밋처럼 보이지만 실제로는 완전히 다른 히스토리다.
git push가 안되는 이유
기본적으로 git push는 fast-forward push만 허용한다.
Git의 판단 기준은 원격 브랜치가 내 로컬 브랜치의 조상인가? 이다.
정상적인 fast-forward 상황은 다음과 같다.
origin/feature
A --- B
local feature
A --- B --- C
이 경우 push 가능하다.
하지만 rebase 이후에는 다음처럼 된다.
origin/feature
A --- B --- C
local feature
A' --- B' --- C'
해시가 다르기 때문에 Git은 공통 조상이 아니라고 판단한다.
그래서 push를 하면 다음과 같은 메시지가 나온다.
! [rejected] non-fast-forward
의미: 원격 브랜치에 네가 모르는 히스토리가 있으니 그냥 덮어쓰는 건 위험하다.
rebase 후 올바른 push 방법
rebase 이후에는 일반 push 대신 다음 커맨드를 사용한다.
git push --force-with-lease origin feature/xxx
여기서 중요한 옵션!!
--force-with-lease의 의미
: 원격 브랜치가 내가 마지막으로 확인한 상태 그대로라면 덮어써도 된다.
push 가능한 상황:
1. 내가 pull 또는 fetch를 했다
2. 그 이후 원격 브랜치에 새로운 커밋이 추가되지 않았다
3. 그렇다면 rebase된 히스토리로 덮어쓴다
push 불가능한 상황:
다른 사람이 이미 원격 브랜치를 업데이트함
git push --force
-> 다른 사람의 커밋도 날려버릴 수 있음
git push --force-with-lease
-> 그러한 위험 방지
즉 --force-with-lease는 rebase로 바뀐 커밋 해시를 의도적으로 원격에 반영하는 안전한 방식인 것...~
rebase를 사용하는 이유
rebase를 사용하는 가장 큰 이유는 히스토리를 깔끔하게 유지하기 위해서다.
merge를 사용하면 히스토리가 이렇게 된다.
A --- B --- C -------- M
\ /
D --- E -----
하지만 rebase를 사용하면 이렇게
A --- B --- C --- D --- E
linear history가 된다.
이 때문에 다음과 같은 상황에서 많이 사용된다.
- feature 브랜치를 main에 올리기 전 정리
- PR을 깔끔하게 유지
- commit history 정리 (interactive rebase)
정리
- rebase는 커밋을 이동시키는 것이 아니라 새로 만든다.
- 그래서 커밋 해시가 바뀌고 히스토리가 달라진다.
- 이 때문에 일반 push가 막히고 --force-with-lease를 사용해야 한다
따라서 이런 흐름으로 자주 사용하게 될 것이다..
git fetch origin
git rebase origin/main
git push --force-with-lease origin feature/xxx
끝!
'Dev & Study' 카테고리의 다른 글
| Next.js가 삭제된 파일을 계속 참조하는 문제 (.next 캐시 삭제 방법) (0) | 2026.03.02 |
|---|---|
| [Next.js] next-env.d.ts가 자꾸 바뀌는 문제 (0) | 2026.03.02 |
| 멋사 세미나 과제 5 (2) | 2024.12.05 |
| 멋사 세미나 과제 4 (2) | 2024.11.21 |
| 멋사 세미나 과제 3 (3) | 2024.11.07 |