Git

Git이란 버전 관리 시스템(VCS, Version Control System)의 한 종류입니다.

Git은 리눅스의 아버지라고 불리는 리누스 토발즈(Linus Benedict Torvalds)에 의해서 만들어졌습니다. 그는 프로그램을 개발하면서 소스코드를 관리하는 프로그램의 필요성을 느꼇지만, 현재 널리 사용되고있는 프로그램에 만족을 못하고 직접 Git을 제작하였다고 한다.

버전 관리 시스템(Version Control System) CVS , 머큐리얼, SVN , Git , 비트버킷등 다양한 버전관리시스템이 존재합니다. 그 중에서 Git은 현재 가장 많은 개발자가 선택하고 있는 버전관리시스템 입니다.

Git vs SVN

**형상관리툴의 종류**

  • Client/Server 타입 : Subversion(SVN), CVS, Perforce, ClearCase, TFS
  • 분산저장소 타입 : Git, Mercurial, Bitkeeper, SVK, Darcs
  • Folder 공유 타입 : RCS, SCCS

이 중 가장 많이 사용되었던 SVN과 현재 가장 많이 사용하고 있는 Git을 비교해 보겠습니다.

SVN

  1. 소스코드의 효율적인 관리를 위한 형상 관리 도구
  2. 중앙 집중식 소스 관리 (개념적으로 이해, 사용하기 쉬움)
  3. SVN은 보통 대부분의기능을 완성해놓고 소스를 중앙 저장소에 COMMIT한다.
  4. 개발자가 자신만의 version history를 가질 수 없다. (local history를 사용하지만 일시적, 내가 몇일전 까지 했던 작업 내역을 확인 가능하지만 버전관리가 되지 않는다.)
  5. 프로젝트 소스는 SVN 서버의 Trunk라는 곳에 위치 -> 자신의 Local에 Trunk의 소스를 다운 받아(update) 수정 및 추가 후 다시 업로드(commit)하는 방식자신만의 소스를 다른 개발자들과 떨어져서 작업하려면 Branch(원 소스의 나뭇가지)를 만들어 작업 후 자기자신만 접근하여 개발하며 완성되면 Merge 기능을 사용하여 Trunk와 소스를 합치면 된다.
  6. SVN최대 장점은 직관적이다. 하지만 두 사람이 하나의 파일을 동시에 수정하고 커밋하였을 때 충돌이 일어날 확률이 높아진다.

GIT

  1. 소스코드의 효율적인 관리를 위한 형상 관리 도구
  2. 매우 빠른 속도의 분산형 저장소. SVN보다 많은 기능을 지원하는 대신 익숙해지는데 더많은 시간이 필요하다.
  3. 여러명이 동시에 작업하는 병렬 개발이 가능하다.
  4. 소스를 최신으로 유지하면서 개발자들이 원하는 때에 원하는 만큼 수정이 가능

git은 개발자가 자신만의 commit history를 가질 수 있고, 개발자와 서버의 저장소는 독립적으로 관리가 가능합니다.

Git 특징

  • 거의 모든 명령을 로컬에서 실행
  • 차이가 아니라 스냅샷

Subversion과 Subversion 등과 Git의 가장 큰 차이점은 데이터를 다루는 방법에 있습니다. 큰 틀에서 봤을 때 VCS 시스템 대부분은 관리하는 정보가 파일들의 목록입니다. CVS, Subversion, Perforce, Bazaar 등의 시스템은 각 파일의 변화를 시간순으로 관리하면서 파일들의 집합을 관리합니다.

..\assets\post_img\git\deltas.png

(각 파일에 대한 변화를 저장하는 시스템들)

Git은 이런 식으로 데이터를 저장하지도 취급하지도 않습니다. 대신 Git은 데이터를 파일 시스템 스냅샷의 연속으로 취급하고 크기가 아주 작습니다. Git은 커밋하거나 프로젝트의 상태를 저장할 때마다 파일이 존재하는 그 순간을 중요하게 여깁니다. 파일이 달라지지 않았으면 Git은 성능을 위해서 파일을 새로 저장하지 않습니다. 단지 이전 상태의 파일에 대한 링크만 저장합니다. Git은 데이터를 스냅샷의 스트림처럼 취급합니다.

..\assets\post_img\git\snapshots.png

(시간순으로 프로젝트의 스냅샷을 저장)

이것이 Git이 다른 VCS와 구분되는 점입니다. 이점 때문에 Git은 다른 시스템들이 과거로부터 답습해왔던 버전 컨트롤의 개념과 다르다는 것이고 많은 부분을 새로운 관점에서 바라봅니다.

  • Git의 무결성

Git은 데이터를 저장하기 전에 항상 체크섬을 구하고 그 체크섬으로 데이터를 관리합니다. 쉽게 말하면 해당 커밋의 고유번호입니다. 체크섬은 Git에서 사용하는 가장 기본적인(Atomic) 데이터 단위이자 Git의 기본 철학입니다.

