GIT

반응형

GIT 커밋 메시지 컨벤션 (이대로 할 필요는 없다. 대충 이런 방식이 있다는 정도 알아두면 된다.)

 

AngularJS commit conventions1

AngularJS commit conventions2

 

type(scope): short summary
BLANK LINE
body
BLANK LINE
footer (Breaking Changes, Referencing Issues 있다)

 

<type>

feat : 새로운 기능 추가  

fix : 버그 수정  

docs : 문서 관련  

style : 스타일 변경 (포매팅 수정, 들여쓰기 추가, …)  

refactor : 코드 리팩토링  

test : 테스트 관련 코드  

build : 빌드 관련 파일 수정  

ci : CI 설정 파일 수정  

perf : 성능 개선  

chore : 자잘한 수정  

 

 

괜찮은 git 설명서

https://backlog.com/git-tutorial/kr/intro/intro1_1.html

 

누구나 쉽게 이해할 수 있는 Git 입문~버전 관리를 완벽하게 이용해보자~ | Backlog

누구나 쉽게 알 수 있는 Git에 입문하신 것을 환영합니다. Git을 사용해 버전 관리를 할 수 있도록 함께 공부해봅시다!

backlog.com

 

 

 

github private 저장소 클론을 위한 ssh key 설정 방법. (https://ssabi.tistory.com/48)

 

git client fork 툴. GUI 툴.

 

 

 

git rebase 하는 방법

https://flyingsquirrel.medium.com/git-rebase-%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95-ce6816fa859d

 

git checkout master

git rebase development

만약 master 와 development 가 동일한 부분을 다르게 수정하여 충돌나면

git rebase --abort 로 방금 rebase 를 취소할 수 있고

모든 충돌을 수정후 git add/rm <conflicted_files> 하고 git rebase --continue 해준다.

git rebase --skip 로 병합 대상 브랜치의 내용으로 강제 병합할 수도 있으나 다른 곁가지가 있을 경우 이러면 다시 rebase 불가능해질 수도 있다.

--no-ff 옵션도 있다. fast-forward 를 하지 않는다는 것. 즉, 몇개의 분기된 히스토리 전부 커밋 기록에 남기면서 병합 수행. --ff 가 기본이다.

rebase 하면 merge 와 다르게 한 줄로 쭉 병합되며 기존-development-master 이런식으로 중간에 development 도 분기 형식은 아니면서 일렬로 병합 기록에 남게된다.

 

 

master (or develop 개발 기준 리모트 브랜치) - feature

master 를 clone or pull 한다.

항상 푸시 전에는 리모트의 master 를 최신으로 pull 한다.

작업한 feature 해당 로컬의 master 에 merge 또는 rebase 한다.

rebase 를 추천한다. rebase 하기 전에 자신의 wip (work in progress 같은 커밋) 은 제거해줄 수 있다.

git rebase -i @~3 (-i 는 --interactive 옵션이고, @~3은 최근 3개의 commit 을 rebase 하겠다는 뜻이다. HEAD~3 과 같은 뜻이다.)

merge 든 rebase 이든 동일한 코드 부분을 이미 다른 개발자가 수정하였다면 conflict 가 난다. 충돌 해결해주면 된다.

rebase 라고 덮어쓰는 것이 아니다.

merge 는 중간 중간 상대방의 코드와 나의 코드가 병렬로 순서대로 나오는 git 트리 모습을 보인다. 따라서 어떤 feature 에 대한 개발을 했을 경우 코드의 변경 사항이 지저분하게 보일 수 있다.

rebase 를 하면 다른 개발자의 코드의 커밋들은 먼저 쭉 나열되고 그 뒤에 순차적으로 나의 커밋이 나열된다. 따라서 읽기가 좋다.

물론 rebase 를 할 경우는 로컬로 master 를 당겨와서 나의 feature 를 먼저 rebase 해주고 푸시해주는 식으로 해야한다.

rebase 로 리모트에 직접적으로 잘못 푸시할 경우 다른 개발자들의 모든 코드가 꼬일 수 있다.

따라서 jira 에서 풀리퀘스트 방식으로 병합할 경우 대부분 머지를 한다고 보면된다.

그래서 jira 의 풀리퀘스트 방식은 jira 의 이슈(feature) 단위로 끊어서 작업해주는 것이 좋다.

confluence 에서 요구사항을 추출하고 jira 의 이슈를 만들고 다음과 같은 상태 순서에 따라 작업하고 작업을 할 때는 해당 이슈에서 브랜치를 만들어 태깅을 남기면서 작업을 하고 병합한다.

 

Backlog

To Do

In Progress

In Review

Complete

Archived

Icebox

 

git branch day1

 

git checkout day1 (체크아웃, 즉 해당 브랜치로 이동)

 

git checkout -b day1 (브랜치를 만들면서 체크아웃 한다.)

 

git remote add origin https://user@bitbucket.org/user/spring_ex.git (origin 으로 remote 추가)

 

git remote get-url origin (origin 의 remote url 을 확인한다.)

 

git checkout master (master 브랜치로 복귀)

 

git merge day1 (master 브랜치에 day1 변경 사항 반영)

 

git push -u origin master (master 의 변경 사항 remote 중 origin 에 반영, 기존에 master 는 이미 추가되어 있다면 -u 옵션은 필요없다.)

 

git push -u origin day1 (remote 중 origin 에 day1 브랜치를 추가하면서 내용 반영. 즉, master 도 있게 되고 day1 도 있게 된다. day1 은 새로 추가되는 것이므로 -u 옵션 필요)

 

물론 git add . / git commit -m "xxx" 이런 부분 들은 생략하였다. push 전에 커밋은 해야 한다. merge 전에 커밋은 해야 한다.

 

 

 

 

git branch (현재 내가 어떤 브랜치에 있는지 확인한다. 브랜치 리스트도 보여준다.)

git branch development (development 라는 브랜치를 만든다.)

git branch -d development (development 라는 브랜치를 삭제한다.)

 

 

 

git pull origin master (remote origin 것을 local master 로 가져옴. 다른이가 remote 에 작업해서 커밋하고 푸시 한 경우.)

git pull 은 git fetch 와 git merge 를 합친 기능이다.

git fetch 만 할 경우 origin/master 은 회색으로 맨 앞에 보일 것이고 master 부분이 뒤에 선명히 보이며 HEAD 를 가리키고 있을 것이다.

git merge 해주면 이게 다시 합쳐져서 origin/master 와 master 가 하나로 되어 origin/master 라는 글자가 선명히 보이며 HEAD 를 가리킬 것이다.

 

 

 

git branch

git pull origin master

이 두 명령어는 아침에 코딩 시작할 때 반드시 확인.

 

 

 

git checkout master

git merge development

만약 master 와 development 가 동일한 부분을 다르게 수정하여 충돌나면

git merge --abort 로 방금 merge 를 취소할 수 있고

수정하고 git commit 통해서 커밋하면 해당 상태로 merge 되면서 커밋된다.

merge 도 --ff 가 기본이다.

 

 

 

git checkout master

git cherry-pick development 의 7자리커밋코드

master 에 다가 development 브랜치의 "병합하고 싶은 커밋"만 쏙 골라서 병합해준다. 이또한 충돌시 해당 파일 수정해주고 커밋해주면된다.

 

 

 

한마디로 --cached 안 붙이면 파일을 git 스테이징 뿐 아니라 로컬에서도 실제 삭제한다.

파일을 삭제하고 git add . 하고 git commit 해주면 파일을 삭제한 것으로 반영은 한다.

그 과정을 한번에 반영해주는 것이 git rm 이고 --cached 를 넣어주면 로컬에는 파일을 남겨둔다.

git rm file.txt             : 로컬과 git 에서 모두 파일 삭제.

git rm --cached file.txt    : git 에서만 파일 삭제. 로컬에는 남아 있다. 차후 계속 제외시키고 싶다면 .gitignore 에 추가하라.

git rm -f file.txt          : file.txt 생성 후 git add file.txt 하고 git rm file.txt 하면 변경사항으로 삭제 못한다고 나오는데 그때 -f 옵션으로 강제 삭제.

git rm -rf directory        : 디렉토리의 경우 -r 즉 recursive 옵션 넣어주어야 한다.

 

 

 

git config --global user.email "내 이메일"

git config --global user.name "내 이름"

 

git config --global core.quotepath false (git status 한글 깨짐 방지)

git config --global gui.encoding utf-8

git config --global i18n.logoutputencoding utf-8

 

git config --global --edit

 

https://reiphiel.tistory.com/entry/git-handle-newline

git config --global core.autocrlf [true | input | false] // 설정하기 (맥에서는 input, 윈도우전용이면 false 해도 된다. 그냥 input 으로 설정하라.)

git config --global --unset core.autocrlf //설정 해제하기

 

 

github.com 에서 리포지터리에 처음 푸시할 때 명령어이다. private 리포는 앞에 계정을 붙여주어야 한다.

git remote add origin https://github.com/dmk3141618/myrepo.git

git remote add origin https://dmk3141618@github.com/dmk3141618/myrepo.git (private 일 경우)

git branch -M main (이건 처음 커밋 후 해야함. 처음 커밋 한번해야 master 가 실제로 생긴다. 그리고 main 으로 이름 변경하는 것임.)

git push -u origin main

 

* github 에 private repo 생성 후 최초 push 하려면

git remote add origin https://{github_id}@github.com/{github_id}/{repo_name}.git (맨 앞 {github_id}@ 추가해야함.)

git branch -M main (master > main 으로 자신 로컬의 저장소 이름을 바꿔주는 것)

git push -u origin main

만약 git remote add origin https://github.com/{github_id}/{repo_name}.git 이렇게만 입력해서 삭제해야할 경우

git remote remove origin 명령어로 origin remote 를 삭제해줄 수 있다.

 

 

 

git log

git shortlog

git log --graph

 

 

 

git checkout -- code1.txt   : code1.txt 파일 원래 상태로 복구.

 

 

 

git commit -am "Commit Message 잘 적어라. 최대한 자세히 적는게 좋다."

: git add . 과 함께 commit 하는 명령어. 아니다... git add . 은 안된다.

untracked files 는 add 하지 않는다.

따라서 git add . 과 git commit 을 사용하는 것이 좋다.

 

 

 

git diff

 

 

 

기존커밋 -> 빨강이(modified) -> 초록이(staged) -> 새커밋

git reset HEAD~1 (현재 커밋 기준인 HEAD 에서 한번 전의 커밋으로 돌아가는 것. 수정된 사항은 남아있다. 단지 커밋만 풀어주는 것. untracked 였던 것은 다시 untracked 되어 버림.)

git reset HEAD~1 --soft (staged 로 돌림. 단, 생성한 파일은 untracked 상태가 됨.)

git reset HEAD~1 --mixed (modified 로 돌림)림 : 이게 기본임.

git reset HEAD~1 --hard (완전 기존커밋으로 돌)

그냥 git reset --hard 를 하게 되면 현재까지 모든 수정 사항이 HEAD 로 돌아간다.

git reset 7자리커밋코드 해도 된다.

remote origin 에 git push 해놓고 그보다 전으로 reset 하면 기존것 다 사라지고 해당 커밋으로 reset 되지만 push 된 것은 회색으로 가리키고는 있다.

 

 

 

 

git revert (되돌린 것 조차 기록에 남기는 것. 다른이들이 이미 실수커밋을 pull 받은 상태라면 revert 를 사용해야 다른이들도 함께 반영시킬 수 있다.)

git revert HEAD

git revert 7자리커밋코드

커밋 히스토리는 실수커밋 -> HEAD -> revert '실수커밋' 과 같이 된다. revert '실수커밋' 부분 커밋 메시지는 revert 시에 입력 가능하다.

해당하는 커밋까지 모두 되돌리면서 새로운 커밋을 한다. HEAD 이면 현재 가리키고 있는 거를 되돌리고, 7자리커밋코드 이면 해당 커밋까지 모두 되돌린다.

 

 

 

 

 

해당 커밋에서 git tag v1.0.0 과 같이 중요한 커밋에 태그를 붙여두면 좋다.

git reset v1.0.0 이나 git revert v1.0.0 과 같이 해당 태그를 7자리커밋코드 대신 사용할 수도 있다.

git tag 를 로컬에서 붙여서 github 에 push 해도 해당 tag 가 적용되어 있지 않다.

tag 도 올리는 방법이 있다는데 찾아봐야할 듯.

 

 

 

git stash 는

development 브랜치에서 작업하다가 git checkout master 로 브랜치 이동시 작업하던 내용을 커밋을 하고 이동해야 작업한 내용이 사라지지 않는다.

즉, 커밋 안된 작업 내용은 checkout 으로 브랜치 이동시 이동했다가 다시 되돌아오면 다 사라진다.

그래서 그걸 임시 저장해놓기 위해 git stash 라고 해주면 해당 내용이 임시 저장되어 있게 된다.

git stash list 를 해보면 stash 된 것들 리스트를 볼 수 있다.

이것은 전역적이라서 다른 브랜치 즉, development 에서 작업하다가 master 로 이동해서 git stash list 해도 확인되고

이것을 다시 불러오기 위해서는 git stash apply 라고 해주면 된다. git stash pop 을 하면 적용하고 해당 stash 를 삭제한다.

development 에서 작업하다 git stash 하고 master 갔다가 다시 development 로 돌아와서 git stash apply 해서 작업하는 것이 원래 stash 의 용도이나

development 에서 작업하다 git stash 하고 master 가서 git stash apply 해도 master 에 해당 내용이 적용이 된다.

따라서 실수로 master 인 줄 알고 development 에서 작업하던 중 master 로 옮겨 가고 싶을 때도 git stash 를 이용해도 될 것이다.

그러나 git status 나 git log 할 때 stash 도 남아 있는 상태.

git stash drop 하면 stash 가 삭제된다.

 

 

 

 

 

 

github flow workflow

hotfix - master - dev - function1 function2 ...

hotfix - master - dev - user1 user2 ...

function1 function2 ...

user1 user2 ...

이런식으로 된 애들이 지지고 볶고 해서 dev 로 커밋 하고 dev 에서 충분히 합치고 테스트한 후 master 로 옮긴다.

hotfix 는 master 로 부터 급하게 수정해야 할 사항이 있을 경우 한 번 따서 쓰고 버린다.

물론 dev 나 hotfix 로 부터 master 로 통합되면 해당 통합된 사항을 각 브랜치들에 전부 다시 뿌려야 한다.

 

 

 

gitflow workflow

https://thewavelet.tistory.com/42

 

 

 

 

 

 

이미 tracked 된 파일은 ignore 되지 않는다. ignore 를 위해서는 먼저 index 에서 제거해야 한다.

 

git rm --cached private.xml

git add -u .

git commit -m "Record deletion of private.xml from the index"

 

(--cached 옵션이 파일은 그대로 남겨두고 index 에서만 제거해준다.)

그리고나서 .gitignore 에 아래를 추가.

private.xml

 

어떤 .gitignore 룰 이 적용되어 있는지 아래 명령어로 확인할 수 있다.

git check-ignore -v -- private.xml

 

 

 

 

 

 

 

 

git 설정

https://git-scm.com/book/ko/v1/Git%EB%A7%9E%EC%B6%A4-Git-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0

 

 

http://blog.appkr.kr/learn-n-think/comparing-workflows/

http://blog.appkr.kr/work-n-play/git-flow/

 

 

1. Centralized WorkflowPermalink

2. Feature Branch Workflow

3. Gitflow Workflow (위의 두번째 url 에 git-flow 툴 사용을 하여 적용하자.) << 결국 이 방법 선택하자.

 

4. Forking Workflow << 이런 것도 있지만 이건 사용할 일 없음.

Forking Worflow는 다른 워크플로우와 근본적으로 다르다. 하나의 중앙 저장소를 이용하는 것이 아니라, 개개인마다 서로 다른 원격 저장소를 운영하는 방식이다. 모든 프로젝트 참여자가 개인적인 로컬 저장소와 공개된 원격 저장소, 즉 두 개씩의 Git 저장소를 가지는 방식이다.

 

 

 

중앙 저장소 생성

ssh user@host git init --bare /path/to/repo.git

중앙 저장소 복제

git clone ssh://user@host/path/to/repo.git

저장소를 복제하면 Git은 로컬 저장소와 연결된 중앙 저장소(원격 저장소)를 기억하기 위해 origin이라는 별칭이 자동으로 만들어진다. 앞으로 이 별칭을 이용해서 중앙 저장소와 여러 가지 상호작용을 하게 된다.

 

$ git status            # 로컬 저장소의 상태 확인

$ git add <some-file>   # 스테이징 영역에 some-file 추가

$ git commit            # some-file의 변경 내역을 커밋

 

$ git push origin master

origin은 철이가 중앙 저장소를 복제할 때 자동 생성된 별칭이고, 로컬 저장소와 중앙 저장소를 연결한다고 말한 바 있다. 명령에 사용한 master라는 인자(argument)는 로컬 master 브랜치를 origin의 master 브랜치에 동기화하겠다는 뜻이다.

 

$ git pull --rebase origin master

 git pull 명령으로 중앙 저장소의 변경 이력을 로컬 저장소로 내려 받는다. 이 명령은 중앙 저장소의 최신 이력을 내려 받는 동작과 이를 로컬 이력과 합치는 동작을 한 번에 한다.

--rebase 옵션을 주면 중앙 저장소의 커밋 이력을 미애의 커밋 이력 앞에 끼워 넣는다.

--rebase 옵션 없이 쓸 수도 있지만, 불필요한 병합 커밋을 한 번 더해야 하는 번거로움이 있으므로 --rebase 옵션을 쓰는 것이 좋다.

리베이스는 미애의 로컬 커밋을 새로 내려 받은 master 브랜치에 하나 하나 대입하고 대조해 가면서 커밋 이력을 재배열한다. 이런 동작 특성때문에 커밋 이력도 깔끔하게 유지할 수 있을 뿐만아니라, 경우에 따라 버그를 발견하기도 한다.

철이와 미애가 서로 다른 기능을 개발했다면, 리베이스 과정에 충돌이 발생할 가능성은 거의 없다. 어쨌든 리베이스 과정에 충돌이 발생하면, Git은 현재 커밋에서 리베이스를 멈추고 다음과 같은 메시지를 뿜어 낸다.

# CONFLICT (content): Merge conflict in <some-file>

이 사례에서 미애는 git status 명령으로, Unmerged paths: 부분에서 충돌이 발생한 파일을 찾을 수 있다.

이제 some-file을 열어 충돌을 해결하고, 스테이징 영역에 변경된 파일을 추가한 후, 리베이스를 계속 하면 된다.

$ git add <some-file>

$ git rebase --continue

리베이스는 다음 커밋으로 넘어가고, 더 이상 충돌이 없다면 리베이스는 성공적으로 끝난다.

리베이스 중에 뭔가 잘못되었다면, 다음 명령으로 git pull --rebase 명령을 내리기 이전 상태로 되돌릴 수 있다.

$ git rebase --abort

중앙 저장소의 커밋 이력과 로컬 커밋 이력을 모두 합쳤으므로, 이제 중앙 저장소에 올리기만 하면 된다.

$ git push origin master

 

 

 

2. Feature Branch Workflow

 

이 워크플로우도 프로젝트의 공식적인 변경 이력을 기록하기 위해서 중앙 저장소와 master 브랜치를 사용한다. 그런데, master 브랜치에 직접 커밋하지는 않고, 새로운 기능을 개발할 때마다 브랜치를 만들어서 작업한다. 보통 animated-menu-items 또는 issue-#1061처럼 의미를 담고 있는 브랜치 이름을 사용한다.

브랜치를 이용하면 격리된 영역에서 안전하게 새 기능을 개발할 수 있을 뿐만아니라, 풀 리퀘스트를 이용해서 브랜치에 대한 팀 구성원들의 토론 참여를 이끌어 낼 수도 있다. 기능 개발을 끝내고 master에 바로 병합하는 것이 아니라, 브랜치를 중앙 저장소에 올리고 master에 병합해달라고 요청하는 것이 풀 리퀘스트다.

풀 리퀘스트는 특정 브랜치에 대한 코드 리뷰의 시작점이라 볼 수 있다. 따라서 기능 개발 초기 단계에 미리 풀 리퀘스트를 보낸다고 문제될 것은 없다. 예를 들어, 기능 개발 중에 막히는 부분은 미리 풀 리퀘스트를 던져서 다른 팀 구성원들의 도움을 받을 수도 있을 것이다. 풀 리퀘스트에 포함된 각 커밋에 팀 구성원들이 의견을 제시할 수 있고, 새로운 의견이 등록되면 토론 참여자들에게 알림을 보낼 수도 있다.

팀 구성원이 풀 리퀘스트를 수용(또는 합의)하면, 그 이후의 작업 절차는 Centralized Workflow와 거의 같다. 먼저 로컬 master가 최신 상태인지 확인한 후, 기능 개발 브랜치를 master 브랜치에 병합하고, 중앙 저장소의 master 브랜치로 푸시하면 된다.

풀 리퀘스트는 Bitbucket Cloud이나 Bitbucket Server을 이용하면 편리하다.

https://bitbucket.org/product

https://www.atlassian.com/software/bitbucket/server

역주) Atlassian이 작성한 글이라 빗버킷을 제안하는데, 깃허브도 똑같은 기능을 제공한다.

 

