서론
최근에 학원에서 팀프로젝트를 하나 했는데, git branch에 익숙하지도 않고 시간에 쫓기다보니 그냥 master branch에 다 커밋했었다. 그러다보니 깃허브 커밋 이력이 엉망진창이다.
이번 기회에 글을 정리하며 깃허브 커밋 관리에 대해 좀 더 이해해보려 한다.
Git Flow
예전에 branch를 공부하면서 얼핏 본 기억이 나는 그림이다. 배울 당시에도 좀 복잡했지만 실무에서는 이렇게 쓰겠구나하는 감이 와서 좋았었다. 위 그림만 봐도 어떻게 브랜치 형상관리가 이뤄지는지 알 수 있다. branch는 총 5개로 구분해서 관리한다.
- master : 제품으로 출시될 수 있는 브랜치
- develop : 다음 출시 버전을 개발하는 브랜치
- feature : 기능을 개발하는 브랜치
- release : 이번 출시 버전을 준비하는 브랜치
- hotfix : 출시 버전에서 발생한 버그를 수정 하는 브랜치
master
master 브랜치는 우리에게 익숙한 origin/master 브랜치다. 여기는 항상 바로 제품으로 출시될 수 있는 상태여야한다. 그리고 항상 병합의 기준이 되는 브랜치로 병합브랜치라고 불리기도 한다.
그리고 그림에서 보듯이 병합은 hotfix를 제외하고는 release 브랜치를 통해서만 이루어진다.
develop
develop 브랜치는 개발환경의 뿌리가 되는 브랜치다. develop 브랜치를 중심으로 개발이 이뤄지며 이 브랜치는 삭제되지 않는다. develop으로부터 feature 브랜치를 생성해서 기능을 개발한다. 기능 개발이 끝나면 develop 브랜치로 병합하고 feature 브랜치는 삭제한다.
$ git checkout -b myfeature develop
"myfeature" 브랜치 생성 후 변경
$ git checkout develop
"develop" 브랜치로 변경
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557 (Summary of changes)
$ git branch -d myfeature
myfeature 삭제
$ git push origin develop
여러 기능들이 구현되고 이를 실제 서비스에 반영하고 싶으면 release 브랜치를 만들어 테스트한다. 즉 release 브랜치에서는 자잘한 버그와 메타데이터를 준비하는 작업만 이루어진다. 이 또한, master 브랜치와 병합이 완료되면 삭제한다.
$ git checkout -b release-1.2 develop
"release-1.2" 브랜치 생성 후 변경
$ ./bump-version.sh
버전 정보 수정
$ git commit -a -m "Bumped version number to 1.2"
$ git checkout master
"master" 브랜치로 변경
$ git merge --no-ff release-1.2
Merge made by recursive. (Summary of changes)
$ git tag -a 1.2
$ git checkout develop
"develop" 브랜치로 변경
$ git merge --no-ff release-1.2
Merge made by recursive. (Summary of changes)
git merge --no-ff는 무엇일까?
git marge는 기본적으로 가능한 경우 fast-forward 옵션으로 병합한다. fast-forward는 무슨 의미일까?
fast-worward
fast-forward(빨리 감기) 는 모든 커밋을 변경없이 한 줄로 합칠 수 있는 상태다. 이렇게만 들으면 사실 무슨 말인지 이해하기 어렵다. non-fast-forward 와 비교하면 좀 더 이해하기 쉽다.
오른쪽이 non-fast-forward 상태다. 분기된 브랜치를 한 줄로 합치려면 새로운 커밋(초록색 점)이 필요하지만 왼쪽은 그냥 분기된 브랜치 그대로 병합 대상 브랜치 앞에 잘라내기-붙여넣기하면 된다. 브랜치가 생성됐다는 기록이 남지 않는다라는 rebase와 비슷한 점(한 줄의 커밋 히스토리)도 있다.
다만, fast-forward 방식은 feature 브랜치의 세세한 commit 이력들이 병합 브랜치에 그대로 들어가기 때문에 커밋 이력이 복잡해진다. (commit 내용의 깊이 차이로 복잡해 보임)
non-fast-forward 옵션을 사용하면 fast-forward 상태에서도 여러 커밋을 하나로 합친 후에 병합 브랜치로 병합하기 때문에 깔끔한 커밋 이력을 유지할 수 있다. 그래서 보통 merge할 때는 --no-ff 옵션을 기본적으로 사용하는 게 좋다.
rebase
사람의 욕심은 끝이 없다고... 이제 --no-ff 의 여러 줄의 커밋 이력이 거슬리기 시작했다. 이제 사람들은 fast-forward 병합 결과처럼 한 줄로 커밋 이력을 관리하고 싶어졌다. 그 해결책이 rebase 병합이다. 병합 결과를 보면 fast-forward merge랑 똑같아 한 줄지만, non-fast-forward 상태에서도 한 줄로 병합이 가능하다는 점이 다른 점이다.
위 그림에서 보듯이 non-fast-forward 상태지만 한 줄로 병합이 가능하다. 다만, 한 가지 문제점이 있다.
plain merge(fast-forward)처럼 한 줄로 만든 건 좋은데, plain merge와 같이 커밋 이력이 복잡해진다(커밋 내용의 깊이 차이). 아마 하위 브랜치의 세세한 커밋 이력들이 그대로 들어가 한 줄로 쭉 늘어선 형태가 될 거다.
이를 해결하기 위해 squash 옵션을 사용한다. 참고로 merge도 squash 옵션이 있다.
rebase에서 squash 옵션을 사용하기 위해서는 interactive rebase로 병합한다.
$ git rebase -i HEAD~3
3개의 커밋을 squash 한다.
pick 7c65355 Task 1/3
pick 2639543 Task 2/3
pick 4567812 Task 3/3
# Rebase 2260a88..d442427 onto 2260a88
#
# Commands: # p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
위의 메시지가 뜨면 아래와 같이 바꿔준다.
pick 7c65355 Task 1/3
squash 2639543 Task 2/3
squash 4567812 Task 3/3
그럼 위의 그림과 같이 불필요하게 나눠진 커밋들이 하나로 합쳐져 한 줄로 커밋 이력을 관리할 수 있다.
추가로 알다시피 git push 하기전에 pull은 필수다. pull 또한 git pull --rebase로 Rebase 할 수 있다.
Git - Rebase 하기
Git에서 한 브랜치에서 다른 브랜치로 합치는 방법으로는 두 가지가 있다. 하나는 Merge 이고 다른 하나는 Rebase 다. 이 절에서는 Rebase가 무엇인지, 어떻게 사용하는지, 좋은 점은 뭐고, 어떤 상황에
git-scm.com
우린 Git-flow를 사용하고 있어요 - 우아한형제들 기술 블로그
안녕하세요. 우아한형제들 배민프론트개발팀에서 안드로이드 앱 개발을 하고 있는 나동호입니다.오늘은 저희 안드로이드 파트에서 사용하고 있는 Git 브랜치 전략을 소개하려고 합니다. ‘배달
woowabros.github.io
A successful Git branching model
In this post I present a Git branching strategy for developing and releasing software as I’ve used it in many of my projects, and which has turned out to be very successful.
nvie.com
`git merge`와`git merge --no-ff`의 차이점은 무엇입니까?
qastack.kr
'Tools > git' 카테고리의 다른 글
커밋 주기는 어느정도가 적당할까? (0) | 2023.05.08 |
---|---|
Git 명령어 정리 (0) | 2021.12.28 |