Git은 SHA-1 해시를 사용하여 체크섬을 만듭니다. 만든 체크섬은 40자 길이의 16진수 문자열입니다. 파일의 내용이나 디렉토리 구조를 이용하여 체크섬을 구한다. SHA-1은 아래처럼 생겼습니다.

24b9da6552252987aa493b52f8696cd6d3b00373

실제로 Git은 파일을 이름으로 저장하지 않고 해당 파일의 해시로 저장합니다.

  • Git은 데이터를 추가할 뿐

Git은 되돌리거나 데이터를 삭제할 방법이 없다. 다른 VCS처럼 Git도 커밋하지 않으면 변경사항을 잃어버릴 수 있습니다. 하지만, 일단 스냅샷을 커밋하고 나면 데이터를 잃어버리기 어렵습니다. (커밋을 돌리고 강제로 원격에 올리는 방법이 있긴 합니다…)

용어 정리

Repository : 프로젝트가 거주할 수 있는 디렉토리나 저장 공간. 로컬 폴더가 될 수도 있고, 깃허브나 다른 온라인 호스트의 저장 공간이 될 수도 있다. 저장소 안에 코드 화일, 텍스트 화일, 이미지 화일을 저장하고, 이름붙일 수 있다.

Remote : 원격 저장소

Commit : 현재 변경된 작업 상태를 점검을 마치면 확정하고 저장소에 저장하는 작업이다. “스냅샷”을 찍어, 프로젝트를 이전의 어떠한 상태로든 복원할 수 있는 체크포인트를 가질 수 있다.

Branch : 가지 또는 분기점을 의미하며, 작업을 할때에 현재 상태를 복사하여 Branch에서 작업을 한 후에 Merge하는 작업을 한다.

Merge : 다른 Branch의 내용을 현재 Branch로 가져와 합치는 작업을 의미한다.

Head : 현재 작업중인 Branch를 가리키는 포인터이다.

Staging Area : 저장소에 커밋하기 전에 커밋을 준비하는 위치이다.

Working Tree : 저장소를 어느 한 시점을 바라보는 작업자의 현재 시점이다.

Fetch : 원격헤드를 참조해서 로컬에 없는 객체를 내려받는 작업.

Checkout : 작업자의 작업트리를 저장소의 특정 지점과 일치 하도록 변경하는 작업.

명령어 정리

git init : 깃 저장소를 초기화한다. 저장소나 디렉토리 안에서 이 명령을 실행하기 전까지는 그냥 일반 폴더이다. 이것을 입력한 후에야 추가적인 깃 명령어들을 줄 수 있다.

git config : “configure”의 준말, 처음에 깃을 설정할 때 가장 유용하다.

git help : 21개의 가장 많이 사용하는 깃 명령어들이 나타난다. “git help 명령어”를 사용하면 특정 깃 명령어를 사용하고 설정하는 법을 이해할 수도 있다.

git status : 저장소 상태를 체크. 어떤 화일이 저장소 안에 있는지, 커밋이 필요한 변경사항이 있는지, 현재 저장소의 어떤 브랜치에서 작업하고 있는지 등을 볼 수 있다.

git add : 이 명령이 저장소에 새 파일들을 추가하진 않는다. 대신, 깃이 새 화일들을 지켜보게 한다. 파일을 추가하면, 깃의 저장소 “스냅샷”에 포함된다.

git commit : 어떤 변경사항이라도 만든 후, 저장소의 “스냅샷”을 찍기 위해 사용한다. 보통 “git commit -m “Message hear.” 형식으로 사용한다. -m은 명령어의 그 다음 부분을 메시지로 읽어야 한다는 것을 말한다.

git branch : 여러 협업자와 작업하고 자신만의 변경을 원한다면 이 명령어로 새로운 브랜치를 만들고, 자신만의 변경사항과 파일 추가 등의 커밋 타임라인을 만든다. 새 브랜치를 “hello”로 이름을 지정하고 싶다면 “git branch hello”라고 쓸 수 있다. 뒤에 아무것도 붙이지 않으면 브랜치 목록을 볼 수 있다.

git checkout : 현재 위치하고 있지 않은 저장소를 “체크아웃”할 수 있다. 이것은 체크하길 원하는 저장소로 옮겨가게 해주는 탐색 명령이다. 만약 master 브랜치를 들여다 보고 싶으면, git checkout master를 사용할 수 있다.

git merge : 브랜치에서 작업을 끝내고, 모든 협업자가 볼 수 있는 master 브랜치로 병합할 수 있다. “git merge cats”는 “cats” 브랜치에서 만든 모든 변경사항을 master로 추가한다.

git push : 로컬 컴퓨터에서 작업하고 커밋을 원격 저장소로도 볼 수 있기를 원한다면, 이 명령어로 깃허브에 변경사항을 “push”한다.

git pull : 로컬 컴퓨터에서 작업할 때, 작업하고 있는 저장소의 최신 버전을 원하면, 이 명령어로 깃허브로부터 변경사항을 다운로드한다.

git log : 커밋 내역을 확인해보고 싶을 때 사용하는 명령어이다.

git remote : 원격 저장소 추가(add)/삭제(rm)