새로운 기능을 개발하기에 앞서 격리된 작업 브랜치를 만들어야 한다.

$ git checkout -b miae-feature master

miae-feature브랜치로 체크아웃하는 명령이다. -b 옵션을 주면 체크아웃하려는 브랜치가 없으면 master 브랜치를 기준으로 해서 만들 수 있다.

이 브랜치에서 미애는 평상시 하던대로 새로운 기능을 개발하고 변경 내용을 커밋하면 된다.

$ git status

$ git add <some-file>

$ git commit

미애는 오전 동안 새로 만든 브랜치에 꽤 여러 번의 커밋을 남겼다. 점심을 먹으러 나가기 전에 그간의 작업 내용을 중앙 저장소에 푸시해 놓기로 했다. 이는 로컬 저장소의 백업 역할을 할 뿐만 아니라, 다른 팀 구성원들이 미애의 작업 내용과 진도를 확인할 수도 있어 좋은 습관이라 할 수 있다.

$ git push -u origin miae-feature

miae-feature 브랜치를 중앙 저장소(origin)에 푸시하는 명령이다. -u | --set-upstream 옵션이 중요하다. 이는 로컬 기능 개발 브랜치와 중앙 저장소의 같은 이름의 브랜치를 연결하는 역할을 한다. 한번 연결한 후에는 git push 명령만으로 푸시할 수 있다.

