아래 처럼 remote/main 브랜치에 새로운 commit 이 push 된 상태이다.
이 상태에서 local/main 브랜치에서는 remote 의 변경 사항을 받아오지 않고 새로운 commit 을 해버렸다.
이때 깃 로그를 한번 봐보자.
local/main 브랜치, remote/main 브랜치 각각에 commit 이 생겨있다.
이를 도식화해보면 다음과 같다.
이 상태에서 remote 브랜치에 local 변경 사항을 push 하려고 하면 다음과 같은 오류가 발생한다.
remote 의 변경 사항을 먼저 local 에 반영한 다음에 push 를 해야 한다는 것이다.
그럼 여기서 merge 와 rebase 의 차이는 뭘까?
직접 해보자!
터미널 명령어
git config pull.rebase false
git pull origin main
remote/main 브랜치를 local/main 브랜치에 merge 를 하면 깃 이력이 다음과 같이 바뀐다.
push 를 할 때 local 커밋과 merge 커밋 두 개의 커밋이 푸쉬된다.
도식화하면 다음과 같다.
만약 ide 가 아닌 명령어를 사용해서 merge 를 한다면, conflict 를 해결하고 생기는 commit message 에 fix: resolve merge conflict
이런 메시지를 써주면 된다.
터미널 명령어
git config pull.rebase true
git pull origin main
이 상황에서 이번엔 rebase 를 사용해보자
rebase 를 사용하면 다음과 같이 커밋 이력이 남는다.
여기서 주의할 점은 local commit 의 id 가 변경되었다는 점이다.
그리고 이를 도식화하면 다음과 같다.
rebase 를 실행하면 선형적으로 커밋이 쌓이는 것을 볼 수 있다.
주의할 점은 재정렬되는 commit 이력이기 때문에, 재정렬되는 commit 이력에는 이전과는 다른 새로운 해쉬 ID가 부여된다.
만약 ide 가 아닌 명령어를 사용해서 rebase 를 한다면, conflict 를 해결하고 생기는 commit message 에 rebase 된 커밋의 메시지
를 써주면 된다.
여기서는 docs: first local commit
가 될 것이다.
만약 처음 문제 상황에서 git pull 을 받으려고 하면 다음과 같은 이유로 pull 이 거부된다.
우리가 사용하는 pull 명령어는 기본적으로 fast forward 형식을 사용한다.
✅ git pull --ff-only
pull 하려는 원격저장소의 브랜치와 로컬저장소의 브랜치가 fast-forward 관계일 때만 pull을 허용한다.
두 브랜치가 fast-forward 관계라는 건 둘 중 하나를 의미한다.
두 브랜치가 갈라진 commit을 기준으로
로컬저장소에만 새로운 commit이 있고, 원격저장소에는 없다.
원격저장소에만 새로운 commit이 있고, 로컬저장소에는 없다.
첫번째 경우는 pull을 받아올 필요가 없으므로 두 번째의 경우에만 pull이 가능하다는 뜻이 된다.
그럼 만약 원격저장소의 새로운 commit이 존재하는데 git pull을 하지 않은 상태에서 로컬저장소에 새로운 commit을 했다면, git은 pull을 허용하지 않을 것이다.
✅ git pull --rebase
pull 시에 rebase를 사용하면 아래와 같이 동작한다.
rebase란? 새 브랜치가 시작된 분기점 commit이 존재한다. 이 분기점을 기준 브랜치의 가장 최근 commit으로 변경하는 작업.
로컬 브랜치의 시작점을 원격 브랜치의 마지막 commit으로 옮기는 식인 것 같다. 그 과정에서 conflict가 발생할 경우 이를 해결해줘야 할 듯 싶다.
git history가 깔끔해진다는 장점이 있지만, 부주의하게 사용할 경우 별도의 알림 없이 git history를 영구적으로 변경할 수 있기 때문에 ff-only 방식을 더 추천한다고 한다.
참고