about Git

게시: by Creative Commons Licence

1. 참고

Git 공식문서 - 매우 좋은 사이트 !!!

git - 간편 안내서 - 어렵지 않아요 - 한글 사이트, 이해하기 쉽다.

  • 다음은 위 참고 사이트를 요약 정리한 것입니다.

2. 시작하기

1) Git의 기초

  • 분산 버전 관리 시스템
  • 빠른 속도, 단순한 구조, 비선형적인 개발( 수 천 개의 동시 다발적인 브랜치), 완벽한 분산
  • Git의 기초
버전 1 버전 2 버전 3 버전 4 버전 5
파일 A A1 (not Δ1) A1 A2 A2
파일 B B B B1 B2
파일 C C1 C2 C2 C3
  • 차이(not Δ1)가 아니라 스냅샷. Git은 데이터를 스냅샷의 스트림처럼 취급한다.

  • 거의 모든 명령을 로컬에서 실행 : Git은 작은 파일 시스템 :: 로컬 데이터베이스의 히스토리임

  • Git의 무결성: 저장 전 체크섬을 구하고, 이 체크섬으로 데이터를 관리함

    • 체크섬- Git의 가장 기본적인 데이터 단위(Atomic Data Unit), Git의 기본 철학

    • Git만 ✓ SHA-1 해시 알고리즘을 통하여 체크섬을 만든다.
    • SHA-1의 모습 24b9da6552252987aa493b52f8696cd6d3b00373
    • Git은 모든 것을 해시로 식별하고, 파일 또한 해시로 저장함
  • Git은 데이터를 추가할 뿐 : 스냅샷 ➝ 커밋 이후 데이터를 되돌리거나 삭제할 방법이 없다.

  • 세 가지 상태 ☛ 파일상태확인은 $ git status

    • Committed : 데이터가 로컬 데이터베이스에 안전하게 저장됐다.
    • Modified : 수정하였으나 아직 로컬 데이터베이스에 커밋하지 않은 것
    • Staged : 스냅샷을 찍어 곧 커밋할 것이라고 표시한 상태
Working Directory   Staging Area   .git 로컬 저장소
Untracked $ git add Staged (스냅샷) $ git commit --amend Commited (영구적인 스냅샷)
Unmodified        
Modified $ git checkout -- <file> $ git reset HEAD <file>    

2) Git 설치

  • Ubuntu 등 데이안 계열 리눅스 배포판 sudo apt-get install git

3) Git 최초 설정 - git config

  • 설정 파일의 위치
➜  ~ git config
사용법: git config [<옵션>]
설정 파일 위치
    --global              공통 설정 파일을 사용합니다  # ~/.gitconfig
    --system              시스템 설정 파일을 사용합니다 # /etc/gitconfig
    --local               저장소 설정 파일을 사용합니다
    -f, --file <파일>     지정한 설정 파일을 사용합니다
    --blob <블롭-id>      지정한 블롭 오브젝트에서 설정을 읽습니다

# 주요 설정:  ~/.git/config 
  • 사용자 정보
# --global 옵션 설정은 딱 한 번 쓰인다. 
➜ git config --global user.name "Hong_Gildong"
➜ git config --global user.email HongGildong@example.com
  • 편집기 설정
# 기본은 vi 
➜ git config --global core.editor [편집기명]
# 예 
➜ git config --global core.editor vim
➜ git config --global core.editor nano
➜ git config --global core.editor gedit
  • 설정 확인 git config -list

4) git help

➜ git help [command]
➜ git [command] --help
➜ man git-[command]

3. Git의 기초

1) git init - 저장소 만들기

  • 새로 만들기
➜ git init
  • 기존 저장소를 Clone 하기
➜ git clone <URL>
➜ git clone https://github.com/libgit2/libgit2 mylibgit

2) git status - 파일 상태 확인

파일의 라이프 사이클

➜ git status 

3) git add [파일] 추적하기

4) .gitignore- 파일 무시

표준 Glob 패턴 : *, **, ?, [0-9], [a-z]
슬래시( /) 로 시작하면 하위 디렉토리에 적용되지 않는다( Recursivity ).
느낌표 (!)로 시작하는 패턴의 파일은 무시하지 않는다.
  • 예시
# 확장자가 .a인 파일 무시
*.a

# 윗 라인에서 확장자가 .a인 파일은 무시하게 했지만 lib.a는 무시하지 않음
!lib.a

# 현재 디렉토리에 있는 TODO파일은 무시하고 subdir/TODO처럼 하위디렉토리에 있는 파일은 무시하지 않음
/TODO