오후에 맡은 기능 개발을 모두 완료했다. (역주: 이 팀은 개발자가 직접 master에 병합하지 않고, 풀 리퀘스트를 이용하는 규칙을 가지고 있다.) master 브랜치에 병합하기 전에 풀 리퀘스트를 던져서 팀 구성원들에게 작업 완료 사실을 알려야 한다. 물론 그 전에 중앙 저장소에 작업 내용을 올려야 한다.

$ git push

미애는 GUI 도구를 이용해서 miae-feature 브랜치를 master 브랜치에 병합해 달라고 요청하는 풀 리퀘스트를 던지면, 팀 구성원들은 알림을 받게된다. 이제 팀 구성원 누구나 풀 리퀘스트의 각 커밋에 질문을 남기거나 의견을 달 수 있다.

풀 리퀘스트를 확인한 혁 팀장이 miae-feature 브랜치를 검토하다가, 공식 저장소에 병합하기 전에 몇 가지 수정이 필요하다고 판단하고, 미애에게 수정 의견을 제시했다.

혁 팀장이 마침내 미애의 풀 리퀘스트를 수용하기로 결정했다. 누군가 병합 작업을 해야 한다(병합은 혁 팀장이든 미애든 누구나 할 수 있다).

$ git checkout master

$ git pull