git clone : 원격 저장소를 복제하여 로컬 저장소를 생성한다.

git fork : 원격 저장소에 있는 다른 사람이 올린 저장소 상태를 그대로 복사해서 자신의 Github 계정에 원격 저장소를 생성하고 복제하는 기능입니다. fork한 저장소는 원본과 연결되어 있는 상태입니다. (clone은 단순 복제, fork작업에도 clone작업이 포함되어 있다고 보면됩니다. 단, 기존 프로젝트에 기역하기 위한 upstream등의 remote를 설정하고 fetch등의 작업을 하기 위한 과정이 포함되어 있다고 생각하면 됩니다.)

git blame : 코드 라인별로 커밋ID 와 커밋한 사람등의 정보를 보여준다.

git fetch : 원격 저장소의 변경사항을 가져온다.

git diff : 파일 변경사항들을 보여준다. 파일을 명령어 뒤에 입력하면 해당 파일의 변경사항을 볼 수 있다.

git stash : 워킹 디렉토리에 unstaged 파일들을 백업하고 워킹디렉토리를 깨끗한 상태 즉 HEAD의 상태로 만든다.

File 의 Three States

..\assets\post_img\git\Untitled.png

  • Committed : 데이터가 로컬 데이터베이스에 안전하게 저장됐다는 것을 의미한다.
  • Modified : 수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않은 것을 말한다.
  • Staged : 현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태를 의미한다.
  • working directory : 사용자가 실제로 작업을 하는 공간이다. 이 공간에서 파일을 수정, 추가, 삭제를 할 수 있다. 프로젝트의 특정 버전을 Checkout 한 것이라고 생각하면 된다.
  • staging area : working directory에서 바뀐 상태(수정, 추가, 삭제)를 이 공간으로 올린다. (add 한다.)
  • git directory : staging area에 올린 상태들을 repository에 올림으로써 하나의 버전을 등록하게 된다. (commit 한다.) Git이 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳을 말한다.

Git File의 Life cycle

Git으로 하는 일은 기본적으로 아래와 같다.

  1. 워킹 트리에서 파일을 수정한다.
  2. Staging Area에 파일을 Stage 해서 커밋할 스냅샷을 만든다. 모든 파일을 추가할 수도 있고 선택하여 추가할 수도 있다.
  3. Staging Area에 있는 파일들을 커밋해서 Git 디렉토리에 영구적인 스냅샷으로 저장한다.

..\assets\post_img\git\Untitled%201.png

워킹 디렉토리의 모든 파일은 크게 Tracked(관리대상임)와 Untracked(관리대상이 아님)로 나눕니다.

Tracked 파일은 이미 스냅샷에 포함돼 있던 파일입니다.

또, Tracked 파일은 Unmodified(수정하지 않음)와 Modified(수정함) 그리고 Staged(커밋으로 저장소에 기록할) 상태 중 하나의 상태를 유지합니다.

간단히 말하자면 Git이 알고 있는 파일이라는 것입니다.

그리고 나머지 파일은 모두 Untracked 파일입니다.

Untracked 파일은 워킹 디렉토리에 있는 파일 중 스냅샷에도 Staging Area에도 포함되지 않은 파일입니다.

처음 저장소를 Clone 하면 모든 파일은 Tracked이면서 Unmodified 상태입니다.

파일을 Checkout 하고 나서 아무것도 수정하지 않았기 때문에 그렇습니다.

마지막 커밋 이후 아직 아무것도 수정하지 않은 상태에서 어떤 파일을 수정하면 Git은 그 파일을 Modified 상태로 인식합니다.

실제로 커밋을 하기 위해서는 이 수정한 파일을 Staged 상태로 만들고, Staged 상태의 파일을 커밋합니다.

이러한 라이프사이클을 계속 반복하게 됩니다.

변경 된 파일을 local repo에 commit 하기 전에, git add 명령어로 staging area영역으로 올리는데 이 때, 파일은 staged 상태가 되었다고 할 수 있습니다. 이 상태에선 commit을 할 수 있으며 commited 상태가 되면 local repo에 commit 되었다고 할 수 있습니다.

단순히 파일을 변경할 경우, working directory 영역에서 modified 상태가 되며 commit을 할 수 없습니다. git add 명령어로 staged 상태로 변경해야만 commit이 가능합니다.

기본적인 흐름

..\assets\post_img\git\Untitled%202.png

브랜치

모든 버전 관리 시스템은 브랜치를 지원합니다. 개발을 하다 보면 코드를 여러 개로 복사해야 하는 일이 자주 생깁니다. 코드를 통째로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발을 진행할 수 있는데, 이렇게 독립적으로 개발하는 것이 브랜치입니다.

브랜치란?

Git은 데이터를 Change Set이나 변경사항(Diff)으로 기록하지 않고 일련의 스냅샷으로 기록합니다.

커밋하면 Git은 현재 Staging Area 에 있는 데이터의 스냅샷에 대한 포인터저자나 커밋 메시지 같은 메타데이터이전 커밋에 대한 포인터 등을 포함하는 커밋 개체를 저장합니다.