# build/ 디렉토리에 있는 모든 파일은 무시
build/

# doc/notes.txt 파일은 무시하고 doc/server/arch.txt 파일은 무시하지 않음
doc/*.txt

# doc 디렉토리 아래의 모든 .pdf 파일을 무시
doc/**/*.pdf

5) $ git diff

​ ╾ Staged vs Unstaged의 변경 내용을 보기

➜ git diff 

​ ╾ Committed vs Staged의 변경 내용을 보기

➜ git diff -staged
➜ git diff -cached

6) git commit

​ ╾ 변경사항 커밋하기 : $ git commit -m "<message>"

​ ╾ Staging Area 생략하기 : $ git commit -a -m "<message>"

7) git rm - 파일 삭제

  • 파일 삭제하기

Git에서 파일을 제거하려면 , ❶ git rm 명령으로 Tracked 상태의 파일을 삭제한 후에(정확하게는 Staging Area에서 삭제하는 것, 스냅샷 지우기) ➁ git commit으로 커밋해야 한다.

이 명령은 워킹 디렉토리에 있는 파일도 삭제하기 때문에 실제로 파일도 지워진다.

➜ git rm grit.gemspec
rm 'grit.gemspec'

➜ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    deleted:    grit.gemspec
    
➜ git commit     
  • 추적에서만 벗어나기
➜ git rm --cached [파일명] 

8) git mv - 파일 이름 변경

➜ git mv fileA fileB
➜ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    fileA -> fileB

위 명령어는 사실 아래와 같다.

➜ mv fileA fileB
➜ git rm fileA
➜ git add fileB

9) git log - 커밋 히스토리 조회

  • 설명
➜ git log
commit ca82a6dff817ec66f44342007202690a93763949 # SHA-1 체크섬
Author: Scott Chacon <schacon@gee-mail.com>     # 저자 이름, 저자 이메일
Date:   Mon Mar 17 21:52:11 2008 -0700          # 커밋한 날자

    changed the version number                  # 커밋 메세지         
# 각 커밋의 diff결과 최근 2개 
➜ git log -p -2

# 히스토리 통계 
➜ git log --stat

 README           |  6 ++++++
 Rakefile         | 23 +++++++++++++++++++++++
 lib/simplegit.rb | 25 +++++++++++++++++++++++++
 3 files changed, 54 insertions(+)
 
# 조회기록 형식 --pretty
##1. --pretty= oneline/short/full/fuller
➜ git log --pretty=oneline

ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit

##2. --pretty=format:"옵션들" [짧은해시-저자이름, 저작시간: 짧은요약]
➜ git log --pretty=format:"%h - %an, %ar : %s"

ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

# graph
➜ git log --pretty=format:"%h %s" --graph

* 2d3acf9 ignore errors from SIGCHLD on trap
*  5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
*  11d191e Merge branch 'defunkt' into local
  • 조회 조건 제한
➜ git log --since=2.weeks -5
➜ git log --since="2 years 1 day 3 minutes ago" -5
# 2018-05-15 이후 5개
➜ git log --after="2008-01-15" -5
# 2018-05-15 이전 5개 
➜ git log --before="2008-01-15" -5
# 저자 
➜ git log --author="HongGildong" 
# 커미터
➜ git log --committer="Greg"
# 커밋 메세지 안 텍스트 검색
➜ git log --grep="로그인 기능 추가"

# python/functions.py에서 변경(추가/삭제)된 코드 내용 검색 
➜ git log -S "def str2int" -- python functions.py
  • 용례
    # wolf라는 사람이 수정한 커밋 중 2008년 10월에 한 것에서 Merge 커밋을 한 것을 제외하여 검색 
    ➜ git log --pretty=format: "%h - %s" \
            --author=wolf \
            --after="2008-10-01" --before="2008-11-01" \
            --no-merges -t
    

10) 되돌리기

  • Git으로 커밋한 모든 것은 언제나 복구할 수 있다. 삭제한 브랜치에 있었던 것도, --amend 옵션으로 다시 커밋한 것도 복구할 수 있다(자세한 것은 데이터 복구 에서 다룬다). 하지만 커밋하지 않고 잃어버린 것은 절대로 되돌릴 수 없다.

git commit --amend

⟳ Committed ➝ Staged ( to Staging Area )

  • 커밋을 했는데 Stage 하는 것을 깜빡하고 빠트린 파일이 있으면 아래와 같이 고칠 수 있다.
➜ git commit -m '1st commit'
➜ git add <forgotten_file>
➜ git commit --amend

git reset HEAD

