Git 협업 가이드

jinuku·2020년 8월 12일
119
post-thumbnail

Feature 브랜치


새로운 기능 개발을 위한 feature 브랜치를 생성할 때 브랜치 이름은 다음과 같은 규칙으로 생성합니다. feature 브랜치는 마지막 develop 브랜치로부터 생성합니다. 꼭 브랜치를 생성하기 전에 develop 브랜치를 pull 받습니다.

feature/{기능}

feature 브랜치는 작은 기능 단위로 쪼개어 최대 10개 미만의 커밋으로 구성되도록 합니다. feature 브랜치가 develop 브랜치에 성공적으로 병합되었다면 feature 브랜치는 로컬과 원격에서 삭제합니다.

feature 브랜치 생성하기

git checkout -b feature/feature1

Commit


커밋은 기능, 타입 단위로 짧게 끊어서 커밋합니다. 한번에 작업한 내용이 많더라도 커밋은 여러번에 걸쳐 구분하여 커밋합니다. 그리고 커밋 타입에 따라 구분하여 커밋합니다. 예를 들어 리소스 추가는 리소스끼리 모아 커밋하고 버그 수정은 버그 수정만 따로 커밋하고 새로운 기능 추가는 추가된 기능만 따로 커밋합니다.

커밋을 하였다면 원격 저장소에 push 하여 다른 멤버가 자신이 작업하고 있는 파일, 내용을 알 수 있도록 합니다.

commit 하기

git add Assets/something.cs
git commit -m "feat : Change something"

원격 저장소에 작업중인 브랜치 원격 저장소에 push 하기

git push --set-upstream origin feature/feature1

Commit message


https://doublesprogramming.tistory.com/256

커밋 메세지를 작성할 때는 다음과 같은 규칙으로 일관성 있게 작성합니다.

1. Commit Message Structure

기본적으로 커밋 메세지는 아래와 같이 제목 / 본문 / 꼬리말로 구성합니다.

type : subject

body

footer

2. Commit Type

  • feat : 새로운 기능 추가
  • fix : 버그 수정, 기능 수정
  • docs : 문서 수정
  • refactor : 코드 리팩토링 (변수명 수정 등)
  • test : 테스트 코드, 리팩토링 테스트 코드 추가
  • style : 코드 스타일 변경, 코드 자체 변경이 없는 경우
  • remove : 파일 또는 코드, 리소스 제거
  • resource : 이미지 리소스, prefab 등의 코드와 상관없는 리소스 추가

3. Subject

  • 제목은 50자를 넘기지 않고, 대문자로 작성하고 마침표를 붙이지 않습니다.
  • 과거시제를 사용하지 않고 명령어로 작성합니다.

예시

feat : Add translation to missing strings
feat : Disable publishing
feat : Sort list context menu
feat : Resize minimize/delete handle icons so they take up the entire topbar
fix : Fix typo in cleanup.sh file

4. Body

  • 선택사항이기 때문에 모든 커밋에 본문내용을 작성할 필요는 없습니다.
  • 부연설명이 필요하거나 커밋의 이유를 설명할 경우 작성합니다.
  • 제목과 구분되기 위해 한칸을 띄워 작성합니다.
  • 각 줄은 72자를 넘기지 않습니다.
  • 본문은 꼭 영어로 작성할 필요는 없습니다.
  • 선택사항이기 때문에 모든 커밋에 꼬리말을 작성할 필요는 없습니다.
  • 등록된 이슈 ID를 트래킹할 때 주로 사용합니다.

6. Example Commit Message

feat: Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequenses of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789

git stash


현재 작업중인 브랜치에서 다른 브랜치로 checkout 해야 할 경우 커밋하지 않은 작업 때문에 checkout 이 안될 수 있습니다. 이럴 때 커밋하지 않은 작업을 stash 명령어로 임시 보관하고 다른 브랜치로 checkout 할 수 있습니다. 스택에 임시 보관한 작업들은 나중에 다시 꺼내와 마무리할 수 있습니다.

git stash
git checkout develop

stash 목록 확인하기

git stash list

stash 적용하기 (했던 작업을 다시 가져오기)

// 가장 최근의 stash를 가져와 적용한다.
$ git stash apply

// stash 이름(ex. stash@{2})에 해당하는 stash를 적용한다.
$ git stash apply [stash 이름]

git rebase


여러 멤버가 동시에 각자의 feature 브랜치에서 기능 개발을 하며 커밋을 하고 develop 브랜치에 merge 로 만들어진 히스토리는 브랜치가 꼬여 프로젝트의 히스토리를 확인하는데 복잡하고 이해하기 어렵습니다. 그래서 다른 멤버에게 잘 보여지도록 git rebase 를 통해 원격 저장소에 Pull Request하기 전 프로젝트의 히스토리를 다듬습니다. 사실 git rebase 의 개념은 어려운 편이지만 편의를 위해 자주 사용하게 됩니다. rebase의 내용은 다음 두 링크를 참고하여 꼭 읽어보시기 바랍니다. 저희 팀은 rebase를 통해 원격 저장소 히스토리를 깔끔하게 정리합니다.

