Git 사용법

Jnary·2022년 9월 22일
0

Concept

목록 보기
1/8
post-thumbnail

시작하기

1. 버전관리

버전 관리 시스템(VCS) : 파일 변화를 시간에 따라 기록했다가 나중에 특정 시점의 버전을 다시 꺼내올 수 있는 시스템

1) 로컬 버전 관리(VCS)

간단한 데이터베이스를 사용하여 파일의 변경 정보를 관리
VCS 도구 중 RCS(Revision Control System)는 Patch set(변경되는 부분)을 관리
일련의 Patch set을 적용해서 모든 파일을 특정 시점으로 되돌릴 수 있음

2) 중앙집중식 버전 관리(CVCS)

다른 개발자와 함께 작업해야하는 경우에 발생하는 문제 해결
모든 클라이언트의 로컬 데이터베이스를 관리하는 것보다 간단
관리자가 누가 무엇을 할 지 관리하기에 용이
but, 중앙 서버에서 문제 발생 시 협업, 백업 불가

3) 분산 버전 관리 시스템(DVCS)

단순히 파일의 마지막 스냅샷(commit)을 Checkout(X)
저장소를 히스토리와 더불어 전부 복제
클라이언트 중 아무거나 골라도 서버 복원 가능
Clone : 모든 데이터를 가진 진정한 백업
리모트 저장소 존재 -> 다양한 워크플로 사용 가능

Checkout : 원하는 commit 버전으로 돌아감

2. Git 기초

1) 시차가 아니라 스냅샷

VCS
: 각 파일들의 변화를 시간순으로 관리하면서 파일들의 집합을 관리
Git
: 데이터를 파일 시스템 스냅샷(commit)의 연속으로 취급
파일 변화X -> 새로 저장X (이전 상태의 파일에 대한 링크만 저장)
데이터 = 스냅샷의 스트림

2) Git의 무결성

체크섬 : 가장 기본적인(Atomic) 데이터 단위이자 Git의 기본 철학
데이터를저장하기 전 항상 체크섬을 구하고 체크섬으로 데이터를 관리
체크섬을 이해하는 Git없이 파일, 디렉터리 변경 불가
SHA-1해시를 사용 (40자 길이의 16진수 문자열)
파일 이름이 아닌 해시로 저장 (Git은 해시로 식별)

3) 세 가지 상태

  • Committed
    : 데이터가 로컬 데이터베이스에 안전하게 저장된 상태
  • Modified
    : 수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않은 상태
  • Staged
    : 현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태

세 가지 상태는 세 가지 단계와 연결
-> 세 가지 단계

  • Working Directory (로컬)
    : 프로젝트의 특정 버전을 Checkout한 것
  • Staging Area (애드)
    : Git디렉토리에 존재.
    단순한 디렉토리. 곧 커밋할 파일에 대한 정보 저장
  • .git directory (커밋)
    : Git이 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳
    다른 컴퓨터에 있는 저장소를 Clone할 때 생성

Git으로 하는 일
1) 워킹 트리에서 파일 수정
2) Staging Area에 파일을 Stage해서 커밋할 스냅샷 생성
3) Staging Area에 있는 파일들을 커밋해서 Git 디렉토리에 영구적인 스냅샷 저장

3. CLI

CLI, GUI를 통해 Git 사용
GUI와 달리 CLI만이 Git의 모든 기능을 지원

4. Git 설치

분산 버전 관리 시스템
프로그램 소스들에 대해 수정 별로 변경사항을 관리하여 추적 가능하게 함

:~$ sudo apt install git

-> 리눅스에서 설치
데비안 계열 배포판에서는 'apt'대신 'dnf'

오픈소스란 ?
오픈소스 소프트웨어
: 소스코드를 아무런 제약없이 확인, 수정, 배포 가능
GNU 프로젝트
: 자유롭게 사용할 수 있는 운영체제와 시스템 프로그램을 제작
Free 소프트 웨어가 되기 위한 조건
1) 프로그램은 누구나 어떤 목적으로든 실행 가능해야 한다.
2) 당신의 요구에 맞게 프로그램은 수정 가능해야 한다. -> 이를 위해 소스코드에 대한 접근이 가능해야 한다.
3) 다른 사람들을 위해 재배포 가능해야 한다.

5. Git 최초 설정

'git config'라는 도구 사용
사용하는 설정 파일 세 가지

  • /etc/gitconfig 파일
    : 시스템의 모든 사용자와 모든 저장소에 적용되는 설정 -> 관리자 권한 필요
    git config --system
  • ~/.gitconfig, ~/.config/git/config 파일
    : 특정 사용자(현재 사용자)의 모든 저장소에 적용되는 성질
    git config --global
  • .git/config 파일
    : 이 파일은 Git디렉토리에 존재. 특정 저장소(현재 작업 중인 프로젝트)에만 적용
    git config --local
    -> 역순으로 우선시

1) 사용자 정보

사용자이름, 이메일주소 설정이 Git의 첫 시작
Git은 커밋할 때마다 이 정보를 사용.
한 번 커밋한 후에는 정보 변경 불가

$ git config --global user.name "Jnary"
$ git config --global user.email jnary@velog.com

플젝마다 다른 사용자 정보 사용하고 싶다면?
-> --global 옵션 제외한 후 명령 실행

2) 편집기

Git에서 사용할 텍스트 편집기 고르기
기본적으로 Git은 시스템의 기본 편집기를 사용
git config --global core.editor vim

3) 설정 확인

$ git config --list
user.name=Jnary
user.email=jnary@velog.com
core.editor=vim

특정 Key에 대해 어떤 값을 사용하는지도 확인 가능

$ git config user.name
Jnary

여러 파일에서 동일한 키에 대해 다른 값을 설정하고 있을 수 있음

7. 도움말 보기

명령어에 대한 도움말이 필요할 때 도움말을 보는 방법 두가지
$ git help <verb>
$ man git-<verb>