$ git pull origin miae-feature

$ git push

먼저 master 브랜치로 체크아웃하고 최신 상태인지를 확인해야 한다. 그 다음 miae-feature 브랜치를 로컬로 가져와야 하는데 로컬에 이미 해당 브랜치가 있다면 최신 상태로 병합한다. 그냥 git merge miae-feature 명령을 이용할 수 있지만, 항상 중앙 저장소의 최신 변경 내용을 로컬에 반영하기 위해서 git pull origin miae-feature 명령을 이용하는 것이 좋다. 마지막으로 병합된 master 브랜치를 중앙 저장소로 다시 올린다.

이 과정을 거치면 병합 커밋이 생기는데, 어떤 팀은 코드 베이스에 기능 추가된 이력을 시각적으로 인지할 수 있어서 좋아하는 병합 커밋을 남기는 것을 좋아한다. 만약 기능 추가 이력을 일직선으로 유지하는 것을 선호한다면, 병합 전에 리베이스를 할 수도 있다(fast-forward 병합이 적용됨).

GUI 도구를 이용하면 이 복잡한 풀 리퀘스트 처리 과정을 ‘수락’ 버튼 하나로 할 수도 있다.

이 워크플로우의 유연성은 큰 장점이지만, 현장에서 적용할 때 유연성은 독이 될 수도 있다. 특히 팀이 크고, 프로젝트 규모가 크면 브랜치마다 좀 더 특별한 의미를 부여하는 것이 더 낫다. 다음에 살펴볼 Gitflow Workflow는 기능 개발과, 릴리스, 유지보수를 위해 좀 더 엄격한 워크플로우를 제시한다.

 

 

 