여기서 이전 커밋 포인터가 있기 때문에 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있습니다. 최초 커밋을 제외한 나머지 커밋은 이전 커밋 포인터가 적어도 하나씩 있고 브랜치를 합친 Merge 커밋 같은 경우에는 이전 커밋 포인터가 여러 개 있습니다.

Git의 브랜치는 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것입니다. 기본적으로 Git은 master 브랜치를 만듭니다. 처음 커밋하면 이 master 브랜치가 생성된 커밋을 가리킵니다. 이후 커밋을 만들면 master 브랜치는 자동으로 가장 마지막 커밋을 가리킵니다.

브런치 생성 과정

..\assets\post_img\git\Untitled%203.png

git branch testing

기존에 작업하고 있던 master 브랜치에서 testing 이라는 브랜치를 만들어보겠습니다.

Git은 HEAD 라는 특수한 포인터가 있습니다. 이 포인터는 지금 작업하는 로컬 브랜치를 가리킵니다. 브랜치를 새로 만들었지만, Git은 아직 master 브랜치를 가리키고 있습니다. git branch 명령은 브랜치를 만들기만 하고 HEAD가 가리키는 브랜치를 옮기지 않습니다.

..\assets\post_img\git\Untitled%204.png

$ git checkout testing

git checkout 명령으로 다른 브랜치로 이동할 수 있습니다.

위와 같은 명령어를 사용하면 HEAD는 testing 브랜치를 가리킵니다.

..\assets\post_img\git\Untitled%205.png

vim test.rb
git commit -a -m 'made a change'

새로 커밋해서 testing 브랜치는 앞으로 이동했습니다. 하지만, master 브랜치는 여전히 이전 커밋을 가리킵니다.

..\assets\post_img\git\Untitled%206.png

git checkout master

위 명령이 하는 일은 두 가지입니다.

master 브랜치가 가리키는 커밋을 HEAD가 가리키게 하고, 워킹 디렉토리의 파일도 그 시점으로 되돌려 놓았습니다. 앞으로 커밋을 하면 다른 브랜치의 작업들과 별개로 진행되기 때문에 testing 브랜치에서 임시로 작업하고 원래 master 브랜치로 돌아와서 하던 일을 계속할 수 있습니다.

..\assets\post_img\git\Untitled%207.png

vim test.rb
git commit -a -m 'made other changes'

이제 브랜치가 갈라지게 되었습니다. 두 작업 내용은 서로 독립적으로 각 브랜치에 존재합니다. 커밋 사이를 자유롭게 이동하다가 때가 되면 두 브랜치를 Merge 하면 됩니다.

실제로 Git의 브랜치는 어떤 한 커밋을 가리키는 40글자의 SHA-1 체크섬 파일에 불과하기 때문에 만들기도 쉽고 지우기도 쉽습니다. 새로 브랜치를 하나 만드는 것은 41바이트 크기의 파일을(40자와 줄 바꿈 문자) 하나 만드는 것에 불과합니다.

브랜치가 필요할 때 프로젝트를 통째로 복사해야 하는 다른 버전 관리 도구와 Git의 차이는 극명합니다. 통째로 복사하는 작업은 프로젝트 크기에 따라 다르겠지만 수십 초에서 수십 분까지 걸립니다. 그에 비해 Git은 순식간입니다.

게다가 커밋을 할 때마다 이전 커밋의 정보를 저장하기 때문에 Merge 할 때 어디서부터(Merge Base) 합쳐야 하는지 압니다. 이러한 특징이 기존VCS에서 Git으로 많은 개발자들이 옮겨가는 가장 특징이라고 생각합니다.

Git의 Merge와 Rebase의 차이

Merge는 branch를 통합하는 것이고, Rebase는 branch의 base를 옮긴다는 개념의 차이가 있습니다.

..\assets\post_img\git\Untitled%208.png

  • B 지점을 base로 가진 branch가 D, E 커밋을 진행 한다.
  • C 지점으로 base를 이동하기 위해 branch에서 C 지점으로 rebase를 한다.
  • C 지점으로 rebase 되면 기존 D, E 커밋은 새롭게 정렬되어 C 지점 이후로 변경된다.

Rebase 장점

  • 히스토리를 단순하고 깔끔하게 유지 가능하다.
  • 여러 개발자들이 같은 브랜치를 공유할 때 커밋을 합치는 가장 직관적이고 깔끔한 방법.

Rease 단점

  • 충돌 상황에서 다소복잡하다. 커밋 순서대로 Rebase를 하는데, 각 커밋마다 충돌해소를 순서대로 해주어야 한다.
  • 해당 커밋들을 다른 곳에 푸시한 적이 있다면 히스토리를 다시 쓰는것에 부작용이 발생한다.

Merge 장점

  • 이해하기쉽다, 원래 브랜치의 컨텍스트를 유치한다. Fast-Forward Merge를 하지 않는다면 브랜치 별로 커밋을 분리해 유지한다. 이러한 기능은 브랜치에 유용하다.
  • 원래 브랜치의 커밋들은 변경되지 않고 계속 유지되어 다른 개발자들의 작업과 공유되는 것에 대해 신경쓸 필요가없다.