도움말 전체가 아닌 각 명령에서 사용할 수 있는 옵션들에 대해 간략히 살펴보는 법
$ git add -h

Git의 기초

1. Git 저장소 만들기

Git 저장소를 사용하는 두가지 방법

  • 아직 버전관리를 하지 않는 로컬 디렉토리 하나를 선택해서 Git 저장소를 적용
  • 다른 어딘가에서 Git 저장소를 Clone

1) 기존 디렉토리를 Git 저장소로 만들기

버전 관리를 하지 않는 기존 프로젝트를 Git으로 관리하고 싶은 경우

$ cd /home/user/my_project
$ git init

.git이라는 하위 디렉토리 생성
.git 디렉토리에는 저장소에 필요한 뼈대 파일(Skeleton)이 포함.
아직 프로젝트의 어떤 파일도 관리하지 않는 상태
아래 명령어로 파일 관리

$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'

2) 기존 저장소를 Clone 하기

다른 프로젝트에 참여하려거나 Git 저장소를 복사하고 싶은 경우
Subversion과 달리 서버에 있는 거의 모든 데이터를 복사

  • Clone
    $ git clone https://github.com/j-nary/repo_name
    'repo_name' 이라는 디렉토리를 만들고 그 안에 .git 디렉토리 생성
    저장소의 데이터를 ㅁ두 가져와 자동으로 가장 최신 버전을 Checkout
    'repo_name' 디렉토리로 이동하면 Checkout으로 생성한 파일 확인 가능
    $ git clone https://github.com/j-nary/repo_name my_dir
    'repo_name'이 아닌 다른 디렉토리 이름으로도 Clone 가능
    -> Working directory에 Checkout됨.
    $ git clone https://github.com/j-nary/repo_name -o jin
    -> -o 옵션으로 저장소 이름 변경
  • 복제 확인
    $ cd my_dir
    $ cat README.md

2. 수정하고 저장소에 저장하기

파일을 수정하다가 저장하고 싶으면 스냅샷을 커밋
Working directory의 모든 파일은 Untracked/Tracked 분류

  • Untracked
    : 관리 대상이 아님
    Working directory에 있는 파일 중 스냅샷에도 Staging Area에도 포함되지 않은 파일
  • Tracked
    : 관리 대상임
    ⅰ) Unmodified (수정하지 않음) : 처음 저장소 Clone 시의 상태
    ⅱ) Modified (수정함) : 마지막 커밋 후 어떤 파일을 수정한 후의 상태
    ⅲ) Staged (커밋으로 저장소에 기록함) : Git이 알고 있는 파일, 실제로 커밋한 상태

1) 파일의 상태 확인하기

$ git status
On branch master	//현재 작업 중인 브랜치
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

-> Clone 한 후에 바로 status 명령 실행하면 나오는 메세지
파일을 하나도 수정하지 않았음.
서버의 같은 브랜치로부터 진행된 작업이 없음

$ cat > newfile
test
$ git status
On branch master
Your branch is up to date wit 'origin/master'.

Untracked files:
	(use "git add <file>..." to include in what will be committed)
    	newfile
    //untracked 파일 : Working directory에 존재. but, 커밋(스냅샷)에 포함 X
    //커밋을 수행하더라도 로컬 데이터베이스에 저장 X
nothing added to commit but untracked files present (use "git add" to track)

파일이 Tracked 상태가 되기 전까지 Git은 절대 그 파일을 커밋 X

2) 파일을 새로 추적하기

$ git add README
README 파일은 Tracked 상태이면서 커밋에 추가될 Staged 상태임

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:		//Staged 상태임을 의미
	(use "git reset HEAD <file>..." to unstage)
    
    	new file: README

add 명령어를 통해 디렉토리에 있는 파일을 추적하고 관리
파일 또는 디렉토리의 경로를 argument로 받음
-> 디렉토리 아래에 있는 모든 파일 재귀적으로 추가

3) Modified 상태의 파일을 Stage 하기

CONTRIBUTING.md라는 파일을 수정한 후에 아래 명령어를 사용해보자.

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:		//Staged 상태
	(use "git reset HEAD <file>..." to unstage)
    
    	new file:	README		
     
Changed not staged for commit:		//Modified 상태
	(use "git reset HEAD <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)
    
    	modified:	CONTRIBUTING.md
        

Modified 상태 -> Staged 상태 : git add 명령 실행

git add 사용 용도
1) 파일 새로 추적
2) 수정한 파일을 Staged 상태로
3) Merge 할 때 충돌난 상태의 파일을 Resolve 상태로

$ git add CONTRIBUTING.md
$ 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)
    
    	new file:	README
        modified:	CONTRIBUTING.md

다시 수정한 후에는 ?

$ vim CONTRIBUTING.md
$ 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)
    
    	new file:	README
        modified:	CONTRIBUTING.md
        
Changed 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:	CONTRIBUTING.md

Staged 상태이면서 동시에 Unstaged인 상태.
add 명령은 파일을 바로 Staged 상태로 만듬.
git add 명령을 실행했을 떄의 버전이 커밋. 갱신되기 전.
git add 명령을 다시 실행해서 최신 버전을 Staged 상태로 만들어야 함.

4) 파일 상태를 짤막하게 확인하기

$ git status -s
 M README				//내용 변경했지만 아직 Staged 상태로 추가X -> _M 표시
MM Rakefile				//변경으로 인해 Staged이면서 Unstaged 상태인 파일 앞 MM
A  lib/git.rb			//Staged상태로 추가한 파일 중 새로 생성한 파일 앞 A_ 표시
M  lib/simplegit.rb		//내용 변경 한 후 Staged 상태로 추가한 파일 앞 M_ 표시
?? LICENSE.txt			//추척하지 않은 새 파일 앞에 ?? 표시

왼쪽에는 Staging Area에서의 상태를, 오른쪽에는 Working Directory에서의 상태를.

