Search
Duplicate

[스크랩] Git Flow와 자주 사용되는 Git 명령어들

Git Flow는 git을 통해 효율적으로 프로젝트를 관리하고 배포하기 위한 전략이다. 기본적으로 Git은 로컬 저장소와 원격 저장소간의 동기화를 위해 아래와 같은 과정을 거친다.
하지만 프로젝트의 규모가 커지고 협업하는 동료들이 많아진다면 저장소의 master branch만을 이용하는 것에서 이슈에 따라 다양한 branch를 통해 다양한 인원이 독립적으로 개발이 가능한 전략이 필요하다.

Git Flow

Git Flow는 다양한 branch를 관리하고 통합하기 위한 전략 중 하나이다. 최근에는 Git Flow의 단점을 해소하기 위해 Github Flow, Gitlab Flow 등 다양한 전략이 있지만 이 문서에서는 가장 기본이 되는 Git Flow를 설명하고 여기에 필요한 기본적인 Git 명령어에 대해 알아보도록 하겠다.

브랜치 전략

Git Flow의 주요 브랜치는 master와 develop 이며, 이 두 브랜치를 중심으로 feature, release와 필요에 따라 hotfixes 브랜치를 정의한다.

master

master 브랜치에 merge된 내역은 새로운 버전이 갱신되었다는 것을 의미한다. 즉 master 브랜치에 변경 내역이 생기면 최종 버전인 Tag를 통해 Production에 배포된다.

develop

hotfix를 제외한 모든 변경내역이 출발하는 지점이다. develop 브랜치의 코드가 안정화되고 배포할 준비가 되면 master를 통해 배포 버전의 태그를 단다.

feature

feature 브랜치는 배포하려고 하는 기능을 개발하는 브랜치다. 기능을 개발하기 시작할 때는 언제 배포할 수 있을지 알 수 없다. 기능을 다 완성할 때까지 유지하고 있다가 다 완성되면 develop 브랜치로 병합한다.
브랜치가 생성되는 대상 : develop
merge 대상: develop

release

release 브랜치는 실제 배포할 상태가 된 경우에 생성하는 브랜치다.
브랜치가 생성되는 대상 : develop
merge 대상: develop, master

hotfix

미리 계획되지 않은 브랜치다. 기본적인 동작방식은 release와 비슷하다. 배포 이후에 생긴 치명적인 버그는 즉시 해결해야하기 때문에 문제가 생기면 master 브랜치에 만들어둔 태그tag로 부터 긴급수정을 위한 브랜치를 생성한다.
브랜치가 생성되는 대상 : master
merge 대상 : develop, master

주요 Commands

소스코드의 origin 저장소를 초기화하고 remote 서버와 처음으로 연결할 때

최초의 프로젝트(origin)는 로컬 저장소에서 시작될 것이다. 운영체제에 git을 설치하고 여러분의 프로젝트를 관리할 원격 저장소가 준비되었다고 가정했을때 아래와 같이 git init 명령을 통해 git 프로젝트로 초기화할 수 있다.
$ echo "# Hola" > README.md $ git init
Plain Text
복사

git add, commit

git add 명령어는 git flow의 첫 단계에 해당되며 인덱스에 새로운 파일이 생겼다는 것을 알리는 행위이다. 이 상태는 저장소에는 반영이 되지 않은 상태이며 git commit 명령을 통해 비로소 저장소에 변경내역이 반영된다.
$ git add build.gradle # 특정 파일에 대한 변경 내역을 알린다. $ git add . # 모든 변경 내역을 알린다
Plain Text
복사
$ git commit -m "이 버전의 변경 내역에 대한 설명"
Plain Text
복사
git add, commit은 아래와 같이 동시에 실행할 수 있다.
$ git commit -am "이 버전의 변경 내역에 대한 설명"
Plain Text
복사

git push

commit이 완료된 시점은 변경 내용이 로컬 저장소에 HEAD안에 머물고 있음을 의미한다. 우리는 변경 내역을 동료들도 확인할 수 있도록 remote 서버에 반영할 필요가 있다.
$ git push origin master
Plain Text
복사
$ git push -u origin master $ git push # -u 옵션을 이용하면 다음 push때 이전 히스토리를 기억하고 반영한다.
Plain Text
복사

git pull