⟳ Staged ➝ Unstaged ( to Working Directory ) : $ git status에서 알려줌

➜ git add *
➜ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

➜ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md

$ git checkout --

위험한 명령임 : 수정된 내용이 모두 사라지고 수정 전 파일로 덮어쓰기하므로 주의 요망

⟳ Modified ➝ Unmodified : $ git status에서 알려줌

 modified:   CONTRIBUTING.md
➜ git checkout -- CONTRIBUTING.md
➜ git status 

11) 리모트 저장소

  • 리모트 저장소를 관리할 줄 알아야 다른 사람과 함께 일할 수 있다.

git remote -v

  • 현재 등록된 리모트 저장소 확인하기
➜ git remote -v

bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)

git remote show

  • 리모트 저장소를 구체적으로 살펴보기
➜ git remote show origin

* remote origin
  Fetch URL: https://github.com/schacon/ticgit
  Push  URL: https://github.com/schacon/ticgit
  HEAD branch: master
  Remote branches:
    master                               tracked
    dev-branch                           tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

git remote add

  • 리모트 저장소 추가하기
➜ git remote add pb https://github.com/paulboone/ticgit

bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (push)

➥ 리모트 저장소 ⟹ 로컬 저장소 : Pull하거나 Fetch하기

git fetch

  • 로컬 저장소에 없지만 리모트 저장소에 있는 데이터 모두를 가져오기
  • 리모트 저장소 ⟹ ( fetch ) ⟹ 로컬 저장소(.git )

git pull

  • 데이터를 모두 가져와서 로컬 브랜치에 자동으로 merge하기
  • 리모트 저장소 ⟹ ( fetch)⟹ 로컬 저장소 ⟹ ( merge ) ⟹ 로컬 브랜치

git push

  • ⬆ 리모트 저장소에 Push하기
➜ git push origin master

git remote rename

  • 로컬에서 관리하던 리모트 저장소의 브랜치 이름도 바뀐다는 점을 생각해두자. 여태까지 pb/master로 리모트 저장소 브랜치를 사용했으면 이제는 paul/master라고 사용해야 한다.
➜ git remote rename pb paul
➜ git remote

origin
paul

git remote remove

  • ⬌ 리모트 저장소 이름을 바꾸거나 리모트 저장소를 삭제하기
➜ git remote remove paul
➜ git remove

origin

12) 태그

  • 보통 릴리즈할 때 사용한다. (v1.0, v1.1 등등)

❶ 조회하기 git tag

➜  git tag
v0.1
v1.3

**➁ 붙이기 -a **

  • Annotated 태그
# Annotated 태그 
➜  git tag -a v1.4 

# 태그 조회 
➜  git tag 
v0.1
v1.3
v1.4

# 태그 정보와 커밋 정보 확인 
➜ git show v1.4

tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:19:12 2014 -0700

my version 1.4

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number
  • Lightweight 태그 붙이기
# -a 옵션이 없다. 
➜ git tag v1.5

# 별도의 태그 정보를 볼 수 없다. 
➜ git show v1.5
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

**❸ 예전 커밋에 태그하기 **

# 커밋 히스토리 조회 
➜  git log --pretty=oneline

15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
✔ 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function

# 예전 커밋 6d52a271에 태그하기 
➜  git tag -a v1.2 6d52a271

# 태그 조회
➜  git tag
v0.1
✔ v1.2
v1.3
v1.4

➃ 태그 공유하기

  • git push 명령은 자동으로 리모트 서버에 태그를 전송하지 않는다. 태그를 만들었으면 서버에 별도로 Push 해야 한다.
➜  git push origin  v1.5

# 여러 태그를 한꺼번에 push
➜  git push origin --tags

❺ Checkout 못함

13) Git Alias

  • Git을 좀 더 쉽고 편안하게 쓸 수 있게 만들어 줄 Alias 라는 팁
➜ git config --global alias.co checkout
➜ git config --global alias.br branch
➜ git config --global alias.ci commit
➜ git config --global alias.st status
➜ git config --global alias.unstage 'reset HEAD --'
➜ git config --global alias.last 'log -1 HEAD'
  • 사용법
➜ git st
➜ git status

➜ git unstage fileA
➜ git reset HEAD -- fileA

4. Git 브랜치

  • 사람들은 브랜치 모델이 Git의 최고의 장점이라고, Git이 다른 것들과 구분되는 특징이라고 말한다.

1) 브랜치란 무엇인가

➔ git add [file1] [file2] [file3]
➔ git commt -m "1st commit"

