💡 사전지식
✅ git merge
✅ head
✅ git reset --hard
✅ git add
✅ Fast-Forward Merge와 3-way Merge
본격적인 내용에 앞서 Merge의 두 종류인 Fast-Forward Merge와 Squash and Merge에 대해 가볍게 짚고 넘어가도록 하겠다.
🟢 Fast-Forward Merge
순차적 커밋에 맞추어 병합하는 방식
브랜치를 생성한 지점과 Merge 저점이 동일한 경우 사용
(브랜치가 생성된 지점을 Base라고 한다.)
git checkout main
git merge feature
Merge 전
Merge 후
🟢 3 - way 병합
병합 대상 브랜치와 병합 원본 브랜치에 공통 조상이 있지만,
두 브랜치가 독립적으로 발전하여 히스토리가 일직선으로 이어지지 않을 때 발생
즉, 브랜치를 생성한 지점과 Merge 지점이 동일하지 않은 경우 사용
병합 대상 브랜치의 커밋들이 하나의 병합 커밋으로 합쳐져 병합 원본 브랜치에 이어짐
git checkout main
git merge feature
Merge 전
Merge 후
✅ Squash and Merge
여러 commit을 하나로 묶어 새로운 커밋을 만들어 병합한다.
git checkout main
git merge --squash feature
🤔 생긴 궁금증
3-way merge랑 squash and merge랑 무언가 동작 방식이 비슷해 보인다.
둘다 Merge전 commit들을 하나로 묶어서 생성된 병합 커밋을 만들어낸다.
여기서 나는 한가지 궁금증이 생겼다.
🤔 3-way merge를 squash and merge 방식으로 merge하면 그냥 일반 merge를 했을 때와 아무 차이가 없는건가?
🖐️ 궁금증 해결
결론부터 말하면 차이가 있다.
위에서 봤던 예시를 다시보자.
- Main 브랜치: A → B → E
- Feature 브랜치: B → C → D
Feature 브랜치가 B에서 분기된 이후로 각 브랜치는 독립적으로 히스토리가 발전했다.
Main은 E 커밋 추가 생성 Feature는 C, D 커밋 추가 생성
이 상황에서 Feature브랜치를 Main 브랜치로 Merge 하려는 상황이다.
이제 실제 인텔리제이 환경에서 위의 예시처럼 브랜치와 커밋을 만들어 보겠다.
Main 브랜치
- A, B, E 커밋이 추가되었다.
- Main 브랜치의 현재 head는 E의 위치하고 있음
Feature 브랜치
- Main 브랜치의 B 커밋에서 분기되었고 그 이후 C, D 커밋이 추가되었다.
- Feature 브랜치의 현재 head는 D의 위치하고 있음
➡️ 이 상태에서 main브랜치에 feature 브랜치를 merge 해보겠다.
git merge feature
먼저 별도의 옵션을 주지 않고 merge를 하게되면 브랜치 구조때문에 자동으로 3-way merge가 수행된다.
Feature 브랜치의 커밋이 Main 브랜치로 합쳐진 것을 볼 수 있다.
이때, 주의 깊게 봐야할 것이 Feature 브랜치의 커밋 히스토리인 B-C-D가 그대로 남아있다는 것이다.
--
다시 원래 상황으로 돌아와 보자.
git reset --hard <E 커밋의 해시값>
--
이제 squash and merge방식으로 merge를 해보자.
git merge --squash feature
그랬더니 바로 Main 브랜치에 병합되는 것이 아니라 Feature 브랜치의 커밋이었던 C와 D가 git add만 되었다.
이 두 커밋의 내용을 하나로 병합해 F라는 이름으로 커밋해보겠다.
이 F의 커밋 내용은 앞서 말했 듯 Feature 브랜치의 C와 D이다.
여기서 주의깊게 봐야할 점은 커밋 Main 브랜치의 커밋 히스토리이다.
저 F라는 커밋이 어디서 온건지 히스토리를 전혀 확인할 수 없게 된다.
어찌보면 당연하다. merge시에 커밋이 바로 병합된 것이 아니라 git add만 되고 커밋은 내가 별도로 해주었기 때문이다.
결론
자 이제 정리해보도록 하겠다.
3-way merge, squash and merge 모두 merge시 커밋들을 하나로 병합한다는 점은 똑같다.
하지만 둘은 다음과 같은 차이가 있었다.
📌 3-way merge
병합 대상 커밋들의 히스토리가 유지된다.
따라서 두 브랜치의 모든 커밋을 유지하여 추적 가능성을 높이고 변경 사항의 세부 정보를 유지할 수 있다.
📌 squash-and-merge
병합 대상 커밋들의 히스토리가 유지되지 않고 새로운 커밋이 생성된다.
실제로는 병합되는 것이 아니라 해당 커밋들을 git add만 한다.
따라서 여러 커밋을 하나로 압축하여 히스토리를 단순화할 수 있어 main 브랜치의 커밋 히스토리가 깔끔해지고, 이해하기 쉬워진다.