Merge 단점

  • 단순히 모든 사람들이 같은 브랜치에서 작업하기 때문에 커밋 히스토리 상으로 복잡하다.

branch workflow

Long-Running 브랜치

..\assets\post_img\git\Untitled%209.png

배포했거나 배포할 코드만 master 브랜치에 Merge 해서 안정 버전의 코드만 master 브랜치에 둡니다.

개발을 진행하고 안정화하는 브랜치는 develop 이나 next 라는 이름으로 추가로 만들어 사용합니다. 이 브랜치는 언젠가 안정 상태가 되겠지만, 항상 안정 상태를 유지해야 하는 것이 아닙니다. 테스트를 거쳐서 안정적이라고 판단되면 master 브랜치에 Merge 합니다.

토픽 브랜치에도 적용할 수 있는데, 해당 토픽을 처리하고 테스트해서 버그도 없고 안정적이면 그때 Merge합니다.

..\assets\post_img\git\Untitled%2010.png

코드를 여러 단계로 나누어 안정성을 높여가며 운영할 수 있습니다. 프로젝트 규모가 크면 proposed 혹은 pu (proposed updates)라는 이름의 브랜치를 만들고 next 나 master 브랜치에 아직 Merge 할 준비가 되지 않은 것을 일단 Merge합니다.

중요한 개념은 브랜치를 이용해 여러 단계에 걸쳐서 안정화해 나아가면서 충분히 안정화가 됐을 때 안정 브랜치로 Merge 한다는 점입니다.

토픽 브랜치

토픽 브랜치는 어떤 한 가지 주제나 작업을 위해 만든 짧은 호흡의 브랜치입니다.

..\assets\post_img\git\Untitled%2011.png

..\assets\post_img\git\Untitled%2012.png

리모트 브랜치

리모트 브랜치란 리모트 저장소에 있는 브랜치를 말합니다.

리모트 Refs는 리모트 저장소에 있는 포인터인 레퍼런스다. 리모트 저장소에 있는 브랜치, 태그, 등등을 의미합니다. git ls-remote [remote] 명령으로 모든 리모트 Refs를 조회할 수 있습니다. git remote show [remote] 명령은 모든 리모트 브랜치와 그 정보를 보여줍니다. 리모트 Refs가 있지만 보통은 리모트 트래킹 브랜치를 사용합니다.

리모트 트래킹 브랜치는 리모트 브랜치를 추적하는 레퍼런스이며 브랜치입니다. 리모트 트래킹 브랜치는 로컬에 있지만 임의로 움직일 수 없습니다. 리모트 서버에 연결할 때마다 리모트의 브랜치 업데이트 내용에 따라서 자동으로 갱신될 뿐입니다. 리모트 트래킹 브랜치는 일종의 북마크라고 할 수 있습니다. 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타냅니다.

리모트 트래킹 브랜치의 이름은 / 형식으로 되어 있습니다.

예를 들어 리모트 저장소 origin 의 master 브랜치를 보고 싶다면 origin/master 라는 이름으로 브랜치를 확인하면 됩니다. 다른 팀원과 함께 어떤 이슈를 구현할 때 그 팀원이 iss53 브랜치를 서버로 Push 했고 당신도 로컬에 iss53 브랜치가 있다고 가정합니다. 이때 서버의 iss53 브랜치가 가리키는 커밋은 로컬에서 origin/iss53이 가리키는 커밋입니다.

Note

“origin” 의 의미

브랜치 이름으로 많이 사용하는 “master” 라는 이름이 괜히 특별한 의미를 가지는 게 아닌 것처럼 “origin” 도 특별한 의미가 있는 것은 아니다. git init 명령이 자동으로 만들기 때문에 사용하는 이름인 “master” 와 마찬가지로 “origin” 도 git clone 명령이 자동으로 만들어주는 리모트 이름이다. git clone -o booyah 라고 옵션을 주고 명령을 실행하면 booyah/master 라고 사용자가 정한 대로 리모트 이름을 생성해준다.