╾ '커밋'하면, 커밋 객체( tree개체 ⭢ commit개체 ⭢ 파일3개의 Blob개체 )가 생긴다. 커밋과 트리 데이터

'현재 커밋''이전 커밋' 커밋과 이전 커밋

2) git branch - 브랜치 생성

  • 브랜치를 생성하기만 하고 그곳으로 옮겨가지 않는다.
  • HEAD : 작업 중인 브랜치 를 나타내는 개념
➜  ~git:(dev-js) git branch testing

현재 작업 중인 브랜치를 가리키는 HEAD

# 쉽게 브랜치가 어떤 커밋을 가리키는지도 확인할 수 있다.
➜  ~git:(dev-js) git log --oneline --decorate

3) git checkout - 브랜치 이동

  • 브랜치 이동하기 : HEAD가 브랜치를 가르킨다.

  • 히스토리 출력

➜  git log --oneline --decorate --graph --all

* c2b9e (HEAD, master) made other changes  #--decorate HEAD와 브랜치이름 표시
| * 87ab2 (testing) made a change          #--oneline 한줄로 표시
|/                                         #--graph 아스키 그림으로 표시 
* f30ab add feature                        #--all  모든 커밋기록을 보여줌 
* 34ac2 fixed bug 
* 98ca9 1st commit

git checkout -b [브랜치]

  • 브랜치를 생성하면서 그 브랜치로 이동하기

4) git merge

git branch -d

╾ merge된 브랜치 삭제

◷ master 브랜치에서 작업 중 새로운 이슈를 위해 branch iss001을 만들어 작업하다가 master 브랜치에서 더 급박한 요청( hotfix )을 처리해야하는 상황이다. 이때, 어떻게 브랜치를 만들어 작업하고 merge해야하는가?

# master 작업  git checkout -b iss001
➜  wdir git:(master) git branch iss001
➜  wdir git:(master) git checkout iss01
Switched to branch "iss01"  # 브랜치 iss01에서 작업 ...
➜  wdir git:(iss01) python issue01.py 

# 갑자기 master 작업에서 더 급박히 해결해야할 요청(hotfix)를 처리해야 하는 상황 
➜  wdir git:(iss01) git commit -m "일단 issue01 작업 중단, master로 이동"
➜  wdir git:(iss01) git checkout master
Switched to branch "master"  

# master에서 hotfix 브랜치를 만들어서 그곳으로 이동 
➜  wdir git:(master) git chechout -b hotfix 
Switched to branch "hotfix"
# hotfix 문제 해결 
➜  wdir git:(hotfix) git commit -m "hotfix 문제 해결"

# master 브랜치로 이동하여 hotfix를 merge함 
➜  wdir git:(hotfix) git checkout master
Switched to branch "master"
➜  wdir git:(master) git merge hotfix 
# 이제 불필요한 hotfix 브랜치를 삭제함 
➜  wdir git:(master) git branch -d hotfix
Deleted branch hotfix (3a0874c).

# 중단했던 iss01 브랜치로 돌아가 작업함 
➜  wdir git:(master) git checkout iss01
Switched to branch "iss53"

➁ merge 충돌 및 해결

  • 3-way Merge

커밋 3개를 Merge

  • ⮡ merge하는 두 브랜치가 같은 파일을 동시에 수정 하는 경우 충돌 발생
➜ git merge iss01
Auto-merging [수정한 같은 파일]
CONFLICT (content): Merge conflict in [수정한 같은 파일]
Automatic merge failed; fix conflicts and then commit the result.
  • ⮡ 충돌 내용을 보려면 $ git status ⭢ 충돌한 파일을 직접 수정한다.
➜ git status
You have unmerged paths.
both modified: [수정한 파일]

➜ vi [수정한 파일 이름]
<<<<<<< HEAD:[수정한 파일]
<div id="footer">contact : email.support@github.com </div>
=======
<div id="footer">please contact us at support@github.com </div>
>>>>>>> iss01:[수정한 파일]
  • git mergetool ⭬ merge 충돌을 해결하는 다른 방법

5) 브랜치 관리

git branch

  • 브랜치 목록 보기
➜ git branch
 iss53
* master  # 현재 브랜치 * 
 testing
  • 브랜치 목록 보기 + 마지막 커밋 메세지
➜ git branch -v 
 iss53   93b412c fix javascript issue
* master  7a98805 Merge branch 'iss53'
 testing 782fd34 add scott to the author list in the readmes
  • Merge된 브랜치만 출력 - *가 붙지 않은 브랜치는 삭제해도 됨
➜ git branch --merged
 iss01    # 삭제 가능($ git branch -d iss01) 