3. Gitflow Workflow

 

master, develop (feature), release, hotfix

master 가 주가 되며 CI 에 반영됨.

모든 기능 개발은 develop 브랜치 중심으로 수행됨.

어느정도 기능개발이 되면 release 를 위한 release/xxx 또는 release-xxx 와 같은 브랜치를 만듬.

여기서 release 를 위한 사이클이 시작되며

버그수정, 문서추가 등의 릴리즈를 위한 작업 외에는 추가 안함.

이와 동시에 develop 은 또 계속 진행.

release 가 브랜치가 완료되면 release v0.2 라하면 이것을 master 에 반영.

여기서 혹여나 버그가 생기면 hotfix 로 브랜치를 따서 버그 수정.

즉, hotfix 는 master 로 부터 따서 버그 수정하는 것임. 수정 후에는 master, release, develop 모두에 반영.

 

먼저 할 일은 master 브랜치를 기준으로 develop 브랜치를 만드는 것이다. 팀 구성원 중 한 명이 자신의 로컬 저장소에 빈 develop 브랜치를 만들고 중앙 저장소로 푸시하면 된다.

$ git branch develop

$ git push -u origin develop

 

master 브랜치는 축약된 프로젝트 이력만 담고 있는 반면, 이 개발 브랜치는 모든 개발 이력을 다 담을 것이다. 이제 팀 구성원들은 중앙 저장소를 복제하고, 중앙 저장소와 연결된 개발 브랜치를 만들어야 한다.

