merge에는 두 모양, 한 가지 mental model이 있어
git merge의 결과는 두 모양 가운데 하나야. fast-forward: source가 갈라진 뒤 target branch가 움직이지 않았다면 Git은 target pointer를 source의 tip까지 앞으로 밀어. 새 commit은 만들지 않아. three-way merge: 양쪽이 모두 움직였다면 각 tip을 parent로 둔 새 commit을 만들어 Y자 이력을 합쳐. graph만 봐도 어느 쪽인지 알 수 있어. 직선이면 fast-forward, 다이아몬드면 three-way야.
fast-forward는 다른 사람이 건드리지 않은 branch에서 작은 기능을 끝낼 때 흔해. main이 그대로인 상태에서 git merge feature하면 main pointer만 이동하지. 대신 나중의 이력에는 feature branch가 있었다는 흔적 없이 더 긴 직선만 남아. 그래서 어떤 팀은 fast-forward할 수 있어도 --no-ff로 merge commit을 강제해 한 작업 단위였다는 기록을 보존해.
three-way merge는 양쪽이 모두 움직였을 때 일어나. Git은 가장 최근의 공통 조상을 base로 삼고, base에서 양쪽으로 생긴 diff를 계산해 합쳐. 서로 다른 줄을 바꿨다면 자동으로 merge하고 같은 줄을 바꿨다면 conflict에서 멈춰. merge commit의 기본 message는 "Merge branch 'feature' into main"이야. 의미 있는 통합이라면 message도 의미 있게 고쳐.
두 flag도 알아두자. git merge --ff-only는 fast-forward할 수 없으면 거부해. script에서 뜻하지 않은 merge commit을 만들지 않고 눈에 띄게 실패시키고 싶을 때 좋아. git merge --squash는 source branch의 변경을 target 위에 commit 하나 분량으로 stage해. branch의 중간 commit이 산만하고 main에는 깔끔한 commit 하나만 두고 싶을 때 써.