* master

➜ git branch -d iss01

6) 브랜치 워크플로

  • 브랜치를 만들고 Merge 하는 것을 어디에 써먹어야 할까? 개발에 어떻게 적용해야 할까?

⭄ Long-Running 브랜치

  • Git 개발자가 많이 선호하는 워크플로가 하나 있다.

각 브랜치를 하나의 "실험실"로 생각

  • master 브랜치 - 배포했거나 배포할 코드만 master 브랜치에 Merge 해서 안정 버전의 코드만 master 브랜치에 둔다. 안정적인 브랜치일수록 커밋 히스토리가 뒤쳐짐
  • develop 브랜치 - 개발을 진행하고 안정화하는 브랜치는 develop이나 next라는 이름으로 추가로 만들어 사용한다. 이 브랜치는 언젠가 안정 상태가 되겠지만, 항상 안정 상태를 유지해야 하는 것이 아니다. 테스트를 거쳐서 안정적이라고 판단되면 master 브랜치에 Merge 한다.
  • 토픽 브랜치 (앞서 살펴본 iss53 브랜치 같은 짧은 호흡 브랜치)에도 적용할 수 있는데, 해당 토픽을 처리하고 테스트해서 버그도 없고 안정적이면 그때 Merge 한다.

안정적인 브랜치일수록 커밋 히스토리가 뒤쳐짐

7) 리모트 트래킹 브랜치 (origin/master)

  • 이곳을 반드시 참고하자~!!!

  • 리모트 트래킹 브랜치는 리모트 브랜치를 추적하는 브랜치다. 이 브랜치는 로컬에 있지만 움직일 수 없다. 리모트 서버에 연결할 때마다 리모트 브랜치에 따라서 자동으로 움직일 뿐이다. 리모트 트래킹 브랜치는 일종의 북마크라고 할 수 있다. 리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타낸다.

  • git clone

Clone 이후 서버와 로컬의 master 브랜치

  • 로컬과 서버의 커밋 히스토리는 독립적임

로컬과 서버의 커밋 히스토리는 독립적임

  • fetch하는 순간 리모트 서버의 커밋 = 리모크 트래킹 브랜치 - git fetch 명령은 리모트 브랜치 정보를 업데이트함.

git fetch 명령은 리모트 브랜치 정보를 업데이트 함

  • 다른 리모트 서버를 추적하는 리모트 트래킹 브랜치

'teamone/master'의 리모트 트래킹 브랜치

git push

  • 로컬의 브랜치를 서버로 전송하려면 쓰기 권한이 있는 리모트 저장소에 Push 해야 한다. 로컬 저장소의 브랜치는 자동으로 리모트 저장소로 전송되지 않는다. 명시적으로 브랜치를 Push 해야 정보가 전송된다. 따라서 리모트 저장소에 전송하지 않고 로컬 브랜치에만 두는 비공개 브랜치를 만들 수 있다. 또 다른 사람과 협업하기 위해 토픽 브랜치만 전송할 수도 있다.
# 리모트 저장소 origin 
# 로컬 브랜치 serverfix ➜ 리모트 브랜치 remotefix
➜  git push origin serverfix:remotefix
* [new branch]      serverfix    -> origin/remotefix

git fetch

  • remotefix를 fetch한 경우 - fetch는 리모트 트래킹 브랜치 origin/remotefix를 내려받는다. 그러나 로컬에서 remotefix브랜치가 생기는 것이 아니다.
➜  git fetch origin
* [new branch]      serverfix    -> origin/remotefix

git merge

# 로컬 브랜치 serverfix02에서 리모트 트래킹 브랜치 origin/remotefix를 merge함
➜ git:(serverfix02) git merge origin/remotefix

git checkout -b

  • 트래킹 브랜치 만들기
  • 또는 위와 다르게, local에 리모트 트래킹 브랜치에서 시작하는 새 브랜치(트래킹 브랜치: serverfix03 )를 만들어 수정할 수 있다.
# 트래킹브랜치 만들기 
# git chechout -b [트래킹브랜치] [리모트트래킹브랜치]
➜ git checkout -b serverfix03 origin/remotefix
  • 또는 간단하게 (그러나 브랜치이름은 변경할 수 없게),
➜  git checkout --track origin/remotefix

Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'remotefix'
  • 만약 이미 로컬에 remotefix라는 브랜치가 있어서 이것이 리모트트래킹브랜치를 자동으로 추적하게 하려면,
➜  git branch -u origin/remotefix

Branch remotefix set up to track remote branch remotefix from origin.

fetch 시점, 트래킹 브랜치 목록 보기