$ git clone ssh://user@host/path/to/repo.git

$ git checkout -b develop origin/develop

 

이 사례에서는 철이와 미애가 각자 맡은 기능을 개발할 기능 개발 브랜치를 만들고 서로 다른 기능을 개발한다고 가정한다. 다시 한 번 언급하지만, master를 베이스로 하지 않고, develop 브랜치를 기준으로 기능 개발 브랜치를 따야 한다.

$ git checkout -b some-feature develop

항상 하던대로 개발하고 변경 내용을 커밋한다.

$ git status

$ git add <some-file>

$ git commit

 

몇 번의 커밋 끝에, 미애는 맡은 기능 개발을 완료했다. 만약에 팀이 풀 리퀘스트를 하기로 약속했다면, 미애는 자신의 기능 브랜치를 develop 브랜치에 병합해 달라고 풀 리퀘스트를 보낼 수 있다. 풀 리퀘스트를 이용하지 않기로 했다면 다음과 같이 직접 develop 브랜치에 병합하고 중앙 저장소에 푸시하면 된다.

$ git pull origin develop

$ git checkout develop

$ git merge some-feature

$ git push

$ git branch -d some-feature

 

기능 브랜치를 병합하기 전에 반드시 로컬 develop 브랜치에 중앙 저장소의 변경 내용을 반영해서 최신 상태로 만들어야 한다. master에 직접 병합하지 않도록 주의해야 한다. 병합할 때 충돌이 발생하면 Centralized Workflow에서 본 바와 같이 해결한다.

 

철이가 여전히 기능 개발에 몰두하고 있는 와중에, 미애는 첫 공식 릴리스를 준비하고 있다. 기능 개발과 마찬가지로 릴리스 과정을 캡슐화할 새로운 브랜치를 만들어야 한다. 이 과정에서 버전 번호를 부여한다.

$ git checkout -b release-0.1 develop

이 브랜치는 최종 테스트를 하거나, 문서를 수정하는 등 릴리스와 관련된 여러 가지 작업들을 처리하기 위한 격리 공간이다. 미애가 이 브랜치를 만든 이후에 develop 브랜치에 병합된 기능은 릴리스 대상에서 제외된다. 이번에 포함되지 않은 기능들은 다음 릴리스에 포함된다.

 

릴리스 준비가 끝나면, 릴리스 브랜치를 master와 develop 브랜치에 병합하고, 릴리스 브랜치는 삭제한다.

develop 브랜치에도 병합하는 이유는 릴리스를 준비하면서 개발 중인 다른 기능에 영향을 줄 수 있는 작업을 했을 수도 있기 때문이다. 미애의 팀이 코드 리뷰를 하는 규칙을 가지고 있다면, 병합을 요청하는 풀 리퀘스트를 보낼 수도 있다.

$ git checkout master

$ git merge release-0.1

$ git push

$ git checkout develop

$ git merge release-0.1

$ git push

$ git branch -d release-0.1

 

릴리스 브랜치는 기능 개발(develop)과 프로젝트의 공식 릴리스 사이의 가교 역할을 한다. master 브랜치에 병합할 때는 태그를 부여하는 것이 나중을 위해서 여러 모로 편리하다.

$ git tag -a 0.1 -m "Initial public release" master

$ git push --tags

 

Git은 저장소에 어떤 이벤트가 발생할 때 미리 짜 놓은 스크립트를 자동으로 실행할 수 있는 훅(hook) 기능을 가지고 있다. 중앙 저장소의 master 브랜치에 푸시하거나 태그를 푸시할 때, 자동으로 공개 릴리스를 빌드하는 훅을 거는 등의 자동화도 가능하다.

 

릴리스를 배포한 후에, 미애는 철이와 함께 다음 릴리스를 준비하기 위해 일상으로 돌아갔다. 그런데 사용자가 현재 릴리스에 버그가 있다고 보고해왔다. 버그를 해결 하기 위해 미애(또는 철이)는 작업하던 기능 개발을 잠시 미뤄두고, master 브랜치를 기준으로 유지 보수 브랜치를 만들고, 버그를 수정하고 커밋한다. 버그 수정이 끝나면 master 브랜치에 바로 병합한다.

$ git checkout -b issue-#001 master

# Fix the bug

$ git checkout master

$ git merge issue-#001

$ git push

 