git add, commit, push 하는 일련의 과정은 내 컴퓨터에서 일어난 변경내역을 관리하고, remote 서버에 반영하는 행위라면 git pull은 remote 서버의 가장 최근의 변경 내역을 내 컴퓨터로 가져오는 행위이다.
$ git pull
Plain Text
복사
$ git pull <remote> <branch>
Plain Text
복사

새로운 기능을 위해 branch를 생성하는 방법

git은 강력한 점은 효율적으로 분산된 환경은 제공한다는 것이다. 우리는 master branch가 아닌 더욱 안전하고 격리된 상태에서 새로운 기능을 추가할 수 있다. 새로운 branch를 이용해 개발을 진행하고 개발이 완료가 되면 나중에 master 로 돌아와 merge 하는 프로세스를 의미한다.
아래의 명령을 통해 master branch에서 develop 이라는 새로운 branch를 만들고 갈아탄다.
$ git checkout -b develop
Plain Text
복사
stage라는 특정 branch로 부터 새로운 branch를 만들고 싶다면,
$ git checkout -b develop origin/stage
Plain Text
복사
아래와 같이 다시 master branch로 돌아올 수 있다.
$ git checkout master $ git branch * master stage develop
Plain Text
복사
당신이 새롭게 만든 branch는 remote 서버에 전송하기 전까지는 동료들이 접근할 수가 없다. branch에 대한 검증이 완료되면 여러분은 Github에서 Pull Request를 전송할 수 있게된다.
$ git push -u origin develop
Plain Text
복사
만약 branch를 여러명과 협업하고 있는 도중 push시에 remote 서버의 최신 내용을 로컬에 반영하지 않았다면 아래와 같이 remote 서버와 연결 후 git pull을 통해 merge 한다.
$ git branch --set-upstream-to=origin/develop develop $ git pull
Plain Text
복사

원격 저장소의 기존 branch 확인 후 로컬에 가져오기

원격 저장소의 브랜치 리스트를 조회한다.
$ git branch -r origin/develop origin/master origin/stage
Plain Text
복사
로컬, 원격 저장소의 브랜치 리스트를 모두 조회한다.
$ git branch -a master stage * develop remotes/origin/develop remotes/origin/master remotes/origin/stage
Plain Text
복사
원격 저장소의 develop이라는 branch를 로컬 저장소에 가져오고 싶다면
$ git checkout -t origin/develop Branch develop set up to track remote branch develop from origin. Switched to a new branch 'develop' $ git branch * develop master stage
Plain Text
복사
fatal: Cannot update paths and switch to branch 'develop' at the same time.이라는 에러가 발생한다면 아래와 같이 원격 저장소를 최신 상태를 로컬 저장소에 갱신한다.
$ git remote update
Plain Text
복사

원격 저장소 참고하기

어떤 경우에는 수정 내역을 원격 저장소에 push 하지는 않지만 해당 branch를 참고하기 위해 로컬에 받아서 테스트 해보고 싶은 경우도 있다.
$ git checkout <branch>
Plain Text
복사
아무런 옵션없이 원격 저장소의 branch를 checkout 하면 detached HEAD 상태로 소스를 보고 변경 해볼 수도 있지만 변경 사항들은 commit, push 할 수 없으며 다른 branch로 checkout하면 사라진다.

개발한 내역을 master branch에 merge하는 과정

변경 내역을 master에 merge하는 과정은 아주 중요한 과정이다. 먼저 아래와 같이 remote 서버의 최신 내역을 자신의 로컬 저장소에 갱신하는 습관을 들이는게 좋다. git pull을 통해 remote 서버의 변경 내용이 로컬 저장소에 fetch, merge 된다.
$ git pull
Plain Text
복사
다른 branch에 있는 변경 내용을 현재의 branch(master)에 병합하려면 아래의 명령을 실행하자.
$ git checkout master $ git merge some_function
Plain Text
복사
첫번째 명령이든 두번째 명령이든, git은 자동으로 변경 내용을 merge하려고 한다. 문제는, 항상 성공하는 게 아니라 가끔 충돌(conflicts)이 일어나기도 한다는 점이다. 필요하다면 개발이 완료되어 merge된 branch는 아래와 같이 삭제한다.
$ git branch -D some_function
Plain Text
복사

merge conflict가 발생한다면?