➜ git branch -vv
iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
master    1ae2a45 [origin/master] deploying index fix
* remotefix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
testing   5ea463a trying something new
  • 갱신하여 트래킹 브랜치 목록을 보려면 $ git fetch --all; git branch -vv

git pull

  • 일반적으로 fetchmerge 명령을 명시적으로 사용하는 것이 pull 명령으로 한번에 두 작업을 하는 것보다 낫다.

리모트 브랜치 삭제

# git push <remote> --delete <리모트브랜치>
➜ git push origin --delete remotefix

To https://github.com/schacon/simplegit
 - [deleted]         remotefix

8) Rebase

master 브랜치에서 dev브랜치가 나오고, 다시 dev 브랜치에서 dev-iss01브랜치가 나왔는데, dev브랜치를 놔두고 dev-iss01브랜치를 master브랜치에 합치고 싶을 때,

❶ Rebase의 위험성

이미 공개 저장소에 Push한 커밋을 Rebase하지 말것 - Push 하기 전에 정리하려고 Rebase 하는 것은 괜찮다. 또 절대 공개하지 않고 혼자 Rebase 하는 경우도 괜찮다. 하지만, 이미 공개하여 사람들이 사용하는 커밋을 Rebase 하면 틀림없이 문제가 생긴다.

➁ Rebase vs Merge

  • 일반적인 해답을 굳이 드리자면 로컬 브랜치에서 작업할 때는 히스토리를 정리하기 위해서 Rebase 할 수도 있지만, 리모트 등 어딘가에 Push로 내보낸 커밋에 대해서는 절대 Rebase 하지 말아야 한다.

5. Git 서버

다른 사람과 협업하려면 리모트 저장소가 필요하다. 동료가 저장소를 사용할 수 있게 하려면 언제나 이용할 수 있는 공동 저장소를 만들고 이 저장소에 접근하여 Push, Pull 할 수 있어야 한다.

Git 서버를 운영하는 건 매우 간단하다. 우선 사용할 전송 프로토콜부터 정한다. 그다음엔 각 프로토콜을 사용하는 방법과 그 프로토콜을 사용할 수 있도록 서버를 구성하는 방법을 살펴본다. 마지막으로 다른 사람의 서버에 내 코드를 맡기긴 싫고 고생스럽게 서버를 설치하고 관리하고 싶지도 않을 때 고를 수 있는 선택지가 어떤 것들이 있는지 살펴본다.

서버를 직접 설치해서 운영할 생각이 없으면 이 장의 마지막 절에서 Git 호스팅 서비스에 계정을 만들고 사용하는 방법에 대해 설명한다.

리모트 저장소는 일반적으로 워킹 디렉토리가 없는 Bare 저장소 이다. 이 저장소는 협업용이기 때문에 체크아웃이 필요 없다.

1) 프로토콜

  • 참조 프로토콜

  • 로컬 프로토콜 - 리모트 저장소가 단순히 디스크의 다른 디렉토리에 있을 때 사용한다. 파일 기반 저장소의 장점은 간단하지만 모든 저장소가 한 시스템에 있기 때문에 한순간에 모두 잃을 수 있다. 리모트 저장소가 있는 디스크를 마운트해야 하는데 이것은 다른 프로토콜을 이용하는 방법보다 느리고 어렵다.

➜ git clone /srv/git/project.git
# 또는
➜ git clone file:///srv/git/project.git

➜ git remote add local_proj  /srv/git/project.git
  • 스마트 HTTP 프로토콜은 SSH나 Git 프로토콜처럼 통신한다. SSH는 키를 발급하고 관리해야 하는 번거로움이 있지만, HTTP는 사용자이름과 암호만으로 인증할 수 있기 때문에 더 편리하게 사용할 수 있다. 지금은 Git에서 가장 많이 사용하는 프로토콜일 것이다. HTTP는 매우 보편적인 프로토콜이기 때문에 거의 모든 회사 방화벽에서 통과하도록 돼있다는 장점도 있다.
  • **멍청한 HTTP에 대해서는 참조를 살펴본다. **
  • SSH - 대부분 서버는 SSH로 접근할 수 있도록 설정돼 있다. SSH는 인증 기능이 있고 어디에서든 사용할 수 있으며 사용하기도 쉽다. SSH 데몬은 정말 흔하다. SSH를 통해 접근하면 보안에 안전하다. 모든 데이터는 암호화되어 인증된 상태로 전송된다. 다만 SSH는 익명으로 접근할 수 없으므로, 회사에서만 사용할 거라면 SSH가 가장 적합한 프로토콜일 것이지만 오픈소스 프로젝트는 SSH만으로는 부족하다.
  • Git 프로토콜 - Git에 포함된 데몬을 사용하는 것이다. 포트는 9418이며 SSH 프로토콜과 비슷한 서비스를 제공하지만, 인증 메커니즘이 없다. 전송량이 많은 공개 프로젝트나 별도의 인증이 필요 없고 읽기만 허용하는 프로젝트를 서비스할 때 유용하다.