Git Flow(https://nvie.com/posts/a-successful-git-branching-model/)

..\assets\post_img\git\Untitled%2013.png

Git-flow는 브랜치를 크게 4가지로 나누어 개발하는 전략입니다.

Git-flow는 Git이 새롭게 활성화되기 시작하는 2010년에 Vincent Driessen이라는 사람의 블로그 글에 의해 널리 퍼지기 시작했고 현재는 Git으로 개발할 때 거의 표준과 같이 사용되는 방법론입니다.

Git-flow는 총 5가지의 브랜치를 사용해서 운영을 합니다.

  • master : 기준이 되는 브랜치로 제품을 배포하는 브랜치 입니다. 제품으로 출시될 수 있는 브랜치.
  • develop : 개발 브랜치로 개발자들이 이 브랜치를 기준으로 각자 작업한 기능들을 Merge합니다. 다음 출시 버전을 개발하는 브랜치.
  • feature : 단위 기능을 개발하는 브랜치로 기능 개발이 완료되면 develop 브랜치에 합칩니다. 기능을 개발하는 브랜치.
  • release : 배포를 위해 master 브랜치로 보내기 전에 먼저 QA를 하기위한 브랜치 입니다. 이번 출시 버전을 준비하는 브랜치.
  • hotfix : master 브랜치로 배포를 했는데 버그가 생겼을 때 긴급 수정하는 브랜치 입니다. 출시 버전에서 발생한 버그를 수정 하는 브랜치.

master와 develop가 중요한 매인 브랜치이고 나머지는 필요에 의해서 운영하는 브랜치

사용법

  1. 일단 master 브랜치에서 시작을 합니다.
  2. 동일한 브랜치를 develop에도 생성을 합니다. 개발자들은 이 develop 브랜치에서 개발을 진행합니다. 상시로 버그를 수정한 커밋들이 추가됩니다.
  3. 개발을 진행하다가 회원가입, 장바구니 등의 새로운 기능 구현이 필요할 경우 A개발자는 develop 브랜치에서 feature 브랜치를 하나 생성해서 회원가입 기능을 구현하고 B개발자도 develop 브랜치에서 feature 브랜치를 하나 생성해서 장바구니 기능을 구현합니다.
  4. 완료된 feature 브랜치는 검토를 거쳐 다시 develop 브랜치에 merge합니다.
  5. 이제 모든 기능이 완료되면 develop 브랜치를 release 브랜치로 만듭니다. 그리고 QA를 하면서 보완점을 보완하고 버그를 픽스합니다.
  6. 모든 것이 완료되면 이제 release 브랜치를 master 브랜치와 develop 브랜치로 merge합니다. master 브랜치에서 버전추가를 위해 태그를 하나 생성하고 배포를 합니다.
  7. 배포를 했는데 미처 발견하지 못한 버그가 있을 경우 hotfixes 브랜치를 만들어 긴급 수정 후 태그를 생성하고 바로 수정 배포를 합니다.

GitHub flow(https://guides.github.com/introduction/flow/)

..\assets\post_img\git\Untitled%2014.png

브랜치 보다는 Fork와 Pull requests를 활용하여 구현을 합니다. Git-flow가 Github에서 사용하기에는 복잡하다고 나온 브랜칭 전략입니다, 흐름이 단순한 만큼 role도 단순합니다. master 브랜치에 대한 role만 정확하다면 나머지 브랜치들에 대해서는 관여하지 않습니다. 즉, hotfix 브랜치나 feature 브랜치를 구분하지 않습니다. 다만 우선순위가 다를 뿐입니다. pull request 기능을 사용하도록 권장합니다.

Fork는 브랜치와 비슷하지만 프로젝트를 통째로 외부로 복제해서 개발을 하는 방식입니다. 그렇게 개발을 해서 브랜치처럼 머지(Merge)를 바로 하는 것이 아니라 Pull requests로 원 프로젝트 관리자에서 머지 요청을 보내면 원 프로젝트 관리자가 Pull requests된 코드를 보고 적절하다 싶으면 그때 그 기능을 붙히는 식으로 개발을 합니다.

사용법

..\assets\post_img\git\Untitled%2015.png

1. master 브랜치는 어떤 때든 배포가 가능하다

  • master 브랜치는 항상 최신 상태며, stable 상태로 product에 배포되는 브랜치
  • 이 브랜치에 대해서는 엄격한 role과 함께 사용한다.
  • merge하기 전에 충분히 테스트를 해야한다. 테스트는 로컬에서 하는 것이 아니라 브랜치를 push 하고 Jenkins로 테스트 한다

..\assets\post_img\git\Untitled%2016.png

2. master에서 새로운일을 시작하기 위해 브랜치를 만든다면, 이름을 명확히 작성하자

  • 브랜치는 항상 master 브랜치에서 만든다.
  • Git-flow와는 다르게 feature 브랜치나 develop 브랜치가 존재하지 않는다.
  • 새로운 기능을 추가하거나, 버그를 해결하기 위한 브랜치 이름은 자세하게 어떤 일을 하고 있는지에 대해서 작성해야합니다.
  • 커밋메시지를 명확하게 작성해야합니다.

3. 원격지 브랜치로 수시로 push 하자

  • Git-flow와 상반되는 방식
  • 항상 원격지에 자신이 하고 있는 일들을 올려 다른 사람들도 확인할 수 있도록 해준다
  • 이는 하드웨어에 문제가 발생해 작업하던 부분이 없어지더라도, 원격지에 있는 소스를 받아서 작업할 수 있도록 해준다

..\assets\post_img\git\Untitled%2017.png

4. 피드백이나 도움이 필요할 때, 그리고 merge 준비가 완료되었을 때는 pull request를 생성한다

  • pull request는 코드 리뷰를 도와주는 시스템
  • 이것을 이용해 자신의 코드를 공유하고, 리뷰받자
  • merge 준비가 완료되었다면 master 브랜치로 반영을 요구하자

..\assets\post_img\git\Untitled%2018.png

..\assets\post_img\git\Untitled%2019.png

5. 기능에 대한 리뷰와 논의가 끝난 후 master로 merge한다

  • 곧장 product로 반영이될 기능이므로, 이해관계가 연결된 사람들과 충분한 논의 이후 반영하도록 한다
  • 물론 CI도 통과해야한다!

..\assets\post_img\git\Untitled%2020.png

6. master로 merge되고 push 되었을 때는, 즉시 배포되어야한다

  • GitHub-flow의 핵심
  • master로 merge가 일어나면 자동으로 배포가 되도록 설정해놓는다

GitLab Flow(https://docs.gitlab.com/ee/topics/gitlab_flow.html)

Git Flow의 문제점

GitLab Flow가 해결하고자 하는 문제점을 살펴보면 GitLab Flow가 어떻게 동작하는지 이해하기 쉽습니다. Git Flow에서는 두 가지의 주요 포인트가 있는데, 두 가지 모두 불필요한 브랜치간의 변환 작업을 수반합니다.

Git Flow는 개발자가 master브랜치보다 develop브랜치를 사용하도록 강제합니다. 그런데 많은 도구는 master브랜치에 사용하는 것을 Default로 하고 있어서 브랜치 간 변환 작업의 양이 아주 많아지게 됩니다. 또 다른 비효율은 hotfix브랜치에 업데이트하는 작업인데, 이 작업은 지속 배포 (Continuous Delivery) 구조를 갖춘 대부분의 조직들에게는 필요 없는 작업입니다.

GitLab은 위 문제를 간단하면서도 포괄적으로 해결하기 위해 GitLab Flow가 만들어졌습니다.

GitLab Flow : 단순화된 브랜치 전략

GitLab Flow는 기능 중심 개발 (feature-driven)과 이슈 트래킹 시스템에 연계되는 기능 개발 브랜치 (feature branch)를 합친 개념입니다. GitLab Flow는 Git 워크플로우와 이슈 트래킹 시스템을 연동 및 통합시킴으로써 단순하고 투명하며 효율적인 Git 작업을 가능하게 합니다.

GitLab Flow는 코드와 이슈 트래커의 연계를 더욱더 투명하게 보여줍니다. 이슈 트래킹 시스템으로부터 모든 코드 베이스 변화 업무가 시작됩니다. 코딩을 끝냈거나 코드에 대해 협의하고 싶다면 merge request를 열 수 있습니다. 코드가 준비되었다면 승인권자는 코드를 master브랜치에 반영되도록 승인하고, 이는 추후 쉽게 확인할 수 있도록 기록이 남습니다. GitLab Flow를 사용함으로써 개발자 및 직원들은 master브랜치를 운영용 브랜치에 merge함으로써 새로운 버전의 코드를 배포할 수 있으며 어떤 코드가 운영 상태에 있는지 쉽게 구분할 수 있습니다. GitLab Flow에서는 커밋은 다운 스트림으로만 동작하므로 모든 환경에서 테스트 되었음을 알 수 있습니다.

GitLab Flow는 Git Flow에서 자주 있는 릴리즈, 태깅, 머지 측면에서의 비효율성을 제거합니다.

GitLab Flow를 간단히 소개하면 아래와 같습니다.

  • 모든 기능과 변경 점은 master브랜치로 향함
  • 버그 픽스, 핫 픽스 패치들은 우선 master브랜치에서 선별적으로 수용됨
  • production 브랜치가 존재하여 커밋한 내용들을 일방적으로 디플로이를 하는 형태. GitHub에서 브랜치 하나를 더 구성하여 사용하는 이것도 조금은 간단한 구성이다.
  • master와 production 사이에 pre-production을 두어 개발한 내용을 곧장 반영하지 않고 시간을 두고 반영을 해도 된다.
  • release한 브랜치를 두고서 보안상 문제가 발생한 것이나 백포트를 위해서 작업을 할 경우, cherry-pick을 이용해서 작업을 진행할 수 도 있다. 아니면 해당 릴리즈에서 발생하는 버그들을 묶어서 수정하는 방식을 진행하며된다. 일반적으로 말하는 ‘upstream first’ 정책이라고 보면된다.

..\assets\post_img\git\Untitled%2021.png

..\assets\post_img\git\Untitled%2022.png

..\assets\post_img\git\Untitled%2023.png

크게 보아 GitLab Flow는 다음 3개 영역으로 나뉩니다.

  • 기능 브랜치 (feature branch)
  • 운영 브랜치 (production branch)
  • 릴리즈 브랜치 (release branch)

기능 브랜치는 실질적인 개발 작업이 일어나는 공간입니다. 개발자는 기능을 개발하거나 버그 픽스를 만들거나 하는 일들을 master브랜치가 아니라 기능 브랜치에서 수행하게 됩니다. 작업이 완료되면, 개발자는 merge request를 생성하여 작업물을 master브랜치로 merge 합니다.

production브랜치는 기본적으로 단일 구조입니다. 개별 브랜치들이 각각 운영되기보다는 하나의 브랜치가 운영상태에서 오랫동안 운영되는 형태입니다. 세부적인 변화를 추적하기 위해서 각각의 배포 버전에 대해 태깅을 하는 것은 가능합니다.

마지막 브랜치 종류인 릴리즈 브랜치는 매우 중요합니다. 안정적인 분기를 만들고 가능한 한 늦게 분기하십시오. 이렇게하면 여러 분기에 버그 수정을 적용해야하는 시간을 최소화 할 수 있습니다. 릴리스 브랜치를 발표 한 후에는 심각한 버그 수정 만 브랜치에 추가하십시오. 가능하면 먼저 이러한 버그 수정을에 병합 한 다음 master릴리스 브랜치로 체리를 선택하십시오. 릴리스 브랜치에 버그 수정을 포함 할 때마다 새 태그를 설정 하여 패치 버전을 늘 립니다.

다시 정리하면 모든 개발은 feature 를 따서 진행하고, 개발이 완료되면 master 로 merge request 를 보내서 merge합니다. 그러고 나서 master 에서 많은 test 가 진행이 되고나서, stable 한 버전을 하나 만들 때 production branch 로 merge 를 해서 tag 를 붙이면 됩니다. 그래서 이 production branch 는 계속 유지가 된다.

production branch 를 2개를 둘 수도 있습니다. pre-production, production 그래서 pre-production 에서 흔히 test server 에 deploy 를 하고, 이후에 여기서 다시 실제 staging version 으로 production branch 를 뽑는 방식으로 사용하는 듯 합니다.

기본적으로 따라야 할 규칙(https://about.gitlab.com/topics/version-control/what-are-gitlab-flow-best-practices/)

GitLab Flow 전체를 따르고 싶지 않으시다면 다음의 규칙은 숙지하시는 것이 좋습니다. GitLab에서는 GitLab Flow를 통해 효율적이고 깨끗한 결과를 만들기위한 11가지 규칙을 말했습니다.

    1. 메인 브랜치에서 직접 커밋보다는 기능 브랜치를 사용합니다.
  1. 모든 커밋을 테스트하십시오 : 모든 사항이 마스터 브랜치로 반영 (merge) 되기를 기다리지 않는 것이 좋습니다. 문제점을 최대한 빨리 찾아내기 위해서는 커밋되는 순간 테스트하는 것이 좋습니다.
  2. 모든 종류의 테스트를 거치십시오 : 병렬 테스트라고 할지라도 모든 종류의 테스트를 하는 것이 좋습니다.
  3. 코드 리뷰 후에는 마스터 브랜치로 merge 하십시오 : 기다릴 이유가 있나요? “한꺼번에 테스트하지 마시고, 매 순간 테스트하시는 것을 권합니다. 여러분들께서 직접 문제점을 찾아낼 가능성이 크고, 동료들의 도움을 받을 수도 있습니다.” 문제를 일으킬 수있는 이슈를 식별 할 가능성이 더 높기 때문에 코드 검토는 가능한 한 빨리 이루어져야합니다.
  4. 배포는 분기 또는 태그를 기반으로 자동으로 이루어집니다. : 개발자가 main 매번 배포하고 싶지 않은 경우 production 브랜치를 만들 수 있습니다 . 스크립트를 사용하거나 수동으로 수행하는 대신, 자동화를 사용하거나 프로덕션 배포를 트리거하는 특정 브랜치를 만들 수 있습니다 .
  5. 태그는 CI가 아닌 사용자가 설정합니다.
  6. 릴리스는 태그를 기반으로합니다.
  7. 푸시 된 커밋은 리베이스되지 않습니다.
  8. 모두가 메인에서 시작하고 메인을 목표로합니다. : 개발자는 체크 아웃하고 main, 기능을 빌드하고, 병합 요청을 만들고, main 다시 타겟팅 합니다.
  9. 버그를 첫 번째로 메인, 두 번째로 릴리스 브랜치를 수정합니다. : 개발자는 버그를 찾게되면 메인에 푸시를 하고, patch-realse 브랜치에 cherry-pick을 해야합니다.
  10. 커밋 메시지는 의도를 반영합니다.

결론

전략에 따라 장단점이 존재하지만, 절대적으로 좋다 나쁘다라고 단정짓기 어렵습니다.

브랜칭과 배포에 대한 전략은 상황에 따라 바뀔 수 있습니다.

조직의 규모, 서비스의 특징, 프로젝트에 참여하고 있는 구성원들이 제각기 다르기 때문입니다.

깃허브 = 커리어

최근, 오픈소스 소프트웨어가 트렌드 중 하나가 되면서, 개발자의 github와 github의 contribution이 커리어와 개발에 대한 열정을 보여줄 수 있는 하나의 지표가 되었습니다. 이글을 읽으시는 여러분도 오픈소스 기여와 토이 프로젝트들을 열심히 하시고 잘 관리하시면 좋을 듯 합니다.

..\assets\post_img\git\Untitled%2024.png

제 github contribution입니다. 여기를 잔디밭으로 만드는 것이 제 소소한 버킷리스트 중 하나 입니다.