릴리스 브랜치와 마찬가지로, 유지 보수 브랜치에서의 변경 사항은 개발 중인 기능에도 반영되어야 하므로 develop 브랜치에도 병합해야 한다. 병합이 끝나면 유지 보수 브랜치는 삭제해도 좋다.

$ git checkout develop

$ git merge issue-#001

$ git push

$ git branch -d issue-#001

 

 

역주) Git 플러그인을 설치하면 Gitflow Workflow를 쉽게 사용할 수 있다.

http://blog.appkr.kr/work-n-play/git-flow/

 

 

 

 

 

 

[Git Flow] http://blog.appkr.kr/work-n-play/git-flow/

http://nvie.com/posts/a-successful-git-branching-model/

 

 

설치 방법.

https://github.com/nvie/gitflow/wiki/Mac-OS-X

 

$ brew install git-flow

 

$ git flow version

# 0.4.1

 

$ git flow

# usage: git flow <subcommand>

#

# Available subcommands are:

#    init      Initialize a new git repo with support for the branching model.

#    feature   Manage your feature branches.

#    release   Manage your release branches.

#    hotfix    Manage your hotfix branches.

#    support   Manage your support branches.

#    version   Shows version information.

#

# Try 'git flow <subcommand> help' for details.

 

feature, release, hotfix, support 등의 하위 명령이 있다.

 

데모 프로젝트를 만들고, Git 및 Git Flow를 초기화한다.

$ git init gitflow-demo && cd gitflow-demo

 

~/gitflow-demo(branch:master) $ git flow init

# No branches exist yet. Base branches must be created now.

# Branch name for production releases: [master]

# Branch name for "next release" development: [develop]

#

# How to name your supporting branch prefixes?

# Feature branches? [feature/]

# Release branches? [release/]

# Hotfix branches? [hotfix/]

# Support branches? [support/]

# Version tag prefix? []

 

Git Flow 초기화 과정에서 master와 develop 브랜치를 자동으로 만들어 준다. 그리고, feature, release, hotfix로 사용할 브랜치의 접두어 정보를 미리 설정한다. 초기화 과정을 마치면, 자동으로 develop 브랜치로 체크아웃된다.

~/gitflow-demo(branch:develop) $ git branch

# * develop

#   master

 

모든 작업은 develop 브랜치에서 시작한다. feature start 이름으로 시작하고, feature finish 이름으로 끝난다. 다른 하위 명령도 모두 마찬가지다.

~/gitflow-demo(branch:develop) $ git flow feature start awesome

# Switched to a new branch 'feature/awesome'

#

# Summary of actions:

# - A new branch 'feature/awesome' was created, based on 'develop'

# - You are now on branch 'feature/awesome'

#

# Now, start committing on your feature. When done, use:

#

#      git flow feature finish awesome

 

 

자세히 보면, develop 브랜치에서 feature/awesome 브랜치를 땄고, 새로 만든 브랜치로 이동했다. 이제 Feature를 개발하고, 평상시 처럼 커밋하면 된다.

~/gitflow-demo(branch:feature/awesome) $ git commit -am '...'

~/gitflow-demo(branch:feature/awesome) $ git commit -am 'feature finished'

 

 

계획했던 개발이 끝나면, Git Flow로 Feature 개발을 끝낸다.

~/gitflow-demo(branch:feature/awesome) $ git flow feature finish awesome

# Summary of actions:

# - The feature branch 'feature/awesome' was merged into 'develop'

# - Feature branch 'feature/awesome' has been removed

# - You are now on branch 'develop'

 

Git Flow가 자동으로 feature/awesome 브랜치를 develop 브랜치에 머지하고, 필요 없는 브랜치는 삭제했다.

 

릴리스도 develop 브랜치에서 시작한다. 최종 결과는 master 브랜치에 적용된다.

~/gitflow-demo(branch:develop) $ git flow release start 0.0.1

# Switched to a new branch 'release/0.0.1'

#

# Summary of actions:

# - A new branch 'release/0.0.1' was created, based on 'develop'

# - You are now on branch 'release/0.0.1'

#

# Follow-up actions:

# - Bump the version number now!

# - Start committing last-minute fixes in preparing your release

# - When done, run:

#

#      git flow release finish '0.0.1'

 

Git Flow가 develop 브랜치에서 release/0.0.1 브랜치를 땄다. 이제 코드에 수정할 부분들을 수정하면 된다. 버전 번호가 하드코드도 되어 있다면 수정하고, README.md 등에 설치/사용법들을 업데이트하는 작업이 될 것이다.

~/gitflow-demo(branch:release/0.0.1) $ git commit -am '...'

~/gitflow-demo(branch:release/0.0.1) $ git commit -am 'release ready'

 

이제 Git Flow로 릴리스 작업을 끝낸다.

~/gitflow-demo(branch:release/0.0.1) $ git flow release finish 0.0.1

 

 

에디터가 총 세 번 뜬다.

릴리스를 master 브랜치에 머지할 때 메시지를 입력하는 에디터

릴리스의 태그를 메기는 에디터

릴리스 브랜치에서 변경된 내용을 포함해서 develop 브랜치에 머지할 때 메시지를 입력하는 에디터

 

최종 메시지는 다음과 같다. origin의 변경사항도 가져온다는 점을 눈여겨봐야 한다.

# Summary of actions:

# - Latest objects have been fetched from 'origin'

