문제 상황
보면, 한 커밋이 두 개씩 있다.
해결 과정
지금 무언가 잘못되었다. git전략이 잘못되었나? 현재, feature > develop으로 Squash & Merge를 수행한다.
커밋의 해쉬번호는 다르다. 그런데 같은 PR번호의 같은 내용이다.
첫 번째 커밋인 3dfcff3이다.
두 번째 커밋인 afadbd0이다.
올라간 PR은 하나인데, 두 개의 커밋이 동일한 이름으로 들어갔다.
내 예상은 develop > master로 머지 혹은 cherry pick을 했을 때 커밋 명이 바뀌고, 이를 pull -—rebase했을 때 다른 커밋으로 인식해 또 커밋이 쌓인 듯하다.
cherry pick을 했을 때 커밋이 바뀌나?
cherry-pick을 사용하여 다른 브랜치로 커밋을 가져갈 수 있다. 이 때, 새로운 커밋을 생성하고, 기존 커밋과 다른 해시 값을 가진다. 이것이 원인이 된 듯하다. cherry pick하는 과정에서 커밋 해시값이 바뀌어 master브랜치에 적용이 되었고, develop에서 pull —-rebase를 하면 이 커밋이 다른 커밋으로 인식하여 새롭게 가져오는 것이다. cherry pick은, develop에 적용한 변경사항을 master에 우선 반영하고 싶을 때 사용했다.
cherry-pick은 커밋 해시값을 바꾼다면, Squash & Merge 그리고 Rebase & Merge는?
Squash & Merge는 여러 커밋을 단일 커밋으로 병합하는 과정이다. 그 과정에서 당연히 새로운 커밋이 생기고, 해시값이 생긴다.
Rebase & Merge는 한 브랜치의 커밋들을 다른 브랜치의 최신 커밋 위에 재배치하는 과정이다. 이 과정에서 재배치되는 커밋들은 새로운 해시값을 가질 수 있다. 즉, develop브랜치를 master에 Rebase & Merge하는 과정에서 develop의 커밋들은 새로운 해시값을 가지게 된다.
상황 Test
1. master에서 hotfix를 파고, master에 머지 후, develop에서 rebase를 한다.
1. master브랜치 생성
git inittouchREADEME.md: 파일 생성git add .git commit -m “add README”git push -u origin master-u:—-set-upstream의 약자로, 현재 브랜치의 기본 원격 저장소와 브랜치를 설정
origin: 원격 저장소의 기본 이름
2. develop 브랜치 생성
git checkout -b develop- develop 브랜치 생성하고(
-b), 이동(checkout)
- develop 브랜치 생성하고(
git siwtch -c develop과 동일
git push -u origin develop- 생성한 develop 브랜치를 원격 저장소에 push하고, 해당 브랜치를
git push또는git pull할 때 해당 브랜치를 기본으로 설정
- 생성한 develop 브랜치를 원격 저장소에 push하고, 해당 브랜치를
3. master에서 hotfix 분기
git checkout mastergit checkout -b hotfix/1git push -u origin hotfix/1touch index.js: 파일 생성git add .git commit -m “hotfix commit”git push
4. hotfix에서 master로 머지
git checkout mastergit merge hotfixgit push- 아까 전에 git push -u origin master로 기본 브랜치로 설정했으므로
git push만 입력해도 된다
- 아까 전에 git push -u origin master로 기본 브랜치로 설정했으므로
master브랜치와 develop브랜치의 현재 상황
![]()
5. develop에서 master를 rebase
-
rebase를하기 전, develop도 하나의 커밋을 더 만들었다.
-
git rebase master
master의 최상 커밋 상황을 반영하여 base를 다시 잡는다.
base를 다시 잡는 과정에서, 이전 develop의 최신 커밋(a6692a3)이 뒤로 가게 되고, 새로운 커밋(01caa90)이 생성되었다.
❗ 이 과정에서 2개의 커밋이 생성되었다.
잘 보면, develop브랜치가 두 개이다. 두 번째 내 프로필 사진이 있는 develop브랜치는 github에 올라간 develop 브랜치이다.
그리고 첫 번째 모니터 사진이 있는 develop브랜치는 현재 내 로컬에 있는 develop브랜치이다.
이 때, 2개의 커밋이 생성이 된 것이다. 이에 대한 이야기는 뒤에서 하겠다.
6. develop에서 master로 merge
-
git checkout master
master의 현재 상황이다. hotfix브랜치까지 반영이 되어있다.
-
git merge develop
develop의 가장 최신 커밋(rebase과정에서 새롭게 생성된 커밋 해시값)이 master에 붙게된다.
-
git checkout develop
develop > master로 머지를 하고 develop으로 오면, pull과 push할 것이 생긴다. 왜냐하면 master에 변경사항이 생겼기 때문이다.
pull은 master에 반영되고, develop에는 반영되지 않은 hotfix 커밋이다.
-
git rebase-
master의 가장 최신 커밋을 base로 잡는다. 이 과정에서 새로운 커밋이 생긴다.
-
-
git pull -
git push -
git checkout master -
git merge develop
이제서야 그래프를 보면, 정상적으로 develop이 master에 머지가 되었다.
그리고, 머지를 하는 과정에서 새로운 커밋이 또 생성이 된다.
❓ 왜 기존에는 git graph가 합쳐지지가 않았나?
master에서는 hotfix가 이미 머지가 되어있었다. develop에서 rebase를 하지 않고 master에 merge를 하였기에, develop브랜치는 최신 상태가 아니었다. 그래서 develop을 master에 merge를 했을 때 완전히 병합되지 않은 것이었다.
다음부터는 상위 브랜치에 머지할 때 꼭 rebase를 하고 merge를 하도록 하자.
커밋이 두 개씩 존재한다.
hotfix commit이 2개, develop commit이 2개이다.
원인 : develop브랜치에서 커밋을 push 하고 나서, rebase를 하였기 때문에 발생한 이슈였다.
해결방법 : rebase를 하고 push를 했어야 했는데, rebase하지 않고 push하지 않아 발생한 이슈였다.
결론
rebase를 하면, rebase대상 브랜치의 가장 최신 커밋을 새로운 base로 잡고, 새로운 커밋 해시값을 생성한다. 그리고, merge를 하게되면 그 rebase한 새로운 커밋을 가져와 현재 브랜치의 최신 커밋으로 설정을 한다.
또한 merge를 하면 새로운 커밋이 생성된다.
rebase를 하지 않고 상위 브랜치에 머지를 하게 되면 상위 브랜치의 최신 상태가 반영되지 않은 상태로 머지가 되기 때문에 그래프 상에서 완전히 병합되지 않는다. 상위 브랜치로 머지할 때는 꼭 rebase 후 merge하도록 하자.
이 때, rebase는 꼭 로컬에서 하고 push 해야 한다. push하고 rebase하면, 커밋이 두 개 생성된다.
전에 프로젝트에서 이슈가 발생했던 것은, develop에서 master로 머지할 때, develop에서 master를 rebase하지 않고 push 후 rebase를 했기 때문에 발생했던 것 같다. 다음부터는 꼭 master를 rebase하고 머지하도록 하자.
2. develop에서 hotfix를 파고, develop에 머지 후, master에 cherry pick을 한다.
-
현재 상황 : master와 develop브랜치의 최신 커밋이 일치한다.
develop에서 hotfix 분기 후 커밋하여 develop에 머지
-
git checkout develop -
git checkout -b hotfix/12 -
touch hotfix12 -
git add . -
git commit -m “hotfix commit12” -
git push -u origin hotfix/12 -
git checkout develop -
git merge hotfix/12
master로 이동 후 cherry pick
-
git checkout master
-
git cherry-pick 34611a0(hotfix=develop의 최신 커밋)
기존 커밋이 아니라 새로운 커밋이 생성되며 해당 커밋을 master로 가져왔다.
커밋 상황은?
그렇다고, hotfix 커밋이 2개가 생성되지는 않았다.
develop이 master에 머지된다면?
git checkout developgit rebase master-
master에 변경사항이 생겼으니 rebase한다.
rebase하니, 기존 hotfix 커밋은 버리고 master의 최신 커밋으로 이동한다.
이제 master와 develop의 최신 커밋은 동일해졌다.
-
결론
cherry pick의 문제도, rebase의 문제도 아니었다. rebase의 순서가 잘못되어 발생한 이슈였다.
feature에서 develop로 머지할 때 Squash & Merge는 문제가 없다. feature의 커밋을 하나로 합쳐서 develop에 합치는 것이기 때문이다.
develop에서 release 분기 후 master에 머지할 때가 문제였다. 정확하게 기억이 안나지만 오늘 실험을 해본 결과 이 때 rebase & merge를 해야하는데, 그냥 merge를 했을 것이라 추측한다. 그냥 merge를 하면 master의 현재까지의 최신 커밋이 release에는 반영이 되지 않는다. 예를 들어 master에서 hotfix브랜치로 작업을 해서 수정사항이 생겼었더라면, 그냥 merge를 했을 때 하나의 브랜치로 합쳐지지 않는다. rebase를 해서 master의 수정사항이 현재 release에도 반영이 되어 base를 다시 잡고, 그 다음 merge를 해야 release와 master가 동기화가 된다.