Git / Github (Git 관리 전략과 Branch Protection)

Git 관리 전략

기본적으로 하나의 중심 브랜치로만 관리하는 것을 trunk 라고 하고, 거기서 필요할 때만 브랜치를 분기하는 것을 trunk based flow 라고 표현합니다.

현업에서는 다양한 방식으로 브랜치를 관리하는데 가장 대표적인 방식으로 git flow, github flow, gitlab flow 세가지를 살펴보겠습니다.

Git flow

git flow는 총 5 종류의 브랜치를 활용해서 개발하는 깃 관리 전략입니다.

여기서 master, develop 브랜치는 영구적으로 존재하지만, hotfix, release, feature 브랜치의 경우는 필요할 때마다 브랜치를 만들고, merge가 되면 삭제하게 됩니다.

merge시에 각 브랜치별 기록을 상세히 남기기 위해 항상 –no-ff 옵션을 붙입니다.

전체적인 merge 순서 : feature -> develop -> release -> master

master 브랜치 (main)

소비자가 사용하는 서비스 (배포된 코드)가 존재하는 브랜치 입니다. release 브랜치로부터 pr(pull request)를 받습니다.

hotfix 브랜치

이미 배포 된 서비스에 대한 긴급 버그 수정을 진행하는 브랜치로 수정 완료 후 develop과 master 브랜치에 각각 pr을 날려 반영하게 됩니다.

release 브랜치

배포 전에 서비스를 테스트하는 브랜치입니다.

develop 브랜치

개발 단계의 코드가 있는 개발 중심 브랜치입니다.
개발 자체는 feature 브랜치를 따로 분기해서 개발하여 develop브랜치에 병합시키는 작업을 반복하게 됩니다.

feature 브랜치

특정한 단위 기능을 개발하는 브랜치 입니다. 기능 별로 개발 된 코드는 develop 브랜치로 pr을 보내게 됩니다.

Github flow

Github flow는 2 종류의 브랜치를 사용합니다. Git flow에 비해 작은 규모의 팀에서 빠른 개발과 업데이트가 중요한 서비스에서 효율적인 관리를 위해 사용합니다.

반대로 Git flow는 큰 규모의 팀에서 안정성이 매우 중요한 서비스에서 사용됩니다.

master 브랜치 (main)

소비자가 사용하는 서비스 (배포된 코드)가 존재하는 브랜치입니다.

feature 브랜치

특정한 단위 기능을 구현하는 브랜치입니다.

feature브랜치는 만들 때 Git flow보다 더 구체적으로, 상세하게 작업명을 작성하게 됩니다.

Gitlab flow

Git flow의 체계적인 관리와 Github flow의 단순함을 합쳐 절충적으로 관리하는 방식으로 4 종류의 브랜치를 사용합니다.

production 브랜치

소비자가 사용하는 서비스 (배포된 코드)가 존재하는 브랜치입니다.

pre-production 브랜치

배포 전에 제품을 테스트하는 브랜치입니다.

master 브랜치 (main)

개발 단계의 코드가 있는 개발 중심 브랜치입니다.
Git flow의 develop 브랜치와 역할이 같습니다.

feature 브랜치

특정한 단위 기능을 구현하는 브랜치로 브랜치 명은 Github flow처럼 자세하게 작성합니다.


Commit convention

커밋 메시지는 커밋을 할 때, 이 커밋이 어떤 개발에 해당되고, 어떤 변경사항이 있는지를 작성하는 것을 말합니다.

커밋 메시지를 잘 작성하면, 우리는 단순히 커밋 이력만으로도 현재까지 어떤 개발이 진행되었는지, 어떤 문제가 발생했고 해결했는지를 알 수 있게 됩니다.

커밋 메시지 규칙