# - Release branch has been merged into 'master'

# - The release was tagged 'v0.0.1'

# - Release branch has been back-merged into 'develop'

# - Release branch 'release/0.0.1' has been deleted

 

Feature 개발과 다를 바 없다. 다만, 핫 픽스는 릴리스에 바로 반영된다는 점이 다르다. 다시 말하면, Feature 개발과 릴리스를 합쳐 놓은 동작이다.

~/gitflow-demo(branch:develop) $ git flow hotfix start hotfix1

# Switched to a new branch 'hotfix/hotfix1'

#

# Summary of actions:

# - A new branch 'hotfix/hotfix1' was created, based on 'master'

# - You are now on branch 'hotfix/hotfix1'

#

# Follow-up actions:

# - Bump the version number now!

# - Start committing your hot fixes

# - When done, run:

#

#      git flow hotfix finish 'hotfix1'

 

~/gitflow-demo(branch:hotfix/hotfix1) $ git commit -am '...'

~/gitflow-demo(branch:hotfix/hotfix1) $ git commit -am 'hotfix done'

 

~/gitflow-demo(branch:hotfix/hotfix1) $ git flow hotfix finish hotfix1

 

역시 에디터가 세 번 뜬다. 최종 메시지는 다음과 같다.

# Summary of actions:

# - Latest objects have been fetched from 'origin'

# - Hotfix branch has been merged into 'master'

# - The hotfix was tagged 'hotfix1'

# - Hotfix branch has been back-merged into 'develop'

# - Hotfix branch 'hotfix/hotfix1' has been deleted

~/gitflow-demo(branch:develop) $

 

 

git flow cheat sheet

http://danielkummer.github.io/git-flow-cheatsheet/index.ko_KR.html

github flow

https://guides.github.com/introduction/flow/

 

 

 

 

원격 저장소를 클론하면, 기본적으로 master 브랜치만 복제된다. develop 브랜치를 fetch하기 위해서는...

$ git branch --all

# * master

#   remotes/origin/develop

#   remotes/origin/master

 

$ git checkout origin/develop

 

$ git checkout -b develop origin/develop

 

$ git branch

# * develop

#   master

 

 

 

 

 

 

 

 

 

workspace -[add]- stage -[commit]- git(local repo) -[push]- scm server

workspace -[...]- stage -[merge]- git(local repo) -[fetch]- scm server [fetch + merge = pull]

 

 

http://www.slideshare.net/einsub/svn-git-17386752?related=2

 

 

merge 에 관한 이야기 : http://git-scm.com/book/ko/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%B8%8C%EB%9E%9C%EC%B9%98%EC%99%80-Merge%EC%9D%98-%EA%B8%B0%EC%B4%88

 

stash :

 

ammend :

 

 

git reset --hard HEAD (커밋되지 않은 것들 파일까지 모두 HEAD 로 원복)

git checkout ...

 

 

 

 

개별파일 원복

git checkout  -- <파일> : 워킹트리의 수정된 파일을 index에 있는 것으로 원복

git checkout HEAD -- <파일명> : 워킹트리의 수정된 파일을 HEAD에 있는 것으로 원복(이 경우 --는 생략가능)

git checkout FETCH_HEAD -- <파일명> : 워킹트리의 수정된 파일의 내용을 FETCH_HEAD에 있는 것으로 원복? merge?(이 경우 --는 생략가능)

 

index 추가 취소

git reset -- <파일명> : 해당 파일을 index에 추가한 것을 취소(unstage). 워킹트리의 변경내용은 보존됨. (--mixed 가 default)

git reset HEAD <파일명> : 위와 동일

 

commit 취소

git reset HEAD^ : 최종 커밋을 취소. 워킹트리는 보존됨. (커밋은 했으나 push하지 않은 경우 유용)

git reset HEAD~2 : 마지막 2개의 커밋을 취소. 워킹트리는 보존됨.

git reset --hard HEAD~2 : 마지막 2개의 커밋을 취소. index 및 워킹트리 모두 원복됨.

git reset --hard ORIG_HEAD : 머지한 것을 이미 커밋했을 때,  그 커밋을 취소. (잘못된 머지를 이미 커밋한 경우 유용)

git revert HEAD : HEAD에서 변경한 내역을 취소하는 새로운 커밋 발행(undo commit). (커밋을 이미 push 해버린 경우 유용)

 

워킹트리 전체 원복

git reset --hard HEAD : 워킹트리 전체를 마지막 커밋 상태로 되돌림. 마지막 커밋이후의 워킹트리와 index의 수정사항 모두 사라짐.

                                  (변경을 커밋하지 않았다면 유용)

git checkout HEAD . : ??? 워킹트리의 모든 수정된 파일의 내용을 HEAD로 원복.

git checkout -f : 변경된 파일들을 HEAD로 모두 원복(아직 커밋하지 않은 워킹트리와 index 의 수정사항 모두 사라짐. 신규추가 파일 제외)

 

 

* 참조 : reset 옵션

--soft : index 보존, 워킹트리 보존. 즉 모두 보존.

--mixed : index 취소, 워킹트리만 보존 (기본 옵션)

--hard : index 취소, 워킹트리 취소. 즉 모두 취소.

 

* untracked 파일 제거

git clean -f

git clean -f -d : 디렉토리까지 제거

 

반응형

댓글

Designed by JB FACTORY