5) 파일 무시하기

로그 파일이나 빌드 시스템이 자동으로 생성한 파일은 Git이 관리할 필요X

$ cat .gitignore
*.[oa]		//확장자가 '.o', '.a'인 모든 파일 무시
*~			//~로 끝나는 모든 파일 무시

.gitignore 파일은 처음에 만들어 두는 것이 편리

.gitignore 파일에 입력하는 패턴
1) 아무것도 없는 라인이나 '#'로 시작하는 라인은 무시
2) 표준 Glob 패턴 사용 ->프로젝트 전체에 적용
3) '/'로 시작하면 하위 디렉토리에 적용(Recursivity) X
4) 디렉토리는 '/'를 끝에 사용하는 것으로 표현
5) '!'로 시작하는 패턴의 파일은 무시 X

.gitignore 파일의 예시

# 확장자가 .a인 파일 무시
*.a

# 윗 라인에서 예외로 lib.a는 무시 X
!lib.a

# TODO 파일은 무시, subdir/TODO 같이 하위디렉토리에 있는 파일은 무시X
/TODO

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

# doc/notes.txt 파일 무시, doc/server/arch.txt 파일은 무시X
doc/*.txt

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

하나의 .gitignore 파일을 최상위 디렉토리에 두고 모든 하위 디렉토리에까지 적용시키는 방식이 간단.
.gitignore 파일은 하위 디렉토리에도 추가로 둘 수 있음.
.gitignore 파일이 위치한 디렉토리와 그 하위 디렉토리에 적용

6) Staged와 Unstaged 상태의 변경 내용을 보기

단순히 파일이 변경됐다는 사실 확인 -> git status
어떤 내용이 변경됐는지 자세한 확인 -> git diff

$ git staus
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
	(use "git reset HEAD <file>..." to unstage)
    	
        modified:	README
        
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:	CONTRIBUTING.md

git diff : 수정했지만 아직 Staged 상태가 아닌 파일을 비교 가능

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUGIND.md
+++ b/CONTRIBUGIND.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your
PR;
 if we have to read the whole diff to figue out why you're contributing
 in the first place, you're less likely to get feedback and have your
change
 -merged in.
 +merged in. Alse, split your changes into comprehensive chunks if your
patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a
PR
 that highlights your work in progress (and note in the PR title that it's

Working directory에 있는 것(Unstaged)과 Staging Area에 있는 것을 비교.
커밋을 수행한 경우, 마지막 커밋한 것돠 Working directory에 있는 것을 비교
수정한 파일을 모두 Staging area에 넣은 경우, 출력 내용X

$ git diff --staged, $ git diff --cached
-> Staged 상태인 파일 확인
커밋하기 위해 Staging Area에 넣은 파일의 변경 부분을 보고 싶을 때 사용
저장소에 커밋한 것과 Staging Area에 있는 것을 비교

7) 변경사항 커밋하기

Staging Area에 있는 파일들 커밋.
생성 및 수정 후 git add 명령으로 추가하지 않은 파일은 커밋 X
$ git commit
스냅샷을 로컬 데이터베이스에 저장

아래는 Vim 편집기의 화면

// 첫 번째 행은 간략한 커밋 메시지

// 세 번째 행부터 상세한 커밋 메시지
# Please enter the commit message for your changes. Lines stating
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:	COMTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

커밋 메시지 아래에 git status 명령의 결과가 채워짐.
$ git commit -v : 편집기에 diff메시지도 추가됨.

$ git commit -m "Jnary's Git Study"
[master 463dc4f] Jnary's Git Study
 2 files changed, 2 insertions(+)
 create mode 100644 README

-> 메시지를 인라인으로 첨부
master 브랜치에 커밋 / 체크섬은 463dc4f / 수정한 파일, 삭제추가된 라인의 개수
커밋할 때마다 프로젝트의 스냅샷을 기록 -> 나중에 스냅샷끼리 비교하거나 예전 스냅샷으로 되돌릴 수 있음

8) Staging Area 생략하기

$ git commit -a
Tracked 상태의 파일을 자동으로 Staging Area에 넣음.
git add 명령 실행 효과 (모든 파일이 자동으로 추가)

9) 파일 삭제하기

$ rm PROJECTS.md			//단순히 Working directory에서 파일 삭제
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:		//Unstaged 상태
	(use "git add/rm <file>..." to update what will be committed)
    (use "git checkout -- <file>..." to discard changes in working directory)
    
    	deleted:	PROJECTS.md
      
no changes added to commit (use "git add" and/or "git commit -a")

git rm 명령은 삭제한 파일이 Staged 상태가 되게 한다.

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ 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)
    
    deleted:	PROJECTS.md

커밋하면 파일은 삭제 -> Git 추적 X

git rm -f PROJECTS.md
이미 파일을 수정했거나 Staging Area에 추가했다면, -f 옵션으로 강제 삭제 필요
커밋하지 않고 수정한 데이터는 Git으로 복구할 수 없기에
실수로 데이터를 삭제하지 못하도록 하는 안전장치

git rm --cached README
Staging Area에서만 제거 (Git 추적 X)
Working directory에 있는 파일은 남겨둠.
.gitignore 파일에 추가하는 것을 까먹거나 대용량 로그 파일이나 컴파일된 파일인 .a 파일을 실수로 추가했을 때 사용

10) 파일 이름 변경하기

Git은 파일 이름의 변경이나 파일의 이동을 명시적으로 관리X

$ git mv README.md README
$ 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:	README.md -> README

이름을 바꾼 후 해당 파일을 add 한 효과 (아래 명령어 수행한 것과 동일)

$ mv README.md README
$ git rm README.md
$ git add README

3. 커밋 히스토리 조회하기

$ 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						//커밋 메시지
    
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700

  	removed unnecessary test
    
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700

  	first commit

저장소의 커밋 히스토리를 시간순으로 표시 (가장 최근의 커밋 먼저)

git log 주요 옵션
$ git log -p, $ git log -patch : 각 커밋의 diff 결과 출력
$ git log -숫자 : 최근 숫자 개의 결과만 출력
$ git log --stat : 각 커밋의 히스토리 통계 정보 출력 (어떤 파일이 수정됐는지, 얼마나 많은 파일이 변경됐는지, 얼마나 많은 라인을 추가삭제했는지 +요약정보)
$ git log --pretty=oneline : 각 커밋을 한 라인으로 요약해서 출력
$ git log --graph : 브랜치와 머지 히스토리 출력
$ git log --shortstat : --stat 명령의 결과 중 수정한 파일, 추가된 라인, 삭제된 라인만 출력
$ git log --name-only : 커밋 정보 중에서 수정된 파일의 목록만 출력
$ git log --name-status : 수정된 파일의 목록 출력 + 파일을 추가한 것인지, 수정한 것인지, 삭제한 것인지 표시
$ git log --abbrev-commit : 40자 짜리 SHA-1 체크섬 처음 몇자만 표시
$ git log --relative-date : '2 days ago'처럼 상대적인 시간 출력

git log 조회 범위 옵션
ex. git log --since=2.weeks : 지난 2주동안 생성된 커밋 조회
$ git log -숫자 : 최근숫자 개의 커밋만 조회
$ git log --since, $ git log --after : 명시한 날찌 이후의 커밋만
$ git log --until, $ git log --before : 명시한 날찌 이전의 커밋만
$ git log --author :입력한 저자의 커밋만
$ git log --committer : 입력한 커미터의 커밋만
$ git log --grep : 커밋 메시지 안의 텍스트를 검색
$ git log -S : 커밋 변경(추가/삭제) 내용 안의 텍스트를 검색

4. 되돌리기

한 번 되돌리면 복구할 수 없기에 주의
$ git commit -amend : 커밋 재작성
-> 다시 커밋하고 싶을 경우, 파일 수정 작업 후 add한 다음 위 명령어 사용
커밋 메시지 자동으로 포함

// 커밋을 했는데 stage 하는 것을 잊은 경우
$ git commit -m "initial commit"
$ git add forgotten_file
$ git commit -amend			//첫 번째 커밋을 덮어씀

1) 파일 상태를 Unstage로 변경하기

파일을 커밋하려고 add한 후 다시 하나의 파일을 제외시키고 싶은 경우

$ 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 <file> 이용

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
  
  	renamed: README.md -> README
    
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: CONTRIBUTING.md		//다시 Unstaged 상태가 됨.

git reset 명령은 매우 위험. --hard 옵션 없이 사용할 경우, Working directory 파일은 건드리지 X

2) Modified 파일 되돌리기

파일을 수정한 후 최근 커밋된 버전으로 되돌리기
git checkout -- (파일명)

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
  (use "git checkout -- <file>..." to discard changes in working directory)
  
  		modified: CONTRIBUTING.md		//파일이 수정된 상태

$ git checkout -- CONTRIBUTING.md	//최근 커밋된 버전으로 되돌림
$ git status 
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

Git으로 커밋한 모든 것은 언제나 복구 가능
커밋하지 않고 잃어버린 것은 되돌릴 수 X

5. 리모트 저장소

리모트 저장소 관리 : 저장소 추가 및 삭제 + 브랜치 관리 + 추적여부 관리
다른 사람들과 함께 작업하기 위해 리모트 저장소를 관리

1) 리모트 저장소 확인하기

$ git clone http://github.com/j-nary/gitstudy
$ git remote
origin

저장소를 clone하면 origin이라는 리모트 저장소로 자동 등록

$ git remote -v
origin https://github.com/j-nary/gitstudy (fetch)
origin https://github.com/j-nary/gitstudy (push)

-v 옵션을 주어 단축이름과 URL을 함께 볼 수 있다.
여러개 있다면 등록된 전부를 보여줌.

2) 리모트 저장소 추가하기

git remote add <단축이름> <\url>

$ git remote add pb https://github.com/j-nary/gitstudy
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)

URL 대신에 pb 라는 단축이름 사용 가능

3) 리모트 저장소를 Pull 하거나 Fetch 하기

Fetch 하여 리모트 저장소 데이터를 가져옴

$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
 * [new branch] master -> pb/master
 * [new branch] ticgit -> pb/ticgit

로컬에서 pb/master 가 master 브랜치
이 브랜치를 로컬 브랜치 중 하나에 Merge 하거나 Checkout해서 브랜치 내용을 자세히 확인할 수 있다.
Fetch 후 Checkout으로 전환해서 다른 리모트 저장소에 접근
로컬에는 없지만 리모트 저장소에 있는 데이터를 모두 가져옴.

리모트 저장소 fetch & pull

  • fetch : 데이터를 모두 가져오지만, 자동으로 Merge 하지는 X
  • pull : git clone 명령은 자동으로 로컬의 master브랜치가 리모트 저장소의 master 브랜치를 추적하도록 함.
    clone 한 서버에서 데이터를 가져오고 그 데이터를 자동으로 현재 작업하는 코드와 Merge 시킴.

4) 리모트 저장소에 Push 하기

프로젝트 공유하고 싶을 때 Upstream 저장소에 Push 할 수 있다.
$ git push origin master
git push <리모트 저장소 이름> <브랜치 이름>
master 브랜치를 origin 서버에 Push

Clone한 리모트 저장소에 쓰기 권한이 있고 Clone하고 난 이후 아무도 Upstream 저장소에 Push 하지 않았을 때만 사용 가능
리모트 서버에 수정이 있는 경우 다시 데이터를 가져와서 Merge하고 Push해야 함.

5) 리모트 저장소 살펴보기

git remote show <리모트 저장소 이름>
리모트 저장소의 구체적인 정보 확인 가능

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/j-nary/gitstudy
  Push URL: https://github.com/j-nary/gitstudy
  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)

리모트 저장소의 URL과 추적하는 브랜치 출력
git pull 명령을 실행할 때 master 브랜치와 Merge할 브랜치가 무엇인지 표시

6) 리모트 저장소 이름을 바꾸거나 리모트 저장소를 삭제하기

$ git remote rename pb paul
$ git remote
orgin
paul

로컬에서 관리하던 리모트 저장소의 브랜치 이름도 바뀐다.
pb/master -> paul/master

$ git remote remove paul
$ git remote
origin

리모트 저장소 삭제 -> 해당 리모트 저장소에 관련된 추적 브랜치 정보나 모든 설정 내용도 함께 삭제

6. 태그

태그 조회, 생성, 종류

1) 태그 조회하기

커밋에 태그를 다는 기능
하나의 커밋에 여러 태그는 가능 O
여러 커밋에 같은 태그는 X

$ git tag
v0.1
v1.3

알파벳 순서로 태그 보여줌.
검색 패턴 사용하여 태그 검색
500여개의 태그 존재
v18.5 버전의 태그들만 검색할 경우

$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5

2) 태그 붙이기

Lightweight 태그와 Annotated 태그

  • Lightweight 태그
    브랜치와 비슷한데 브랜치처럼 가리키는 지점을 최신 커밋으로 이동시키지 X
    단순히 특정 커밋에 대한 포인터일 뿐
  • Annotated 태그
    Git 데이터베이스에 태그를 만든 사람의 이름, 이메일과 태그를 만든 날짜, 태그 메시지도 저장
    일반적으로 Annotated 태그 만들어 이 모든 정보를 사용할 수 있도록 하는 것이 좋음
    but, 임시적으로 생성하는 태그거나 이러한 정보를 유지할 필요가 없는 경우에는 Lightweight 태그 사용 가능.

3) Annotated 태그

$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4

-a 옵션으로 태그 작성자, 이메일, 태그 날짜 저장
-m 옵션으로 태그를 저장할 때 메시지도 함께 저장 가능
메시지 입력X -> Git은 편집기 실행

git show 명령으로 태그 정보과 커밋 정보 모두 확인 가능

$ 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

4) Lightweight 태그

기본적으로 파일에 커밋 체크섬을 저장하는 것 뿐 다른 정보는 저장 X
-a, -s, -m 옵션 사용X 이름만 달아줄 뿐

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5

단순히 커밋 정보만 표시

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
  changed the version number

5) 나중에 태그하기

예전 커밋에 대해서도 태그.

$ 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
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme

"updated rakefile" 커밋에 v1.2 태그 후에 붙이기
$ git tag -a v1.2 9fceb02 //체크섬 일부만 입력해도 된다.

6) 태그 공유하기

git push 명령은 자동으로 리모트 서버에 태그 전송X
git push origin <태그 이름> 필요

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag] 		v1.5 -> v1.5

한 번에 태그를 여러개 Push 하고 싶다면 --tags 옵션 추가
리모트 서버에 없는 태그 모두 전송 가능

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag] 		v1.4 -> v1.4
 * [new tag] 		v1.4-lw -> v1.4-lw

누군가 저장소에 Clone 하더가 Pull 하면 모든 태그 정보도 함께 전송됨

7) 태그 Checkout 하기

$ git checkout 2.0.0
Note: checking out '2.0.0'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
  git checkout -b <new-branch>
HEAD is now at 99ada87... Merge pull request #89 from schacon/appendixfinal
$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from
schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image

태그가 특정 버전을 가리키고 있고, 특정 버전의 파일을 체크아웃해서 확인하고 싶을 때.
단, 태그를 체크아웃하면 detached HEAD 상태가 되며 일부 Git 관련 작업이 브랜치에서 작업하는 것과 다르게 동작할 수 있다.

detached HEAD 상태
작업을 하고 커밋을 만들면, 태그는 그대로 있으나 새로운 커밋이 하나 쌓인 상태가 됨.
새 커밋에 도달할 수 있는 방법이 따로 X
커밋의 해시 값을 정확히 기억하고 있으면 가능
특정 태그의 상태에서 새로 작성한 커밋이 버그 픽스와 같이 의미있도록 하려면 반드시 브랜치를 만들어서 작업하는 것이 좋음

7. Git Alias

Git 명령을 전부 입력하는 것이 귀찮을 때

$ 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 commit 대신 git ci 만으로도 커밋 가능
$ git config --global alias.unstage 'reset HEAD --' 이런 느낌

Git 브랜치

코드를 여러개로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발을 진행하는 것
Git의 최고의 장점
다른 개발자들과 분리된 개발을 진행
이후 브랜치를 병합하여 전체를 통합

1. 브랜치 ?

  1. Git은 데이터를 Change Set이나 변경사항(Diff)으로 기록하지 않고 스냡샷으로 기록한다.
  2. 커밋하면, 현 Staging Area에 있는 데이터의 스냅샷에 대한 포인터, 저자나 커밋메시지 같은 메타데이터, 이전 커밋에 대한 포인터 등을 포함하는 커밋 매체를 저장
    이전 커밋 포인터가 있어서 현재 커밋이 무엇을 기준으로 바뀌었는지 알 수 있음.
  3. 파일을 Stage 하면, Git 저장소에서 파일을 저장하고(Git은 이것을 Blob이라 부름) Staging Area에 해당 파일의 체크섬을 저장
  4. Commit하면, 루트 디렉토리와 각 하위 디렉토리의 트리 객체를 체크섬과 함께 저장 후 커밋 개체를 만들고 메타데이터와 루트 디렉토리 트리 개체를 가리키는 포인터 정보를 커밋 개체에 넣어 저장
    따라서 언제든지 스냅샷을 다시 생성 가능
  5. Git 저장소에는 다섯 개의 데이터 개체가 생성 : 각 파일에 대한 Blob 3개, 파일과 디렉토리 구조가 들어있는 트리 개체 1개, 메타데이터와 루트 트리를 가리키는 포인터가 담긴 커밋 개체 1개

    다시 파일을 수정하고 커밋하면 이전 커밋이 무엇인지도 저장
    브랜치 : 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것

    브랜치 관리 시 주의사항
    1) 브랜치 기간이 길면 master간의 차이가 심해 병합과정에서 충돌 발생 가능성 Up!
    2) 기능별/이슈별로 잘 나누어 최소화할 것 -> 완료하면 즉시 병합하는 것이 좋음

1) master 브랜치

기본적으로 git init 명령으로 초기화할 때 자동으로 만들어지는 브랜치
처음 커밋할 시 master 브랜치가 생성된 커밋을 갈킴
이후 커밋을 만들면 master 브랜치는 자동으로 가장 마지막 커밋을 가리킴

HEAD 포인터 : 현재 작업중인 로컬 브랜치를 가리킴

2) 새 브랜치 생성하기

$ git branch testing
새로 만든 브랜치도 지금 작업하고 있던 마지막 커밋을 가리킴

--decorate 사용 시, 쉽게 브랜치가 어떤 커밋을 가리키는 지 확인 가능
--online 사용 시, 한 행으로 표시

$ git log --oneline --decorate
f30ab (HEAD -> master, testing) add feature #32 - ability to add new
formats to the central interface
34ac2 Fixed bug #1328 - stack overflow under certain conditions
98ca9 The initial commit of my project

3) 브랜치 이동하기

$ git checkout testing
HEAD는 testing 브랜치를 가리킴

새로 커밋해보자.

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

새로 커밋할 경우 testing 브랜치만 이동

브랜치를 이동하면 Working Directory의 파일이 변경된다.
다시 이동하면, Working Directory의 파일은 그 브랜치에서 가장 마지막으로 했던 작업 내용으로 변경된다.
파일 변경시 문제가 있을 경우, Git은 브랜치 이동명령 수행 X

4) 히스토리 출력

$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project

2. 브랜치와 Merge 의 기초

브랜치와 Merge 진행 방식
1. master 브랜치에서 작업 중인 웹사이트가 존재
2. 새로운 이슈가 발생하여 이를 처리할 새 브랜치를 생성
3. 새로 만든 브랜치에서 이슈 작업 진행
Hotfix 먼저 만들어야 하는 상황 발생
4. 새로운 이슈를 처리하기 이전의 마스터 브랜치로 이동
5. Hotfix 브랜치를 새로 하나 생성
6. 수정한 Hotfix 테스트를 마치고 마스터 브랜치로 머지
7. 다시 작업하던 브랜치로 옮겨가서 하던 일을 진행

1) 브랜치의 기초

브랜치를 만들면서 Checkout까지 한 번에 처리
$ git checkout -b iss53
아래 명령 줄여놓은 것

$ git branch iss53
$ git checkout iss53

2) Fast-forward Merge


운영 환경에 적응하려면 문제를 제대로 고쳤는지 테스트하고 최종적으로 운영환경에 배포하기 위해 hotfix 브랜치를 master 브랜치에 합쳐야 함.

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

Fast-forwoard 방식 : hotfix 브랜치가 가리키는 C4 커밋이 C2 커밋에 기반한 브랜치이기 때문에 브랜치 포인터는 Merge 과정 없이 그저 최신 커밋으로 이동

이제 더이상 필요없는 hotfix 브랜치는 삭제

$ git branch -d hotfix
Deleted branch hotfix (3a0874c).


위에서 작업한 hotfix는 iss53 브랜치에 영향 X

3) 3-way Merge

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html | 1 +
1 file changed, 1 insertion(+)

현재 브랜치가 가리키는 커밋이 Merge 할 브랜치의 조상이 아니므로 Git은 'Fast-forward'로 Merge 하지 X
이 경우 Git은 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용하여 3-way Merge.

포인터를 최신 커밋으로 옮기는 것이 아닌, 3-way Merge의 결과를 별도의 커밋으로 만들고 해당 브랜치가 그 커밋을 가리키도록 이동
이런 커밋은 Merge커밋이라고 부름. (부모가 여러 개)

4) 충돌의 기초

3-way Merge 실패할 경우가 존재 : Merge 하는 두 브랜치에서 같은 파일의 한 부분을 동시에 수정하고 Merge하면 Git은 해당 부분을 Merge 하지 X
아래의 충돌 메시지 출력

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

자동으로 Merge 하지 못해서 새 커밋 생성 X
변경사항의 충돌을 개발자가 해결해야함
충돌시 문제점 확인 -> git status 명령 이용

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
Unmerged paths:							//충돌이 일어난 파일 표시
  (use "git add <file>..." to mark resolution)
  both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")

편집기로 문서 수정 및 저장

<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> iss53:index.html

<<<<<<< 와 ======= 사이 : 머지할 때 작업하던 브랜치 내용
======= 와 >>>>>>> 사이 : 머지될 브랜치 내용
수정 후 <<<<<<<, =======, >>>>>>> 삭제하고 저장

<div id="footer">
please contact us at email.support@github.com
</div>

git add 명령으로 다시 저장
git commit -a -m '커밋 메시지' 명령으로 머지 완료

3. 브랜치 관리

$ git branch
  iss53
* master
  testing

'*' 기호가 붙어있는 브랜치가 현재 Checkout 해서 작업하는 브랜치

$ git branch -v
  iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
  testing 782fd34 add scott to the author list in the readmes

-v 옵션은 브랜치마다 마지막 커밋 메시지도 함께 보여줌

$ git branch --merged
  iss53
* master
$ git branch --no-merged
  testing
$ git branch -d testing			//삭제 실패
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.

머지된 브랜치, 머지되지 않은 브랜치 확인
Merge하지 않은 브랜치를 강제로 삭제하려면 -D 옵션 사용

4. 브랜치 워크플로

1) Long-Running 브랜치

Git 개발자가 많이 선호하는 워크플로
1. 배포했거나 배포할 코드만 master 브랜치에 Merge 해서 안정 버전의 코드만 master 브랜치에 둔다.
2. 개발을 진행하고 안정화하는 브랜치는 develop이나 next라는 이름으로 추가로 만들어 사용 <- 언젠가 안정상태
3. 토픽 브랜치 (짧은 호흡 브랜치) : 해당 토픽을 처리하고 테스트

코드 여러 단계로 분할 -> 안전성 UP!

2) Topic 브랜치

어떤 한 가지 주제나 작업을 위해 만든 짧은 호흡의 브랜치
다른 버전관리 시스템에서는 X (고비용)

5. 리모트 브랜치

리모트 Refs : 리모트 저장소에 있는 포인터인 레퍼런스 (리모트 저장소에 있는 브랜치, 태그, 등등)
$ git ls-remote origin' : 모든 리모트 Refs 조회 $ git remote show origin` : 모든 리모트 브랜치와 그 정보 표시

리모트 트래킹 브랜치
보통은 리모트 Refs보다 리모트 트래킹 브랜치를 사용
리모트 브랜치를 추적하는 브랜치
로컬에 있지만 움직이지 X
리모트 서버에 연결할 때마다 리모트 브랜치에 따라서 자동으로 움직임
리모트 저장소에 마지막으로 연결했던 순간에 브랜치가 무슨 커밋을 가리키고 있었는지를 나타냄
(리모트)/(브랜치) 형식 origin/master


다른 팀워이 서버에 Push 했을 경우 팀원 간의 히스토리가 달라짐.

로컬과 서버의 커밋 히스토리는 독립적.
$ git fetch origin : 리모트 서버로부터 저장소 정보를 동기화
-> 현재 로컬의 저장소가 갖고 있지 않은 새로운 정보가 있으면 모두 내려받음.
받은 데이터를 로컬 저장소에 업데이트하고 나서, origin/master 포인터의 위치를 최신 커밋으로 이동

git remote add 명령으로 현재 작업 중인 프로젝트에 팀의 저장소(teamone)를 추가

서버 추가 후 $ git fetch teamone으로 teamone 서버의 데이터 받음
명령을 실행해도 teamone 서버의 데이터는 모두 origin에도 존재 -> 내려받지 X
teamone/master가 teamone 서버의 master 브랜치가 가리키는 커밋을 가리키게 하는 효과만 존재

1) Push 하기

쓰기 권한이 있는 리모트 저장소에 가능
git push [리모트 저장소][브랜치]
$ git push origin serverfix
: serverfix 라는 로컬 브랜치를 서버로 Push 하는데 serverfix 브랜치로 업데이트한다.
'$ git push origin serverfix:awesomebranch`
: 리모트 저장소 브랜치 이름을 다르게 설정할 때 사용

fetch 후 블내치 새로 생성 X -> 수정 못하는 origin/serverfix 브랜치 포인터 생성
새로 다운 받은 내용을 Merge하기 위해 $ git merge origin/serverfix 필요

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Merge 하지않고 리모트 트래킹 브랜치에서 시작하는 새 브랜치를 생성
origin/serverfix/에서 시작하고 수정할 수 있는 serverfix라는 로컬 브랜치 생성

2) Pull 하기

  • git fetch
    : 로컬에 없는 데이터를 받아와서 저장 -> Working directory의 파일 내용은 변경 X
    사용자가 Merge 해야함.
  • git pull
    : git fetch 명령을 실행하고 나서 자동으로 git merge 명령을 수행
    clone이나 checkout 명령을 실행하여 추적 브랜치가 설정되면 git pull 명령은 서버로부터 데이터를 가져와서 현재 로컬 브랜치와 서버의 추적브랜치를 Merge

-> 일반적으로 fetch -> merge 명시적 사용이 good!

3) 리모트 브랜치 삭제

협업을 위해 리모트 브랜치 생성했다가 작업 마친 후 master 브랜치로 Merge 한 경우, 기존에 사용했던 리모트 브랜치는 더 이상 필요 X

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted] serverfix

6. Rebase 하기

한 브랜치에서 다른 브랜치로 합치는 방법 두 가지 : 1) Merge 2) Rebase

1) Rebase 의 기초


C3 에서 변경된 사항을 Patch로 만들고 이를 다시 C4에 적용시키는 방법

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command


두 브랜치가 나뉘기 전인 공통 커밋으로 이동.
그 커밋부터 지금 Checkout 한 브랜치가 가리키는 커밋까지 diff 차례로 만들어 어딘가에 임시로 저장
Rebase 할 브랜지(experiment)가 합칠 브랜치(master)가 가리키는 커밋을 가리키게 하고 아까 저장해놓았던 변경사항을 차례대로 적용

$ git checkout master
$ git merge experiment

그러고 나서 master 브랜치 Fast-forward 시키기

Merge 커밋과 결과물은 동일, 커밋 히스토리만 상이.
Merge보다 좀 더 깨끗한 히스토리 (log를 살펴보면 히스토리가 선형)
병렬로 진행해도 Rebase 하면 모든 작업이 차례대로 수행된 것처럼 보임
-> 보통 리모트 브랜치에 커밋을 깔끔하게 적용하고 싶을 때 사용

Merge : 두 브랜치의 최종결과만을 가지고 합친다.
Remase : 브랜치의 변경사항을 순서대로 다른 브랜치에 적용하면서 합친다

2) Rebase 활용

테스트가 덜 된 server 브랜치는 그대로 두고 client 브랜치만 master로 합치고자 할 경우.

$ git rebase --onto master server client
master 브랜치로부터 server 브랜치와 client 브랜치의 공통 조상까지의 커밋을 client 브랜치에서 없애고 싶을 경우 사용
client 브랜치에서만 변경된 패치를 만들어 master 브랜치에서 client 브랜치를 기반으로 새로 만들어 적용

$ git rebase master server
: git rebase 'basebranch' 'topicbranch' 라는 명령으로 Checkout 하지 않고 바로 server 브랜치를 master 브랜치로 Rebase
topicbranch 에 Checkout 하고 basebranch 에 Rebase 하는 것.

GitHub

GitHub : 가장 큰 Git 저장소 호스트

1. GitHub 프로젝트에 기여하기

1) 프로젝트 Fork 하기

참여하고 싶은 프로젝트에는 보통 push 권한이 없으므로 Fork 해야함.
Fork한 새 프로젝트

2) GitHub 플로우

GitHub은 Pull Request 가 중심인 워크플로를 위주로 설계
Fork 해서 프로젝트에 기여 <- 토픽 브랜치 중심으로 일하는 방식

  1. master에서 토픽 브랜치 생성
  2. 수정 후 커밋
  3. 자신의 GitHub 프로젝트에 브랜치를 push
  4. GitHub에 새로운 Pull Request 생성
  5. 프로젝트 소유하는 Pull Request를 Merge하고 종료

3) Pull Request

Merge 될 수 있는지 검사해서 서버에서 Merge 할 수 있도록 버튼 제공

2. GitHub 프로젝트 관리하기

1) GitHub에서 디폴트 브랜치(main) 변경하기

Settings -> Code, planning, and automation -> Repositories -> Repository default branch

2) Git 에서 디폴트 브랜치 변경하기

$ git config --global init.defaultBranch main

Git 도구

1. 리비전 조회하기

커밋 하나를 가리키거나 범위를 사용하여 여러 커밋을 가리키는 다양한 방법

1) 계통 관계로 가리키기

$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
* d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list

이름 끝에 ^를 붙이면 해당 커밋의 부모를 의미

$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
  Merge commit 'phedders/rdocs'

^^^도 가능 -> 세 번째 부모를 의미
^ 뒤에 숫자도 사용가능 -> ^2는 두 번째 부모를 의미
두 번째 부모가 있는 Merge 커밋에만 사용 가능

$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b		//Checkout 했던 브랜치
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -0800
  added some blame and merge stuff
$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548		//Merge 한 대상 브랜치
Author: Paul Hedderly <paul+git@mjr.org>
Date: Wed Dec 10 22:22:03 2008 +0000
  Some rdoc changes

첫 번째 부모는 Merge 할 때 Checkout 했던 브랜치
두 번째 부모는 Merge 한 대상 브랜치

$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
  ignore *.gem

HEAD~ == HEAD^
but, HEAD~2 는 첫 번째 부모의 첫번째 부모 (조부모)를 가리킴

2. Reset

Git은 서로 다른 세 파일의 묶음을 관리하는 콘텐츠 관리자

  • HEAD : 마지막 커밋 스냅샷
  • Index : 다음에 커밋할 스냅샷 (Staging Area)
  • Working directory : 작업하는 실제 파일, 샌드박스

1) 워크플로


이 과정을 시각화해보자.

git init 명령 실행하면 Git 저장소 생성.
HEAD는 아직 없는 브랜치를 가리킨다. (master 는 아직 없다.)
Working directory에만 데이터가 있는 상태

git add 명령으로 Working directory의 내용을 Index로 복사

git commit 명령으로 Index의 내용을 스냅샷으로 영구히 저장
그 스냅샷을 가리키는 커밋 객체 생성
master 는 그 커밋 객체를 가리킴
이때, git status 실행하면 아무런 변경 사항X <- 세 트리 모두 같아서

파일 내용을 바꾸면 Working directory의 파일이 변경됨.

Clone 명령도 비슷한 절차
브랜치 Checkout -> HEAD가 새로운 브랜치 가리킴 -> 새로운 커밋의 스냅샷을 Index에 -> Index의 내용을 Working directory에 복사

브랜치를 Checkout 할 경우
HEAD 가 새로운 브랜치를 가리킴
새로운 브랜치의 최근 커밋의 스냅샷을 Working directory로 복사

2) Reset 의 역할

  • 1단계 : HEAD 이동 (--soft)
    checkout처럼 HEAD가 가리키는 브랜치를 변경하지는 X
    HEAD는 계속 현재 브랜치를 가리키고 있고, 현재 브랜치가 가리키는 커밋을 바꿈.

    가장 최근의 git commit 명령을 되돌림
    Index를 업데이트하고 커밋하면 $ git commit --amend와 동일
  • 2단계 : Index 업데이트 (--mixed)

    reset 명령 시행시 아무 옵션도 주지 않으면 기본적으로 --mixed 옵션으로 동작
    가장 최근의 git commit, git add 명령을 되돌림
  • 3단계 : Working directory 업데이트 (--hard)

    reset 명령을 위험하게 만드는 유일한 옵션
    Git에서 데이터를 실제로 삭제할 수 있는 몇 안 되는 방법
    되돌리는 것이 불가능
    Working directory 파일까지 강제로 덮어씀
    커밋한 적이 없다면 Git이 덮어쓴 데이터는 복원 불가
    Merge 되돌리기 할 때 활용

3) 경로를 주고 Reset 하기


$ git reset --mixed HEAD file.txt 와 동일
해당 파일을 Unstaged 상태로
git add 와 반대

파일명으로 Reset : 특정 커밋을 명시하면 그 커밋에서 Index로 파일을 가져옴

3. Checkout

reset 명령과 마찬가지로 위의 세 파일 묶음을 조작
$ git checkout [branch] 는 reset --hard와 비슷하게 '[branch]' 스냅샷을 기준으로 조작
reset과 달리 Working directory를 안전하게 조작
날려버리지 않음을 보장
reset은 HEAD가 가리키는 브랜치를 업데이트 / checkout은 HEAD 자체를 다른 브랜치로

참조
https://git-scm.com/book/ko/v2

profile
숭실대학교 컴퓨터학부 21

0개의 댓글