소스코드를 효과적으로 관리하기 위해 개발된 '분산형 버전 관리 시스템'
원격 저장소와 로컬 저장소
Git은 원격 저장소와 로컬 저장소 두 종류의 저장소를 제공
평소에는 내 PC의 로컬 저장소에서 작업하다가 작업한 내용을 공개하고 싶을 때에 원격 저장소에 업로드
저장소 만들기
- 만들어져 있는 원격 저장소를 로컬 저장소로 복사
- 또는 새로운 저장소 생성
브랜치(branch)
브랜치(branch)란?
독립적으로 어떤 작업을 진행하기 위한 개념
여러 개발자들이 동시에 다양한 작업을 할 수 있게 만들어 주는 기능
각각의 브랜치는 다른 브랜치의 영향을 받지 않기 때문에, 여러 작업을 동시에 진행할 수 있다.
브랜치는 다른 브랜치와 병합(Merge)함으로써, 작업한 내용을 다시 새로운 하나의 브랜치로 모을 수 있다.
브랜치 만들기
어떠한 방식으로 브랜치를 만들고 통합할 것인지 미리 정해둔다.
새로운 브랜치를 만들 때에 브랜치 이름은 어떤 규칙으로 지을 것인지 또는 어떤 상황에서 브랜치를 만들 지, 어느 시점에 통합할 것인지 등등
통합 브랜치(Integration Branch)
언제든지 배포할 수 있는 버전을 만들 수 있어야 하는 브랜치
늘 안정적인 상태를 유지하는 것이 중요
일반적으로 저장소를 처음 만들었을 때에 생기는 'master' 브랜치를 통합 브랜치로 사용
토픽 브랜치(Topic Branch)
기능 추가나 버그 수정과 같은 단위 작업을 위한 브랜치
여러 개의 작업을 동시에 진행할 때에는, 그 수만큼 토픽 브랜치를 생성
토픽 브랜치에서 특정 작업이 완료되면 다시 통합 브랜치에 병합
브랜치 전환하기
처음에 Git을 설치하게 되면 'master' 브랜치가 선택
현재 선택된 브랜치가 아닌 다른 브랜치에서 작업하고 싶을 때에는, '체크아웃(checkout)' 명령어를 실행하여 원하는 브랜치로 전환
HEAD
'HEAD' 란 현재 사용 중인 브랜치의 선두 부분을 나타내는 이름
stash
파일의 변경 내용을 일시적으로 기록해두는 영역
브랜치 통합하기
merge
변경 내용의 이력이 모두 그대로 남아 있기 때문에 이력이 복잡
rebase
이력은 단순해지지만, 원래의 커밋 이력이 변경됨. 정확한 이력을 남겨야 할 필요가 있을 경우에는 사용하면 안됨
효과적인 브랜치 이용
메인 브랜치(Main branch)
- master
배포 가능한 상태만을 관리
커밋할 때에는 태그를 사용하여 배포 번호를 기록 - develop
통합 브랜치의 역할을 하며, 평소에는 이 브랜치를 기반으로 개발을 진행
피처 브랜치(Feature branch) 또는 토픽 브랜치(Topic branch)
새로운 기능 개발 및 버그 수정이 필요할 때에 'develop' 브랜치로부터 분기
개발이 완료되면 'develop' 브랜치로 병합하여 다른 사람들과 공유
릴리즈 브랜치(Release branch)
릴리즈 브랜치에서는 버그를 수정하거나 새로운 기능을 포함한 상태로 모든 기능이 정상적으로 동작하는지 확인
다음 번 릴리즈를 위한 개발 작업은 'develop' 브랜치 에서 계속 진행
릴리즈 브랜치에서는 릴리즈를 위한 최종적인 버그 수정 등의 개발을 수행
모든 준비를 마치고 배포 가능한 상태가 되면 'master' 브랜치로 병합시키고, 병합한 커밋에 릴리즈 번호 태그를 추가
릴리즈 브랜치에서 기능을 점검하며 발견한 버그 수정 사항은 'develop' 브랜치에도 적용
배포 완료 후 'develop' 브랜치에 대해서도 병합 작업을 수행
이름 앞에 'release-' 를 붙임
핫픽스 브랜치(Hotfix branch)
배포한 버전에 긴급하게 수정을 해야 할 필요가 있을 경우, 'master' 브랜치에서 분기하는 브랜치
브랜치 이름 앞에 'hotfix-'를 붙임
브랜치 만들기
git branch <branchname>
# issue1 브랜치 생성
> git branch issue1
# 앞 부분에 * 이 붙어있는 것이 현재 선택된 브랜치
> git branch
issue1
* master
브랜치 전환하기
git checkout <branch>
> git checkout issue1
Switched to branch 'issue1'
# myfile.txt 파일을 먼저 만들어 두고
> git add myfile.txt
> git commit -m "add 설명을 추가"
[issue1 b2b23c4] add 설명을 추가
1 files changed, 1 insertions(+), 0 deletions(-)
- myfile.txt 에 아래 내용 추가
원숭이도 이해할 수 있는 Git 명령어
add: 변경 사항을 만들어서 인덱스에 등록해보기
> git add myfile.txt
> git commit -m "add 설명을 추가"
[issue1 b2b23c4] add 설명을 추가
1 files changed, 1 insertions(+), 0 deletions(-)
브랜치 병합하기 - fast-forward (빨리감기) 병합
git merge <commit>
> git checkout master
Switched to branch 'master'
> git merge issue1
Updating 1257027..b2b23c4
Fast-forward
myfile.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
브랜치 삭제하기
git branch -d <branchname>
# 'issue1' 브랜치 삭제
$ git branch -d issue1
Deleted branch issue1 (was b2b23c4).
# 삭제됐는지 확인
> git branch
* master
동시에 여러 작업하기
# 'issue2' 와 'issue3' 브랜치를 만든 후, 'issue2' 브랜치로 전환
> git branch issue2
> git branch issue3
> git checkout issue2
Switched to branch 'issue2'
> git branch
* issue2
issue3
master
- myfile.txt 에 아래 내용 추가
원숭이도 이해할 수 있는 Git 명령어
add: 변경 사항을 만들어서 인덱스에 등록해보기
+ commit: 인덱스 상태를 기록하기
> git add myfile.txt
> git commit -m "commit의 설명 추가"
[issue2 8f7aa27] commit의 설명 추가
1 files changed, 2 insertions(+), 0 deletions(-)
# 'issue3' 브랜치로 전환
> git checkout issue3
Switched to branch 'issue3'
- myfile.txt 에 아래 내용 추가
원숭이도 이해할 수 있는 Git 명령어
add: 변경 사항을 만들어서 인덱스에 등록해보기
+ pull: 원격 저장소의 내용을 가져오기
> git add myfile.txt
> git commit -m "pull 설명을 추가"
[issue3 e5f91ac] pull 설명을 추가
1 files changed, 2 insertions(+), 0 deletions(-)
merge 병합
- 'issue2' 브랜치 병합
> git checkout master
Switched to branch 'master'
> git merge issue2
Updating b2b23c4..8f7aa27
Fast-forward
myfile.txt | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
- 'issue3' 브랜치 병합
> git merge issue3
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Automatic merge failed; fix conflicts and then commit the result.
- 충돌부분 수정
원숭이도 이해할 수 있는 Git 명령어
add: 변경 사항을 만들어서 인덱스에 등록해보기
<<<<<<< HEAD
commit: 인덱스의 상태를 기록하기
=======
pull: 원격 저장소의 내용을 가져오기
>>>>>>> issue3
- 충돌 수정 후 다시 커밋
> git add myfile.txt
> git commit -m "issue3 브랜치 병합"
# On branch master
nothing to commit (working directory clean)
rebase 병합
- 마지막으로 진행했던 병합 명령을 취소
> git reset --hard HEAD~
- 'issue3' 브랜치로 전환하여 'master' 브랜치에 rebase 를 실행
> git checkout issue3
Switched to branch 'issue3'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: pull 설명을 추가
Using index info to reconstruct a base tree...
<stdin>:13: new blank line at EOF.
+
warning: 1 line adds whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging myfile.txt
CONFLICT (content): Merge conflict in myfile.txt
Failed to merge in the changes.
Patch failed at 0001 pull 설명을 추가
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
myfile.txt 파일 내용에 충돌 수정
원숭이도 이해할 수 있는 Git 명령어
add: 변경 사항을 만들어서 인덱스에 등록해보기
- <<<<<<< HEAD
commit: 인덱스의 상태를 기록하기
- =======
pull: 원격 저장소의 내용을 가져오기
- >>>>>>> issue3
- rebase 의 경우 충돌 부분을 수정 한 후에는 commit 이 아니라 rebase 명령에 --continue 옵션을 지정하여 실행
> git add myfile.txt
> git rebase --continue
Applying: pull 설명을 추가
- 'master' 브랜치로 전환 하여 'issue3' 브랜치의 변경 사항을 모두 병합
> git checkout master
Switched to branch 'master'
> git merge issue3
Updating 8f7aa27..96a0ff0
Fast-forward
myfile.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
커밋(commit)
이전 커밋 상태부터 현재 상태까지의 변경 이력 기록
각 커밋에는 영문/숫자로 이루어진 40자리 고유ID가 있고, 저장소에선 이 40자리 이름을 보고 각 커밋을 구분하고 선택
버그 수정, 기능 추가 등 특별한 의미가 있는 업데이트를 작업 별로 구분해서 각각 커밋하면, 나중에 이력을 보고 특정 변경 내용을 찾기 쉽다.
커밋 버튼을 누를땐 커밋 메시지를 필수로 입력
> git commit -m '변경내용 요약'
커밋 수정하기
git commit –amend: 커밋 덮어쓰기
> git commit --amend
amend의 옵션의 경우 스테이징에 추가된 내용을 반영해주는 동시에 커밋 메시지도 변경
변경할 내용이 없을 때도 커밋메시지를 변경하고 싶을 때 자주 사용
revert 명령어
- 특정 커밋의 내용을 삭제
이전에 작성한 커밋을 안전하게 지우고 싶을 때
revert 명령어를 사용하여 커밋 B의 내용을 뒤집어 원래의 커밋 A의 상태로 돌아갈 수 있는 새로운 커밋 B'를 만듬
> git revert HEAD
> git log --oneline
3333333 (HEAD -> main) second commit
2222222 first commit
1111111 Readme.md
333333 커밋을 되돌리는 경우
> git revert 333333
[main 333333] Revert "second commit"
1 file changed, 1 deletion(-)
delete mode 160000 ...............
결과 확인
> git log --oneline
444444 (HEAD -> main) Revert "second commit"
333333(origin/main) second commit
222222 Add .gitignore
111111 Readme.md
reset 명령어
- 더 이상 필요 없어진 커밋들을 버림
옵션으로 'HEAD' 위치와 인덱스, 작업 트리 내용을 함께 되돌릴지 여부를 선택 가능
모드명 | 설명 | HEAD의 위치 | 인덱스 | 작업 트리 |
---|---|---|---|---|
soft | 커밋만 되돌리고 싶을 때 | 변경함 | 변경 안 함 | 변경 안 함 |
mixed | 변경한 인덱스의 상태를 원래대로 | 변경함 | 변경함 | 변경 안 함 |
hard | 커밋을 완전히 버리고 이전 상태로 | 변경함 | 변경함 | 변경함 |
커밋한 순서 111111 > 222222 > 333333
> git log --oneline
3333333 (HEAD -> main) second commit
2222222 first commit
1111111 Readme.md
333333을 취소하고 싶다면
# HEAD가 이전 커밋(222222)을 가리키도록
# --hard 옵션은 현재 HEAD에서 추가된 변경 사항들을 모두 되돌려줌
> git reset --hard 222222
# 또는 직전 커밋으로 되돌릴 경우
> git reset --hard HEAD^
# Git 저장소에서 관리 하지 않는 파일들(Untracked files)을 추가한 경우 git clean 으로 따로 삭제
# 삭제 대상(Untracked files) 목록 확인
> git clean -n
# Untracked files 파일 삭제
> git clean -f
삭제 후 git log와 git status 명령어로 현재 저장소 상태를 확인
> git log --oneline
222222 (HEAD -> main) first commit
111111 Readme.md
> git status
On branch main
nothing to commit, working tree clean
cherry-pick
- 다른 브랜치에서 지정한 커밋을 복사하여 현재 브랜치로 가져옴
# 다른 브랜치에서 커밋 내용을 'master' 브랜치로
> git checkout master
Switched to branch 'master'
> git cherry-pick 99daed2
rebase 명령어
- 커밋을 다시 쓰거나 다른 커밋과 바꿔 넣을 수 있으며 특정 위치의 커밋을 삭제하거나 여러 커밋을 하나로 통합하는 작업
- push 하기 전에 이전의 커밋 내용을 정리하고자 할 때
- 그룹으로 묶을 수 있는 커밋들을 알기 쉽게 하나로 통합하려고 할 때
- 이전 커밋에 누락된 파일들을 나중에 추가하고자 할 때
커밋 모두 통합하기
> git rebase -i HEAD~~
# 'pick' 문자를 'squash'로 변경, 저장 후 종료
커밋 수정하기
> git rebase -i HEAD~~
# 첫 번째 줄의 'pick' 문자를 'edit'으로 변경하여 저장 · 종료
> git commit --amend
> git rebase --continue
원격 저장소에 푸시(Push)하기
- 웹 상의 원격 저장소로 변경된 파일을 업로드하는 것
- push 를 실행하면, 원격 저장소에 내 변경 이력이 업로드되어, 원격 저장소와 로컬 저장소가 동일한 상태
> git push
> git push -u <REPO_NAME> <BRANCHES_NAME>
원격 저장소에서 풀(Pull)해오기
- 원격 저장소에서 로컬 저장소로 다운로드, 업데이트(병합)
- 원격 저장소에서 최신 변경 이력을 다운로드하여 내 로컬 저장소에 그 내용을 적용
다운로드 하거나
병합
> git pull # 현재 내 로컬 브랜치와 같은 이름을 가진 리모트 서버 브랜치가 타겟
> git pull origin master # origin 리모트 서버의 master 브랜치가 타겟
원격 저장소 복제(Clone)하기
- 원격 저장소의 내용을 통째로 다운로드하는 것
원격 저장소 패치(fetch) 하기
- 원격 저장소의 데이터를 로컬 저장소로 다운로드만
로컬 저장소와 원격 저장소에 B에서 진행된 커밋이 있는 상태에서 fetch 를 수행하면 아래 그림과 같이 이력이 남겨짐
이 상태에서 원격 저장소의 내용을 로컬 저장소의 'master'에 통합하고 싶은 경우에는, 'FETCH_HEAD' 브랜치를 merge 하거나 다시 pull 을 실행
리모트 서버의 최신 이력을 내 클라이언트로 가져오되 병합은 하지 않음
> git fetch
리모트 서버에 새로 업데이트한 모든 내역을 받아옴
로컬에 있는 버전이 리모트 서버에 있는 버전보다 이전 버전이라면 pull 명령어를 사용하여 내 컴퓨터의 소스 코드를 갱신
> git fetch --all -p; git branch -vv | grep ": gone]" | awk '{ print $1 }' | xargs -n 1 git branch -d
fetch를 통해 리모트 서버의 최신 내용을 받아온 뒤, branch 명령어를 사용하여 리모트 서버에서는 삭제되었지만 로컬에는 남아있는 브랜치를 찾아서 싹 다 지워주는 스크립트
참고로 로컬에는 있지만 리모트에서 삭제된 브랜치는 브랜치 이름 뒤에 : gone이라는 문구가 붙어있기 때문에 구분이 가능
> git branch -v
* master fa0cec5 [origin/master] 마스터 브랜치
test 1f3578f [origin/test: gone] 리모트에선 죽은 브랜치
test2 fa0cec5 로컬에서 만들어지고 리모트에 업데이트는 안된 브랜치
태그 (Tag)
커밋을 참조하기 쉽도록 알기 쉬운 이름을 붙이는 것
한 번 붙인 태그는 브랜치처럼 위치가 이동하지 않고 고정
태그(Tag) 실습
준비
> mkdir tutorial
> cd tutorial
> git init
myfile.txt 파일 생성
원숭이도 이해할 수 있는 Git 명령어
커밋 실행
> git add myfile.txt
> git commit -m "first commit"
[master (root-commit) a73ae49] first commit
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile.txt
태그 추가하기
git tag <tagname>
'HEAD'가 가리키고 있는 커밋에 'apple' 이라는 태그 추가
> git tag apple
# 태그 정보를 포함한 이력을 확인
> git log --decorate
commit e7978c94d2104e3e0e6e4a5b4a8467b1d2a2ba19 (HEAD, tag: apple, master)
Author: yourname <yourname@yourmail.com>
first commit
주석 달린 태그 추가하기
git tag -am "커밋 내용" <tagname>
현재 'HEAD'가 가리키고 있는 커밋에 'banana'라는 주석이 달린 태그
> git tag -am "누구나 쉽게 이해할 수 있는 Git 입문" banana
# 태그 목록과 주석 내용을 확인
> git tag -n
apple first commit
banana 누구나 쉽게 이해할 수 있는 Git 입문
태그 삭제하기
> git tag -d <tagname>
> git tag -n
apple first commit
apple2 태그네임
banana 태그 바나나
# 태그 apple2 삭제
> git tag -d apple2
Deleted tag 'apple2' (was 5a7dcca)
> git tag -n
apple first commit
banana 태그 바나나
<참고> 누구나 쉽게 이해할 수 있는 Git 입문