rebase 를 시행하기 전 원격저장소에서 develop 브랜치를 pull 받아 원격 저장소에 그동안 반영된 커밋을 가져옵니다.

git checkout develop
git pull

현재 작업중인 feature 브랜치의 커밋을 develop 에 rebase 하기

git rebase develop feature/feature1

git rebase 를 통해서 미리 conflict를 알아채고 해결할 수 있습니다. 가장 최신의 origin/develop 브랜치 에서부터 자신이 작업한 커밋을 다시 배치하는 것이기 때문에 자신이 작업한 내용과 원격 저장소의 develop 브랜치가 충돌하면 conflict가 발생하게 됩니다. 따라서 Pull Request전에 conflict를 해결한 후 Pull Request를 요청할 수 있습니다.

주의
이미 원격 저장소에 push한 커밋은 절대 rebase하면 안됩니다.
Rebase는 기존의 커밋을 그대로 사용하는 것이 아니라 내용은 같지만 다른 커밋을 새로 만듭니다. 만약 누군가가 그 사이에 그 커밋을 Pull 받았었다면 커밋이 전혀 다르게되어 코드가 엉망이 될 것입니다.

Pull Request


하나의 feature 브랜치에서 기능 개발이 완료되었다면 바로 develop 브랜치에 merge 하여 원격 develop 브랜치에 push 하지 않고 작업중이던 브랜치를 push 한 후 원격 develop 브랜치에 Pull Request를 요청합니다. 만약 Pull Request전에 rebase 를 진행했다면 push force 명령어로 원격 저장소를 강제로 갱신합니다.

Pull Request는 GUI 도구를 사용하는 것이 편리하므로 GUI 도구를 주로 이용하거나 호스팅 서비스 홈페이지에서 진행합니다.

<Pull Request>

origin/feature/feature1 -> origin/develop

Title: Add feature1 to somthing

body : 부연설명과 참고사항 등

PR(Pull Request)이 요청되면 Bit bucket 에서 PR 피드백을 진행합니다. PR 코멘트는 PR, 파일, 라인 단위로 코멘트를 달 수 있습니다. 따라서 다른 멤버들이 원활하게 PR을 확인하고 피드백을 진행하기 위해서 PR 단위가 너무 크지 않도록 주의합니다.

PR이 승인되어 merge commit 되었다면 merge된 feature 브랜치는 로컬과 원격 저장소에서 삭제합니다.

git squash (git rebase -i)


정확히 이야기해서 git squash 라는 명령어는 없습니다. interactive reabse 를 하는데 필요한 명령어 중 하나 입니다. squash는 이중 여러개의 커밋을 하나의 커밋으로 합치는 옵션입니다. 까먹고 같이 커밋하지 않은 파일이 있던가, 같은 커밋에 해당하는 작업인데 커밋 이후에 작업을 했던가, 커밋 로그가 지저분하여 정리를 한다던가 할 경우에 유용하게 사용할 수 있습니다.

PR을 요청한 이후에 까먹고 같이 커밋하지 않은 작업이 있다던지, PR 피드백을 반영하여 파일을 수정하였는데 이를 추가적인 커밋으로 보기가 어렵다면 PR에 요청 했던 이전 커밋과 합쳐서 PR을 수정할 수 있습니다. 아래 두 링크를 참고하여 꼭 읽어보세요.

만약 최근 3개의 커밋을 interacive rebase하고 싶을 때

git rebase -i HEAD~3

위 명령어를 입력하면 rebase가 시작됩니다. vi 에디터가 뜨면서 다음과 같은 화면이 뜹니다.

pick 7c65355 Task 1/3
pick 2639543 Task 2/3
pick d442427 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
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

가장 위의 3줄을 원하는 옵션으로 변경하고 저장합니다. (:wq)

pick 7c65355 Task 1/3
squash 2639543 Task 2/3
squash d442427 Task 3/3

위 rebase 작업이 끝나면 3개의 커밋은 하나로 합쳐져 다음과 같이 하나의 커밋으로 보이게 됩니다.

Task 1/3 ~ 3/3

git rebase 도중 conflict가 발생하면 rebase가 잠시 멈춥니다. 이 때 conflict를 해결 한 후 git rebase --continue 명령어로 진행중이던 rebase 작업을 계속 이어나갈 수 있습니다.

GUI 도구에서는 여러개의 커밋을 선택한 후 오른쪽 클릭하여 git squash를 바로 할 수 있습니다.

git commit --amend


git commit 메세지의 메세지를 변경할 경우 사용되는 명령어 입니다. 커밋 메세지를 잘못 입력했거나 수정해야 할 경우 주로 사용합니다. 커밋 메세지를 계속 수정하여 보기 좋은 히스토리를 남기는 습관을 가집시다.

GUI 도구에서는 커밋을 선택한 후 오른쪽 클릭하여 커밋 메세지를 수정할 수 있습니다.