개발이 완료되면 branch를 merge하는 과정에서 충분히 conflic가 발생할 수 있다.
CONFLICT (content): Merge conflict in foo.java Automatic merge failed; fix conflicts and then commit the result.
Plain Text
복사
int a = 1; <<<<<<< HEAD // conflict 가 발생한 범위의 시작 int b = 2; ======= int b = 0; >>>>>>> 55737474728739293729138123737392371293123737e // 모든 commit은 유일한 커밋 ID를 가진다
Plain Text
복사
conflict 부분을 직접 수정해서 다시 commit하는 전략을 취한다.
int a = 1; int b = 2;
Plain Text
복사
$ git commit -a -m 'Conclude merge'
Plain Text
복사
merge 전에 변경 내용을 확인하는 방법
$ git status -sb
Plain Text
복사
$ git diff some_function master
Plain Text
복사
Merge 중에 발생한 충돌을 해결하는 방법은 몇 가지가 있다. 첫 번째는 그저 이 상황을 벗어나는 것이다. 예상하고 있던 일도 아니고 지금 당장 처리할 일도 아니라면 git merge –abort 명령으로 간단히 Merge 하기 전으로 되돌린다.
$ git merge --abort
Plain Text
복사

로컬 변경 내용을 되돌리기

로컬에서 발생한 변경내역을 되돌리는 일은 빈번히 발생할 수 있다. git status 명령을 통해 현재 branch의 상태와 이후의 상태 변경을 위한 Commands를 확인할 수 도 있다.
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: Git/git-commands.md
Plain Text
복사
위의 상태는 소스 코드를 변경하고 git add를 통해 인덱스에 변경 내역을 알리기전의 상태이다. 아래와 같이 변경 내역을 되돌릴 수 있다.
$ git checkout -- <file>
Plain Text
복사
git add 이후에 변경 내역을 되돌리고자 한다면,
$ git reset HEAD <file>
Plain Text
복사
이미 commit된 내역을 과거로 되돌리고 싶은 경우가 있을 것이다! 먼저 commit history를 살펴보자
$ git log --oneline 8ed5068 (HEAD -> unit-test, origin/unit-test) Update README.md dfff29e (origin/master, master) Merge pull request #8 from stunstunstun/unit-test eec3b7a Integration runner is completed 0a087cf #2 Specification list, create, get, update a603da7 Inialize unit test environments 55c3e73 (origin/stage, stage) Update README.md c354d50 Merge pull request #7 from stunstunstun/api-test 2e6b522 (origin/api-test) #3 Add eslint to devDendencies 5e35c21 #3 Add eslint to devDendencies f9bbe2a #3 version fixed
Plain Text
복사
a603da7 이후의 모든 내역을 삭제하고 돌아가고 싶다면 --hard 옵션과 함께 reset 명령을 이용하자
$ git reset --hard a603da7
Plain Text
복사
특정 commit의 변경 내역을 취소하는 새로운 commit을 발행해야하는 경우도 있다. 이미 commit, push 한 경우 드물게 사용하는 것을 권장한다.
$ git revert <commit_id>
Plain Text
복사

최종 버전 릴리즈하기

애플리케이션의 빌드 및 테스트가 완료되어 새 버전을 릴리즈한다면 읽기 전용 상태의 tag 버전를 생성하는 것이 좋다.
$ git tag 1.0.0
Plain Text
복사
$ git log
Plain Text
복사
생성한 tag 버전은 아래와 같이 remote 서버에 최종적으로 반영한다.
$ git push origin 0.1.0
Plain Text
복사

gh-pages 브랜치를 통해 정적 페이지 관리하기

GitHub Repository를 운영하다 보면 비어 있는 브랜치를 생성해야할 때가 있다. REST API를 제공하는 프로젝트에서 자동으로 생성되는 API Documentation를 정적 페이지를 통해 제공하는 경우가 좋은 예이다.
$ cd /path/to/repo-name $ git symbolic-ref HEAD refs/heads/gh-pages $ rm .git/index $ git clean -fdx $ echo "My GitHub Page" > index.html $ git add . $ git commit -a -m "First pages commit" $ git push origin gh-pages
Plain Text
복사
git checkout -b gh-pages를 통해 브랜치를 생성할 수도 있겠지만 이는 master 브랜치의 과거내역을 가지고 있음을 의미한다. 위와 같은 방법을 참고하면 root branch로 부터 과거 내역이 깔끔히 빈 새로운 브랜치를 생성할 수 있다.
gh-pages 브랜치가 생성되면 아래의 경로를 통해서 정적 페이지에 접속할 수 있다.
http://<username>.github.io/<projectname>
Plain Text
복사
https://gist.github.com/ramnathv/2227408

remote branch 참조와 업데이트