2) 서버에 Git 설치하기

  • 참조 서버에 Git 설치하기
  • 꼭 필요한 것은 ❶ SSH 서버와 ➁ Bare 저장소뿐이라는 점을 꼭 기억하자. - Git 저장소를 만드는 것이은 쉽다. Bare 저장소를 만들어 SSH로 접근할 수 있는 서버에 올리면 된다. 만약 창업을 준비하고 있거나 회사에서 Git을 막 도입하려고 할 때는 개발자의 수가 많지 않아서 설정할 게 별로 없다.
  • SSH 접속 - ❶ 첫째로 모두에게 계정을 만들어 주는 방법이 있다. 이 방법이 제일 단순하지만 다소 귀찮다. 팀원마다 adduser를 실행시키고 임시 암호를 부여해야 하기 때문에 보통 이 방법을 쓰고 싶어 하지 않는다. ➁ 둘째로 서버마다 git’이라는 계정을 하나씩 만드는 방법이 있다. 쓰기 권한이 필요한 사용자의 SSH 공개키를 모두 모아서 'git 계정의 ~/.ssh/authorized_keys 파일에 모든 키를 입력한다.
# Bare 저장소 만들기 
## cp -Rf my_project/.git my_project.git
➜ git clone --bare my_project my_project.git
Cloning into bare repository 'my_project.git'...
done.

# 서버에 위 Bare 저장소 넣기
## 서버 git.example.com
## SSH 프로토콜 
## Git 저장소의 위치  /srv/git
➜ scp -r my_project.git user@git.example.com:/srv/git

# 위 서버에 접근하기 : /srv/git에 읽기 권한이 있는 사용자
➜ ssh user@git.example.com
➜ git clone user@git.example:/srv/git/my_project.git

# 위 서버의 /srv/git/my_project.git에 쓰기 권한 추가하기
➜ ssh user@git.example.com
➜ cd /srv/git/my_project.git
➜ git init --bare --shared

3) SSH 공개키 만들기

cd ~/.ssh
➜ ls
authorized_keys2  id_rsa  known_hosts  config  id_rsa.pub
  • 공개키 만들기 (공개키가 없다면)
➜  ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
Created directory '/home/schacon/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/schacon/.ssh/id_rsa.
Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
  • 자신의 공개키를 Git 서버 관리자에게 보내기 - 사용자는 .pub 파일의 내용을 복사하여 이메일을 보내면 된다.

4) 서버 설정하기

sudo adduser git
➜ su git
➜ cd ~
➜ mkdir .ssh && chmod 700 .ssh
## .ssh/ 소유자만 읽기 쓰기 실행 가능 
➜ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_key
## .ssh/authorized_key 소유자만 읽기 쓰기 가능
  • authorized_keys 파일에 SSH 공개키를 추가
cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys
➜ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys
➜ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys
  • bare 저장소 만들기
cd /srv/git
➜  mkdir project.git
➜  cd project.git
➜  git init --bare
Initialized empty Git repository in /srv/git/project.git/
  • 사용자는 위 저장소를 리모트 저장소로 등록하기
# 사용자 컴퓨터에서 cd myproject
➜  git init
➜  git add
➜  git commit -m "1st commit"
➜  git remote add origin git@gitserver:/srv/git/project.git
  • 이제 사용자는 이 프로젝트를 Clone 하고 나서 수정하고 Push 할 수 있다.
➜  git clone git@gitserver:/srv/git/project.git
➜  cd project
➜  vi README.md
➜  git commit -am 'README 고치기'
➜  git push origin master

5) Git 데몬, 스마트 HTTP, GitWeb, GitLab

6) GitHosting


6. 분산 환경에서의 Git

  • 분산 환경에서 Git이 제공하는 기능을 어떻게 효율적으로 사용할까? 프로젝트 기여자 또는 관리자로서 작업물을 프로젝트에 어떻게 포함시킬지와 수 많은 개발자가 수행한 일을 취합하고 프로젝트를 운영하는 방법을 배운다.
  • 기여자의 입장
  • 관리자의 입장

