git

Git은 원격 저장소와 로컬 저장소 두 종류의 저장소를 제공.

  • 원격 저장소(Remote Repository): 파일이 원격 저장소 전용 서버에서 관리되며 여러 사람이 함께 공유하기 위한 저장소.
  • 로컬 저장소(Local Repository): 내 PC에 파일이 저장되는 개인 전용 저장소.

평소에는 내 PC의 로컬 저장소에서 작업하다가 작업한 내용을 공개하고 싶을 때에 원격 저장소에 업로드. 물론 원격 저장소에서 다른 사람이 작업한 파일을 로컬 저장소로 가져올 수도 있다.

Git은 파일을 Committed, Modified, Staged 이렇게 세 가지 상태로 관리

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

Git 디렉토리

  • Git이 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳. 다른 컴퓨터에 있는 저장소를 Clone 할 때 Git 디렉토리가 만들어진다.

워킹 디렉토리

  • 프로젝트의 특정 버전을 Checkout한 것. Git 디렉토리는 지금 작업하는 디스크에 있고 그 디렉토리에 압축된 데이터베이스에서 파일을 가져와서 워킹 디렉토리를 만든다.

Staging Area

  • Git 디렉토리에 있다. 단순한 파일이고 곧 커밋할 파일에 대한 정보를 저장한다.

Git으로 하는 일은 기본적으로 아래와 같다:

워킹 디렉토리에서 파일을 수정한다.
Staging Area에 파일을 Stage해서 커밋할 스냅샷을 만든다.
Staging Area에 있는 파일들을 커밋해서 Git 디렉토리에 영구적인 스냅샷으로 저장한다.


사용법

console 기준으로 작성
(Windows : Git Bash)

git 설치