remote 서버를 변경해야 할 때

git 저장소의 주소가 변경되는 등의 이슈로 인해 remote 서버를 변경해야 한다면 아래의 명령을 참고한다.
$ git remote -v origin https://wjdsupj@github.com/wjdsupj/awesome-wiki (fetch) origin https://wjdsupj@github.com/wjdsupj/awesome-wiki (push) $ git remote set-url origin https://stunstunstun@github.com/stunstunstun/awesome-wiki $ git remote -v origin https://stunstunstun@github.com/stunstunstun/awesome-wiki (fetch) origin https://stunstunstun@github.com/stunstunstun/awesome-wiki (push)
Plain Text
복사

remote branch 상태 보기

$ git remote show origin
Plain Text
복사

git fetch

로컬 저장소를 리모트 저장소와 동기화하고, 자동적으로 더이상 유효하지 않은 branch 참조를 제거한다.
$ git fetch origin --prune
Plain Text
복사

git remote

$ git remote update --prune # Only prune, don't fetch
Plain Text
복사

GitHub의 오픈소스에 기여하기

GitHub에는 다양한 오픈소스들이 존재하고 경우에 따라서는 직접 참여해 관심있는 오픈소스에 기여할 수도 있다. 이를 위해서는 먼저 오픈소스의 Repository를 아래의 Fork 버튼을 통해 자신의 계정에 추가해야 한다.

Fork한 Repository clone 하기

$ git clone https://github.com/YOUR-USERNAME/jest
Plain Text
복사

Fork를 위한 remote 설정하기

Fork한 Repository를 앞으로 자신의 Repository와 동기화하기 위해서는 아래와 같이 upstreamremote를 추가한다.
$ git remote -v origin https://github.com/stunstunstun/jest (fetch) origin https://github.com/stunstunstun/jest (push) $ git remote add upstream https://github.com/facebook/jest $ git remote -v origin https://github.com/stunstunstun/jest (fetch) origin https://github.com/stunstunstun/jest (push) upstream https://github.com/facebook/jest (fetch) upstream https://github.com/facebook/jest (push)
Plain Text
복사

Fork와 동기화하기

아래와 같은 명령순으로 원본 Repository에서 merge할 수 있다.
$ git fetch upstream remote: Counting objects: 63, done. remote: Compressing objects: 100% (12/12), done. remote: Total 63 (delta 46), reused 51 (delta 45), pack-reused 6 Unpacking objects: 100% (63/63), done. From https://github.com/facebook/jest * [new branch] ericnakagawa-add-romanian -> upstream/ericnakagawa-add-romanian * [new branch] gh-pages -> upstream/gh-pages * [new branch] master -> upstream/master $ git checkout master Your branch is up-to-date with 'origin/master'. $ git merge upstream/master Updating 5a378915..4f685d88 Fast-forward CHANGELOG.md | 34 ++- docs/GlobalAPI.md | 14 +- examples/react-native/package.json | 2 +- integration_tests/__tests__/__snapshots__/globals.test.js.snap | 17 ++ integration_tests/__tests__/globals.test.js | 18 ++ integration_tests/__tests__/jasmine_async.test.js | 6 + integration_tests/jasmine_async/__tests__/generator.test.js | 25 ++ package.json | 10 +- packages/jest-jasmine2/package.json | 2 + packages/jest-jasmine2/src/jasmine/Suite.js | 29 +- packages/jest-jasmine2/src/jasmine_async.js | 9 +- scripts/browserBuild.js | 4 +- types/Circus.js | 2 +- yarn.lock | 1126 ++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- 14 files changed, 954 insertions(+), 344 deletions(-) create mode 100644 integration_tests/jasmine_async/__tests__/generator.test.js
Plain Text
복사

git config

이 명령을 통해서는 로컬에서 참고하는 다양한 옵션을 설정한다. 예를 들면 Git Repository에서 참조하는 계정을 아래와 같이 설정할 수 있다.
global
$ git config --global user.name "stunstunstun" $ git config --global user.email "wjdsupj@gmail.com"
Plain Text
복사
local
$ git config --local user.name "stunstunstun" $ git config --local user.email "wjdsupj@gmail.com"
Plain Text
복사
https://git-scm.com/docs/git-config

마치며

지금까지 Git Flow를 통해 기본적인 명령들을 살펴보았다. Git에 대해 더 알고 싶다면 아래의 자료를 참고하면 많은 도움이 될 것이다!

References