git push --force


원격 저장소에 이미 올라간 커밋이 있는데 로컬에서 커밋을 되돌리거나 변경한 것을 원격 저장소에 강제로 반영할 때 사용되는 명령어 입니다. 주로 PR을 수정하고 업데이트할 때 사용되거나 작업중인 feature 브랜치에서 이미 원격 저장소에 push 한 이후 로컬에서 커밋을 변경했을 경우 사용됩니다.

PR 수정 요청 사항 수정 후 commit > rebase > squash > push 할 때

git push -f origin feature/feature1

위 작업이 진행되면 자신이 요청했던 PR에 수정사항이 반영되어 업데이트 된 것을 확인할 수 있습니다.

git cherry-pick


다른 브랜치에 있는 커밋을 선택적으로 혹은 전부 현재 작업중인 브랜치에 적용시킬 때 사용하는 명령어입니다. 아래 두 링크를 참고하여 한번 읽어보세요.

PR요청 후 다른 멤버들이 PR 피드백과 코멘트를 작성하는 동안 작업하던 브랜치에서 다음 기능 개발을 계속 진행합니다. PR 수정이 모두 반영되고 merge commit 되면, PR이 병합된 develop 브랜치에서 새롭게 다음 기능 개발 feature 브랜치를 생성합니다. 새롭게 생성한 feature 브랜치에 PR이 진행되는 동안 이전 브랜치에 커밋했던 커밋들을 git cherry-pick 으로 가지고옵니다. 물론 이전에 작업한 feature 브랜치는 삭제합니다.

특정 커밋을 현재 작업중인 브랜치로 가져올 때

git cherry-pick [커밋해시]

여러 개의 연속된 커밋을 현재 작업중인 브랜치로 가져올 때

git cherry-pick [시작커밋해시] [끝커밋해시]

git cherry-pick 도중 conflict 가 발생하면 conflict를 해결한 후 git cherry-pick --continue 로 cherry-pick을 이어나갈 수 있습니다.

실제 프로젝트에 적용하기


위의 지식을 갖추고 실제 프로젝트에 적용해봅시다.

1. develop 브랜치에서 feature 브랜치를 생성합니다.

git checkout develop
git pull
git checkout -b feature/feature1

2. feature 브랜치에서 기능을 개발하고 커밋합니다.

git add files
git commit -m "feat : Add something"

3. rebase로 커밋 로그를 정리합니다.

git chekcout devleop
git pull
git checkout feature/feature1
git rebase develop feature/feature1

4. Pull Request를 요청합니다.

git push -f origin feature/feature1

[PR]
origin feature/feature1 -> origin develop

5. PR 수정 요청사항을 수정하고 squash하고 force push합니다.

// 수정 요청사항 수정후

git rebase -i HEAD~n

// squash, 커밋 메세지 변경 등의 작업 진행

git push -f origin feature/feature1

6. PR 요청 후 작업 하던 커밋을 cherry-pick 으로 새로운 브랜치에 가져옵니다.

git fetch  // 원격 저장소의 상황을 가져옵니다
git stash  // 작업중이던 내용을 임시 보관합니다.
git checkout develop
git develop pull
git checkout -b feature/feature2
git cherry-pick [작업했던 커밋해시]
git branch -d feature/feature1  // 이전에 작업한 브랜치는 삭제합니다.

+추가 내용


저도 깃 협업을 준비하면서 이것 저것 찾아보며 작성한 글이라 부족한 점이 있습니다. 잘못된 점은 댓글로 남겨주시면 수정하도록 하겠습니다!

Git GUI Client

깃을 사용하다 보면 명령어가 편하신 분도 계시겠지만 역시 한눈에 보고 마우스 클릭 몇번으로 깃 명령어를 실행하는게 직관적이고 편합니다. 이런 도구가 깃 GUI 클라이언트입니다. 대표적으로 소스트리와 깃크라켄이 있습니다. 자세한 설명은 생략하겠습니다.

Source Tree


무료입니다. 트렐로, 지라, 비트버킷을 만든 회사에서 만들었고 오래되었습니다. 저도 예전에는 소스트리를 1년정도 사용했었습니다.
https://www.sourcetreeapp.com/

Git Kraken


유료입니다. 어느날 혜성같이 등장해 많이 사용됩니다. 제 경험상 깃크라캔을 쓰니까 다시 소스트리로 못돌아갔습니다.
https://www.gitkraken.com/

profile
유니티 개발을 조금씩 해왔습니다.

3개의 댓글

comment-user-thumbnail
2020년 9월 21일

저도 git extensions 씁니다. 보기엔 안이뻐도 기능이 마음에 들어 크라켄 넘어갈 기회가 있었는데도 못떠나네요

답글 달기
comment-user-thumbnail
2020년 10월 9일

저도 전회사부터, 지금회사까지 Git Kraken 구입해서 사용하고 있는데
너무 만족하고 사용하고 있습니다.
매우 편하지요!
안써보신들 꼭 써보시길!

답글 달기