http://git-scm.com에서 OS에 맞는 클라이언트를 설치한다.
OSX 에서는 homebrew를 이용하면 편리하다. (http://brew.sh 참고)

버전 확인

설치가 정상적으로 진행되고 나면 git --version 명령어를 실행한다.
git version x.x.x... 와 같은 메시지가 출력되면 설치에 성공한 것이다.

사용자 정보 등록

변경 내역에 반영될 사용자 정보의 등록이 필요하다. 이 정보를 등록하지 않으면 누가 변경했는지 제대로 표시되지 않기 때문에 등록이 필요하다.

git config --global user.name "<사용자명>"
git config --global user.email "<메일 주소>"

저장소(Repository) 생성

저장소를 생성할 때는 git init 명령을 사용한다.
프로젝트 폴더를 생성하고, 해당 폴더로 이동한 다음 위 명령을 사용하면 저장소가 생성된다.

mkdir tutorial
cd tutorial
git init

저장소가 생성되면 Initialized empty Git repository in "경로..."/tutorial/.git/ 메시지를 확인 할 수 있다.

저장소 상태 확인

저장소 내의 폴더와 파일, 작업트리와 인덱스 상태 확인을 할 때 git status 명령을 사용한다.
sample.txt 파일을 생성한 뒤 git status명령을 입력하면 아래와 같은 출력을 볼 수 있다.
현재 브랜치, untracked files이 출력됨을 알 수 있다.

kimsy-iMac:tutorial kimsoyoun$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	sample.txt

nothing added to commit but untracked files present (use "git add" to track)

commit

변경 이력을 기록.
커밋할 때는 버그 수정이나 기능 추가 등 특별한 의미가 있는 업데이트를 작업 별로 구분해서 각각 커밋해야 나중에 이력을 보고 특정 변경 내용을 찾기가 편리하다.
커밋시에는 커밋 메시지를 필수로 입력해야 한다. 메시지는 명료하고 이해하기 쉽게 남겨야 이력을 확인하기 쉽다. 아래는 git에서 권장하는 메시지 형식이다.

line 1 : 커밋 내의 변경 내용을 요약
line 2 : 빈칸
line 3 : 변경한 이유

커밋 할 파일을 인덱스(index)에 등록

인덱스 대신 스테이지(stage)라고도 부른다.
커밋을 하기 전에 커밋할 대상 파일을 인덱스에 등록해야 한다.
git add 명령을 이용해서 파일을 인덱스에 등록한다.

git add <file>

파일명을 띄어쓰기 하여 여러개의 파일 을 한번에 등록할 수 있다.

git add <file1> <file2> ...

파일 명 대신 . 을 쓰면 모든 파일 을 한번에 등록할 수 있다.

git add .

파일을 등록한 후 다시 status 명령을 통해 확인 해 보면, 새로운 파일로 sample.txt가 stage 된 것을 확인 할 수 있다.

kimsy-iMac:tutorial kimsoyoun$ git add sample.txt
kimsy-iMac:tutorial kimsoyoun$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   sample.txt

커밋 명령 실행

아래 git commit 명령을 사용하여 커밋을 실행한다.

git commit -m "커밋메시지"

커밋 후 상태 확인.

kimsy-iMac:tutorial kimsoyoun$ git commit -m "first commit"
[master (root-commit) a2ec9c7] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 sample.txt
kimsy-iMac:tutorial kimsoyoun$ git status
On branch master
nothing to commit, working directory clean
kimsy-iMac:tutorial kimsoyoun$

변경 이력 확인

git log 명령을 이용해 변경 이력을 볼 수 있다.

kimsy-iMac:tutorial kimsoyoun$ git log
commit a2ec9c702dfe8bab2a6032c0b78c4e5eb6c1f6b4
Author: KimSoyoun <kimsy@selim.co.kr>
Date:   Wed Aug 17 11:22:00 2016 +0900

    first commit

원격 저장소(Remote Repository) 설정

commit을 push 하기 이전에 원격 저장소의 설정이 필요하므로, 원격 저장소를 설정하는 방법을 먼저 설명한다.

git remote add <name> <url>

보통 원격 저장소의 이름으로 origin을 많이 사용한다.
push나 pull을 할 때 원격저장소의 이름을 생락햐면, origin이라는 이름의 원격 저장소를 사용한다. 그래서 보통의 경우 origin을 붙인다.

git remote add origin https://github.com/makeajourney/tutorial.git

여기서는 github의 http 주소를 사용했다.
ssh 주소도 사용 할 수 있는데, ssh key를 사용하면 github의 id나 비밀번호를 입력하지 않아도 되서 편리하다.

ssh key 생성

원격 저장소 주소 변경

git remote set-url <REMOTE_REPO_NAME> <NEW_ADDR_FOR_REMOTE_REPO>

push

push는 로컬저장소의 변경내역(commit)을 원격 저장소에 반영하는 기능이다.
이를 위해서는 원격저장소가 필요하다.
원하는 곳의 원격 저장소를 생성하거나, 기존 원격 저장소를 이용하여 원격 저장소 설정을 한 다음 푸시를 진행한다.

아래 명령을 사용하여 푸시를 한다. 푸시 할 때는 remote repository name, remote branch를 명시한다.

git push <repository> <branch>

아래는 origin이라는 원격 저장소의 master 브랜치에 푸시한다.
-u 옵션을 추가하면, 다음에 push 할 때 해당 브랜치명을 명시하지 않아도 된다.

git push -u origin master

master? origin/master?

여기까지 작업을 성공적으로 수행하고 나면 master와 origin/master가 각각 history로 나타난다.
master는 로컬 저장소의 branch이고, origin이 앞에 붙은 것은 원격 저장소의 것이라고 생각하면 된다.

clone (원격 저장소 복제)

원격 저장소를 통째로 다운로드하는 것을 의미한다.
clone하면 변경이력도 함께 복제되어, 이 이력을 참조하고 커밋도 진행할 수 있다.
아래 명령 git clone을 사용하여 복제한다. remote repository url과, 로컬에 저장할 폴더 명을 입력하고 명령을 실행한다.

git clone <repository> <directory>

pull

원격 저장소에서 여러사람이 함께 작업을 할 때, 다른 사람의 변경 사항을 내 로컬 저장소에도 반영하기 위해 pull을 사용한다.
원격 저장소 주소와 원격 브랜치명을 명시해야 한다.

git pull <repository> <branch>

pull은 원격 브랜치의 변경사항을 가져와서 내 저장소와 merge한다. 그러므로 충돌이 발생할 수 있다.
그런 경우에는 충돌이 있는 부분을 수정한 다음 커밋해야 한다. 충돌이 발생하지 않는 경우 fast-forward 병합한다.
fetch하여 원격 브랜치의 변경사항을 가져 온 후 이를 로컬저장소의 브랜치와 merge한 다음 이를 commit하여 해결할 수도 있다.
(fetch > merge > commit)
pull된 내역은 git log 명령으로 확인하면 된다.

merge

git push
Username: <사용자명>
Password: <비밀번호>
To https://github.com/makeajourney/tutorial.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/makeajourney/tutorial.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

push 명령을 실행했을 때, (혹은 pull 명령을 실행했을 때도) 이런 상황을 만날 수 있다.
이미 원격에 변경된 사항이 내가 변경하려는 부분과 충돌하는 경우이다.
이런 경우, git은 충돌이 발생했음을 메시지로 알리고, 충돌되는 부분을 파일에 표시해준다.
이 파일을 열어서 충돌한 부분을 확인하고, merge한 다음, 변경사항 반영을 위해 커밋한다.
그런 다음 다시 push(혹은 pull) 명령을 실행하면, 병합된 내용이 merge 되었음을 확인 할 수 있다.

commit 변경

branch

위처럼, push나 pull 작업을 할 때 충돌 할 가능성이 있다. 그러다보면 상대방의 코드에 영향을 줄 수도 있고 또 내 작업에 영향을 받을 수도 있다.
이런 상황을 방지하기 위해 브랜치 기능을 적극 활용하는 것이 좋다.

master는 안정된 상태로 유지하는 것이 좋다.
새로운 기능을 개발 할 때는 새로운 브랜치를 생성하여 그 곳에서 작업하고, 테스트까지 진행 한 다음 기능 개발이 완료되면 작업그룹에서 의논을 거쳐 master에 병합한다.
또 안정된 버전과 별도로 릴리즈 버전, 버그 수정을 위한 브랜치도 별도로 생성하여 관리하는 것이 좋다.

이렇게 브랜치를 관리하면,
- 다른 사람의 작업에 영향을 주거나 받지 않고,
- 작업 흐름의 파악이 편리하며,
- 문제가 발생했을 경우 원인을 파악하기 쉬워 유지보수에 편리하다.
는 장점이 있다.

브랜치 생성

새로운 브랜치를 만들려면 아래 명령을 사용하면 된다. 새로 만들려는 브랜치의 이름을 명시하여 사용한다.

git branch <branchname>

브랜치를 새로 만들고 나면 이 브랜치를 사용하기 위해 지정해주어야 한다. 이 때 checkout 명령을 사용한다.
위에서 만든 브랜치의 이름을 명시하여 사용한다.

git checkout <branch>

체크아웃과 동시에 새로운 브랜치를 생성하려면 아래 명령을 사용하면 된다.

git checkout -b <branch>

아래 명령을 입력하면 브랜치 목록 전체를 확인 할 수 있다.
여기서 앞에 *가 붙어있는 것이 현재 선택된 브랜치이다.

git branch

브랜치 병합

아래 명령을 통해 브랜치를 병합 할 수 있다.
현재 checkout되어있는 브랜치에서 HEAD가 가리키고 있는 브랜치로 병합이 이루어진다.

git merge <commit>

fast-forward 병합

예를 들어, 현재 작업하고 있는 브랜치는 ‘issue01’이고 이를 마스터에 병합하려고 한다.
그런 경우에는 먼저 현재 issue01에 위치한 HEAD를 master로 변경한 다음, merge 명령을 사용하면 된다.

git checkout master
git merge issue01

non fast-forward 병합

예를 들어, ‘issue02’, ‘issue03’ 브랜치를 만들어서, 각각 작업을 수행했다. 그리고 issue02 브랜치를 master에 fast-forward 병합을 수행했다. 이후 issue03을 master에 병합하려고 하니 conflict가 발생했다.
이 경우에는 충돌 부분을 확인한 후 수정을 하고 다시 커밋한다. 그러면 issue03도 master에 병합됨을 확인 할 수 있다.

rebase

non fast-forward 병합을 수행하면, issue02, issue03 브랜치가 master에서 각각 갈라졌다가 병합 수행 이후에 다시 master로 합쳐지는 형태를 눈으로 확인 할 수 있다.
여기서 설명하는 rebase를 이용한 병합은, issue02, issue03 브랜치가 각각 독립적으로 갈라져 보이는 게 아니라, 하나의 줄기로 합쳐지도록 한다.
non fast-forward와 달리, merge 명령을 사용하지 않고 rebase명령을 사용 한다.

git checkout issue03
git rebase master

여기까지 진행하면 위와 마찬가지로 충돌이 발생한다. 충돌을 해결하기 위해 앞과 마찬가지로 충돌부분을 확인한 뒤 수정을 한다.
수정 이후 여기서는 다시 commit을 하지 않고, 수정된 파일을 stage 한 뒤에 아래 명령을 실행한다.

git rebase --continue

그러면 issue03브랜치가 master 브랜치가 위치하는 줄기에 합쳐진다. 하지만 브랜치 자체가 병합된 것은 아니다. 그러므로 다시 병합 명령을 실행해야 한다.

git checkout master
git merge issue03

모든 브랜치가 한 줄로 표현됨을 눈으로 확인 할 수 있다.

브랜치 삭제

git branch -d <branchname>

fetch

원격 저장소의 변경 이력을 가져오되, 병합은 하지 않는다.
fetch 명령을 사용해 가져온 변경 이력은 브랜치 이름이 없는 상태이므로, 이 브랜치는 FETCH_HEAD라는 이름으로 checkout이 가능하다.
fetch된 브랜치를 로컬의 master와 합치려면 FETCH_HEAD 브랜치를 merge 하거나 다시 pull을 실행한다.
위에도 말 했듯이, fetch > merge는 pull과 같은 기능을 한다.

tag

gitignore

pull request