개발 Dev/깃 Git

Q. 깃허브github에서 깃플로git-flow와 스쿼시와 병합Squash and merge을 함께 쓰면 안 되는 이유는?

Tap to restart 2023. 10. 11. 22:00

A. release 브랜치에서 main 브랜치로 PR(Pull Request) 요청할 때마다 충돌이 발생한다.

 

스쿼시와 병합Squash and merge이란?

여러 커밋을 하나의 커밋으로 밀어넣어서(squash) 병합(merge)해주는 기능이다. 예를 들어서 feature 브랜치에서 develop 브랜치로 PR을 만들었다고 하자. feature 브랜치에서 작업한 커밋이 10개다. 스쿼시와 병합 기능을 쓰면 단 1개의 커밋으로 10개의 커밋이 합쳐져서 develop에 병합된다. 그래서 커밋 이력이 깔끔해진다.
 

충돌 예시

 
add hello title, add hello text란 두 커밋을 하고 feature/add_hello 브랜치에서 develop으로 PR을 만든 경우다.
 

 
Squash and merge한 결과는 아래와 같다. PR 제목대로 Feature/add hello (#1) 커밋이 생겼고 커밋은 하나만 추가된 것을 볼 수 있다. 커밋 해시값은 fdbf80b다.
 

 
git-flow에 따라 develop에서 release/v0.0.1 브랜치를 분기한다. 그 뒤 release/v0.0.1 -> main으로 PR을 만들어서 병합한다.
 

 
Squash and merge 한 결과 main 브랜치에 Feature/add hello (#1) (#2)란 커밋이 추가된 것을 볼 수 있다. 맨 뒤 커밋 해시값을 보면84fc5d6으로 앞의 develop과 다른 것을 볼 수 있다.
 

 
실제로 README.md 파일 자체는 똑같다.
 

 

 
이번에 추가로 feature/add_world란 브랜치를 develop으로부터 분기한다. 
그리고 이번에는 Add world title, Add world text 두 커밋을 한다.
 

 
마찬가지로 feature/add_world -> develop으로 PR을 만든다. 스쿼시와 병합을 한다.
 

 
결과로 아래처럼 두 커밋이 한 커밋으로 develop에 추가된다.
 

 
이 상태에서 다시 develop에서 release/v.0.0.2를 분기한다. 그리고 release/v.0.0.2 -> main으로 PR을 만든다.
그렇게 하면 develop과 main이 완전히 같은 README.md 상태였음에도 아래처럼 충돌이 발생하는 것을 볼 수 있다.
사실 새로운 커밋은 Feature/add world (#3) 임에도 Feature/add world (#1) 도 목록에 보인다. 그 이유는 앞에서 살펴봤듯이 해시값이 다르기 때문이다. 해시값이 다르니 완전히 같은 내용의 커밋임에도 서로 다른 커밋으로 인식이 된다. 
 

 
커밋 순서상
Feature/add hello (#1) - release/v.0.0.2
-> Feature/add hello (#1) (#2) - main
-> Feature/add hello (#3) - release/v.0.0.2
이 되니 충돌이 발생하게 되는 것이다.
 
충돌 내용을 보면 world를 추가했기 때문에 충돌이 난다고 나온다.
 

 
지금은 커밋 내용이 적어서 그렇지, 변경점이 많은 경우 Squash and merge를 이용하면 충돌이 많아지고, 충돌나는 파일도 많아진다. 매번 충돌을 해결해야 한다. 
 

Squash and merge를 계속 쓰고 싶다면?

feature 브랜치에서 develop으로 병합하는 경우에는 squash and merge를 써도 된다. release 브랜치를 main과 develop으로 병합하는 경우(release -> main PR, release -> develop PR)와 hotfix 브랜치를 main과 develop으로 병합하는 경우(hotfix -> main PR, hotfix -> develop PR)에는 일반 merge를 하자. 그러면 위와 같은 상황이 발생하지 않는다.
 
그 이유는 커밋 release/v.0.0.1 -> main으로 스쿼시와 병합을 하지 않았다면 main 브랜치의 마지막 커밋은 Feature/add hello (#1) 이 될 것이다. 당연히 release/v.0.0.2 -> main으로 PR을 만들면 main 브랜치의 Feature/add hello (#1) 커밋과 release/v.0.0.2 브랜치의 Feature/add hello (#1) 커밋이 해시값도 일치하니 그 다음 커밋인 Feature/add hello (#3) 커밋만 PR에 보이고 충돌도 없게 된다.