분산환경 워크플로

  • 분산환경에서의 워크플로

  • Git은 분산형이다. Git은 구조가 매우 유연하기 때문에 여러 개발자가 함께 작업하는 방식을 더 다양하게 구성할 수 있다.
  • 중앙집중식 - 중앙 저장소는 딱 하나 있고 변경 사항은 모두 이 중앙 저장소에 집중된다. JohnJessica가 동시에 같은 부분을 수정하는 상황을 생각해보자. John이 먼저 작업을 끝내고 수정한 내용을 서버로 Push 한다. Jessica도 마찬가지로 작업을 끝내고 수정한 내용을 서버로 Push 하려 하지만 서버가 바로 받아주지 않는다. 서버에는 John이 수정한 내용이 추가되었기 때문에 Push 하기 전에 Fetch로 받아서 Merge 한 후 Push 할 수 있다.

중앙집중식 워크플로

  • Integration-Manager 워크플로
  • Dictator and Lieutenants 워크플로

프로젝트에 기여하기

프로젝트 관리하기

토픽 브랜치에서 일하기

메인 브랜치에 통합하기 전에 임시로 토픽 브랜치를 하나 만들고 거기에 통합해 보고 나서 다시 메인 브랜치에 통합하는 것이 좋다.

# main branch : dev, origin/dev
# dev-iss01 토픽 브랜치에서 메인 dev 브랜치로 이동
➜ git:(dev-iss01) git checkout dev
# 메인 dev에서 임시 dev-temp 만들어서 이동 
➜ git:(dev)  git checkout -b dev-temp
# 이하 위 내용대로  dev-iss01을 dev-temp에 merge 
➜ git:(dev-temp) git merge dev-iss01
➜ git:(dev-temp) git branch -d dev-iss01
➜ git:(dev-temp) git checkout dev
➜ git:(dev) git merge dev-temp
➜ git:(dev) git branch -d dev-temp

이메일로 받은 Patch를 적용하기

​ 우선 토픽 브랜치에 Patch를 적용한다.

git apply --check email_patch.patch

git am email_patch.patch

리모트 브랜치로부터 통합하기

무슨 내용인지 확인하기

기여물 통합하기

​ Merge하는 워크플로

​ 바로 master 브랜치에 Merge 하는 것이 가장 간단하다.

​ 개발자가 많고 규모가 큰 프로젝트에서는 최소한 두 단계로 Merge 하는 것이 좋다.

​ master(안정/배포브랜치) + dev(개발메인브랜치) + issue01(토픽브랜치)

토픽브랜치개발메인브랜치에 merge하고,

개발메인브랜치가 안정되어 배포할만하면,

안정/배포브랜치개발메인브랜치로 Fast-forward시킨다

​ 대규모 Merge 워크플로

​ Rebase와 Cherry-Pick 워크플로

​ Rerere (Reuse Record Resolution)

​ 릴리즈 버전에 태그 달기

​ 빌드넘버 만들기

​ 릴리즈 준비하기

​ 빌드넘버 만들기


7. GitHub

  • GitHub은 가장 큰 Git 저장소 호스트이다. GitHub을 잘 쓰는 방법을 알아보도록 하자.

계정 만들고 설정하기

GitHub 프로젝트에 기여하기

(1) 프로젝트 Fork하기

  • Fork해야 Push할 수 있다.

(2) GitHub 플로우

1. `master`에서 `토픽 브랜치`를 만든다.
2. 뭔가 수정해서 커밋한다.
3. 자신의 GitHub 프로젝트에 `토픽 브랜치`를 Push 한다.
4. GitHub에 Pull Request를 연다. "New pull request"
5. 토론하면서 그에 따라 계속 커밋한다.
6. 프로젝트 소유자는 Pull Request를 Merge 하고 닫는다.
  • Pull Request만들기

GitHub 프로젝트 관리하기

  • 저장소 만들기 New Repository

  • 동료 추가하기 Collaborator in Settings : Push권한 부여
  • Pull Request 관리하기
  • 이메일 알림

Organization 관리하기

GitHub 스크립팅


8. Git 도구

리비전 조회하기

대화형 명령

Stashing과 Cleaning

내 작업에 서명하기

검색

히스토리 단장하기

Reset 명확히 알고 가기

고급 Merge

Rerere

Git으로 버그 찾기

서브 모듈

Bundle

Replace

Credential 저장소


9. Customization (맞춤)

Git 설정하기

Git Attributes

Git Hooks

정책 구현하기


10. Git과 여타 버전 관리 시스템

Git: 범용 Client

Git으로 옮기기


11. Git의 내부