보통 아래와 같은 7가지 규칙을 지키게 됩니다.
(출처: https://cbea.ms/git-commit/)

  1. 제목과 본문은 한 줄을 띄워서 작성한다.
  2. 제목은 영문 기준 50자 내외로 작성한다.
  3. 제목 첫 글자는 대문자로 작성한다.
  4. 제목 끝에 마침표(.)는 찍지 않는다
  5. 제목은 개조식으로 작성한다. (Update code, Fix bug 등으로만 작성)
  6. 본문은 영문 기준 72자마다 줄바꿈을 한다.
  7. 본문은 무엇을, 에 맞춰서 작성한다.

타입 작성

1
Feat: "로그인 함수 추가"

제목은 [타입: “내용”] 형식으로 작성합니다.

단순히 제목의 내용만 적는 것이 아니라 앞에 Feat: 이라는 단어가 붙어있는데요, 이는 해당 커밋의 타입을 명시하는 부분입니다.

  • Feat : 새로운 기능 추가
  • Fix : 버그 수정
  • Env : 개발 환경 관련 설정
  • Style : 코드 스타일 수정 (세미 콜론, 인덴트 등의 스타일적인 부분만)
  • Refactor : 코드 리팩토링 (더 효율적인 코드로 변경 등)
  • Design : CSS 등 디자인 추가/수정
  • Comment : 주석 추가/수정
  • Docs : 내부 문서 추가/수정
  • Test : 테스트 추가/수정
  • Chore : 빌드 관련 코드 수정
  • Rename : 파일 및 폴더명 수정
  • Remove : 파일 삭제

issue, pull request template

template은 issue나 request를 작성하기 위한 틀을 말합니다.
우리가 issue나 pull request를 작성할 때 일일이 목차를 직접 작성하게 되면 시간이 오래 걸리게 됩니다. 또한 issue 나 pull request를 작성하는 팀원들 간의 양식을 지킬 수 있게 됩니다.

vscode에서 template 설정해보기

git으로 관리되는 폴더 내부에 .github 폴더를 만든다.

main 브랜치로 push한 이후에 github내에서 이슈 생성으로 들어가보면 템플릿이 적용된 것을 확인할 수 있습니다.

issue의 경우, 단순 작업 정리 용도가 아닌, 다양한 목적으로 생산될 수 있습니다.

때문에 여러 개의 issue template를 만들 수 있는 github 자체 기능이 있습니다.

깃허브 레포지토리 설정에 들어가 General 메뉴에서 스크롤을 내리다보면 아래와 같이 setup templates 버튼이 보입니다.

기본적으로 깃허브에서 기본적으로 마크다운을 어느정도 작성해 놓은 템플릿을 추가할 수 있는데, preview and edit 버튼을 눌러서 수정도 가능합니다.


Branch Protection

지금까지 예시에서는 main 브랜치에 바로 push를 했는데요, main 브랜치에 바로 push하는 행위는 위험합니다.

그게 바로 pull request를 사용해야 하는 이유인데요 주니어 개발자가 에러가 나는 코드를 잘못해서 바로 main 브랜치에 push를 하게 된다면 서비스 사용자는 갑자기 에러를 마주하게 될 것입니다.

때문에 실수를 방지하기 위해서 main 브랜치에 push하는 것을 원천적으로 차단해버려야 합니다.

우리는 github에서 branch protection이라는 방식으로 이를 해결할 수 있습니다.


레포지토리 설정에 들어가서 왼쪽에서 브랜치를 선택하면 add rule 버튼을 확인할 수 있습니다.

여기에 보호하고자 하는 브랜치 이름을 적어주면 됩니다. 또한 여기서 pattern도 지정이 가능합니다.(feature*라고 작성하면 feature라는 접두어를 가진 모든 브랜치에 protection이 적용됩니다.)

이제 main 브랜치가 보호되었습니다. main 브랜치에 직접 push를 해보면, 보호된 브랜치라서 push가 불가능하다고 에러가 나오게 됩니다.


git사용 꿀팁 / pull 오류를 만났을 때

위 에러는 현재 가진 로컬 브랜치의 커밋 이력과, 리모트 브랜치의 커밋 이력이 충돌하는 경우입니다. 여러번의 push 요청이 오게되면 git 입장에서는 이력을 어떻게 합치는 것이 좋은지 선택하지 못하게됩니다.

git pull의 근본적인 원리는 github쪽의 리모트 브랜치와 로컬 브랜치를 merge, rebase를 통해 합치는 것으로 이루어집니다. 그런데 해당 에러는 git이 pull을 할 때 정확히 merge, rebase 혹은 fast-forward merge 중에 무엇을 선택할지 모르겠으니 사용자에게 지정해달라고 하는 것입니다.

main 브랜치에 대해서 직접 push하지 않고 pull request를 통해서만 merge를 하게 되면 이 에러가 발생하지 않을 것입니다.

보통 개발 블로그에서 git config pull.rebase false 같은 명령어를 입력하라고 할텐데, 이렇게 git 절정 자체를 바꾸기 보단,

1
git pull origin main --no-ff

와 같이 내가 원하는 pull 형태가 어떤 것인지 지정해주는 것이 좋습니다.
이후에 conflict가 발생한 부분을 수정한 뒤에 commit까지 해주면 해결이 됩니다.


git으로 관리하지 않을 대상 설정

개발을 하다보면, 분명 암호 파일을 프로젝트 폴더 내부에서 관리하게 되는 경우가 발생합니다.

이 경우 github에 해당 파일을 올리게 되면 모두가 암호를 볼 수 있겠죠?

또한 로그, 컴파일 파일 같은 용량이 큰 파일: Java 컴파일 파일(.class), 모듈파일(vendor, node_modules)같은 파일들 또한 git으로 다 관리하기에 무리가 있습니다.

이런 경우 우리는 .gitignore을 이용할 수 있습니다.

프로젝트 폴더 내부에서 특정한 파일만 제외하고 싶을 때, .gitignore라는 파일을 만들고, 파일 내부에 제외하고자 하는 파일명 혹은 폴더명을 적어주시면 됩니다.

vscode 상에서 해당 파일의 색깔이 회색으로 바뀌는 것을 확인할 수 있습니다.

이미 key 파일이 git으로 관리되고 있을 때

git에서 이미 해당 파일을 add, commit까지 하여서 git이 대상 파일을 인지하고 있다면 파일이 cache (임시 저장소) 안에 남아있기 때문에, .gitignore 안에 파일명을 추가해도 제외되지 않습니다.

이미 git으로 관리되는 파일을 제외하기 위해서는 임시저장소의 파일을 삭제해주는 작업이 필요합니다.

1
git rm -r --cached .

git이 자체적으로 가지고있는 캐시들을 삭제하는 명령어입니다.