개념 이해

일단 용어를 익히고 넘어 가자.

  • 작업 사본(working copy) : 저장소(repository)의 특정 리비전을 복사해 와서 내가 갖고 있는 파일들. svn에서 300번 리비전을 다운받아서 내 컴퓨터에 해당 리비전의 파일들이 있다고 하자. 그게 작업 사본이다.
  • 저장소 : 모든 commit history, tag, branch를 갖고 있는 곳. svn은 중앙 저장소에 이걸 모두 저장한다.

SVN은 원격 저장소에 commit history가 누적되고, 각 개발자는 작업 사본(working copy)을 들고 작업한다. SVN의 경우 현재 최신 리비전이 300번이고, 내가 최신으로 업데이트를 했다면, 내 컴퓨터에는 rivision 300번인 작업 사본만 존재한다. SVN의 정보는 .svn이라는 폴더에 저장되며, 여기엔 원격 저장소와 통신할 때 사용할 다양한 정보가 저장된다.

반면 git(한글 발음은 기트로 하겠다)는 원격 저장소가 필수가 아니다. 작업 사본과 commit history는 한 폴더에 함께 있다. 내가 left21이라는 프로젝트를 git 저장소로 만들고 싶다면, left21 폴더에서 git init이라고 치면 끝이다. 그러면 그 때부터 그 곳은 git 저장소가 된다. .git라는 git 폴더가 생성되며, 이곳에는 모든 commit history가 저장된다. 이 저장소들 중 하나를 원격 저장소로 만들고 ssh나 http, https로 접속을 가능하게 만들면 그냥 그게 원격 저장소가 된다. (git:// 프로토콜이나 file:// 프로토콜도 사용할 수 있다.)예컨대, 아래처럼 할 수 있다.

git clone http://192.168.0.30/left21.git

left21.git은 원격 저장소 폴더명이다. (원격 저장소 폴더에는 .git이라고 suffix를 붙이는 게 관례다.) 원격 저장소를 만드는 명령으로 만드는 건데, 일단 개념을 익히기 위한 것이니 그냥 보고 넘기자. 원격 저장소는 작업 사본을 포함하지 않고 .git 폴더의 내용만 들어있다. 여튼간에 여기서 기억할 것은 아래 두 가지다.

  1. git는 원격 저장소가 필수가 아니다. 모든 개발자의 컴퓨터가 하나의 저장소다.
  2. 여러 저장소 중 하나를 원격 저장소로 변환해서 사용하면 그만이다. (변환하지 않고 그냥 사용해도 되는 것 같은데 일단 패스.)

장점

로컬에 커밋한다는 점때문에 생기는 장점이 분명하다.

  • 커밋 속도가 무지하게 빠르다.
  • 브랜치 생성 속도가 무지하게 빠르다. 이 덕에 브랜치를 상당히 부담없이 만들었다 날렸다 할 수 있다. 브랜치는 나중에 설명한다.
  • 브랜치를 굳이 원격 저장소에 보낼 필요가 없으므로 동료들의 코드를 어지럽힐 걱정 없이 로컬에 있는 소스를 마음대로 갖고 놀 수 있다.
  • 원격 저장소가 날아가도 commit history가 대부분 보전된다. (원격에만 있는 branch 같은 건 보전 안 될 수도 있는 것 같던데 더 공부해 보고.)

설치

데비안 계열 리눅스에선 아래 명령어면 된다. (버전에 따라 apt-get install git-core라고 쳐야 할 수도 있는 것 같다.)

apt-get install git

윈도우에선 git를 따로 다운받아 설치하면 된다. 윈도우용을 제공한다.

기초설정

git config --global user.name "myname"
git config --global user.email "[email protected]"

이렇게 자신을 설정해 주지 않으면 작동하지 않는다. 이건 뭘 설정한 걸까? 한 컴퓨터에 git가 설치되면 해당 컴퓨터는 하나의 저장소가 된다. 이 저장소를 사용하는 주인의 이름과 이메일을 적는 것이다. 이 저장소에서 다른 저장소의 것을 받아오거나, 다른 저장소로 push를 하거나 뭐 그럴 때 이 이름을 사용하게 되는 거다.

git config --global core.quotepath false

위 명령은 한글 파일명을 제대로 보기 위한 설정이다. 위 설정을 하지 않으면 한글 파일명이 \302 하는 식으로 표시된다. 물론 한글 파일명은 사용하지 않는 게 귀찮은 일을 원천 차단하는 게 될 거다.

맥 유저가 있다면, 맥에서 아래 설정을 해 줘야 정신 건강에 좋을 거다. 한글 파일명 때문이다. 맥은 한글 파일명을 자소별로 분리해서 저장한다. (NFD방식이라고 한다. 자소를 합쳐서 저장하는 건 NFC 방식이라고 하고.) 이 때문에 생기는 문제가 있다. 아래와 같은 문제다.

  1. 리눅스 유저 팀원이 “한글파일명” 이라고 저장한 뒤 푸시한다.
  2. 맥 유저 팀원이 풀한다. “한글파일명”이 추가된다. 그러나 내부적으로는 “ㅎㅏㄴㄱㅡㄹㅍㅏㅇㅣㄹㅁㅕㅇ”이라고 저장됐다. 따라서 이 파일은 git 저장소에 없는 새로운 파일이다. untracked 파일이 발견됐으므로 커밋하라고 나온다. 시키는대로 커밋하고 푸시한다.
  3. 리눅스 유저 팀원이 풀하면 “ㅎㅏㄴㄱㅡㄹㅍㅏㅇㅣㄹㅁㅕㅇ”이라는 파일이 또 생긴다.

그걸 회피하려면 아래처럼 설정한다.

git config --global core.precomposeunicode true
git config --local core.precomposeunicode true

위처럼 일단 글로벌 설정을 해 준다. 그리고 이미 생성된 저장소에서는 모두 local로 유니코드 설정을 해 준다. 글로벌 설정과 로컬 설정 중에 당연히 우선순위를 갖는 것은 로컬 설정인데, 기본적으로 모든 저장소에는 core.precomposeunicodefalse로 설정돼 있기 때문에 로컬로 다 고쳐 줘야 한다.

저장소 만들기

저장소로 만들 폴더로 가서 다음 명령어를 치면 끝이다. git는 기본적으로 로컬 커밋이 가능하기 때문에 원격 저장소는 염두에 두지 않고 로컬 저장소를 만든다. 원격 저장소를 만드는 방법은 나중에 설명하도록 하겠다. (모든 로컬 브랜치는 그 자체로 원격 저장소가 될 수도 있을 지 모르겠는데, 정확힌 모르니까 일단 이렇게만 쓴다.)

로컬에서 사용할 용도니 로컬 저장소긴 한데, 특별히 로컬 저장소라고 부르진 않겠다.

git init

git에 파일을 추가하고 commit하기

git status

위 명령을 치면 저장소의 현재 상태가 나온다. 커밋할 놈 정보를 보여 주니까 이걸 보고 확인하면 된다. 파일을 하나 만들고 git status라고 쳐 보자.

그러면 git가 추적하고 있지 않은 놈 목록에 방금 만든 파일이 포함돼 나온다. 아래 명령을 치면 모든 파일을 stage 상태로 넣는다. .gitignore에 포함된 파일은 제외하고 말이다.

git add .

그렇게 하고 다시 git status라고 쳐 보자. 그러면 파일이 커밋할 놈에 포함됐다고 나온다. 이걸 stage 상태라고 부른다. 이제 커밋을 하자.

git commit

그러면 에디터가 뜨고 commit 메시지를 적게 한다. 에디터는 기본으로 vi로 돼 있다. 이 기회에 vi의 기본 명령을 익히자. i를 누르면 입력 모드로 들어간다. esc 키를 누르면 다시 명령 모드로 돌아온다. :를 누르면 명령줄이 나타나고, wq를 명령줄에 써 주고 엔터치면 저장(write)하고 빠져나온다(quit). 어떤 에디터를 쓰건 간에 저장하고 빠져나오면 바로 commit이 된다.

파일 수정 후 달라진 점을 확인하고 commit하기

아까 커밋한 파일을 수정해 보자. 그리고 다시 git status라고 명령을 내려 보자. 그러면 수정된 놈 목록에 포함돼 나온다. 뭐가 달라졌는지 확인해 보자.

git diff 파일명

그러면 달라진 점을 확인할 수 있다.

diff를 볼 때 색을 입혀서 보고 싶으면 아래 명령을 내려서 색을 입힌다.

git config --global color.diff auto

diff는 기본적으로 줄바꿈이 안 돼서 나온다. 줄바꿈을 해서 보고 싶다면 아래처럼 설정을 해 준다.

git config core.pager 'less -r'

less는 문서가 길 때 페이지를 넘기면서 볼 수 있게 해 주는 놈인데, -r 옵션을 주면 줄바꿈을 해서 보여 주나 보다. 그리고 less에서 페이지를 넘길 때는 기본적으로 다음 키를 사용할 수 있다.

  • 엔터 : 한줄씩 넘어간다
  • 스페이스바 : 한 페이지씩 넘어간다
  • q : 종료
  • /단어 + 엔터: ‘단어’라는 글자를 검색한다. 엔터친 상태에서 N을 누르면 다음 검색 결과로 간다. Shift+N을 누르면 이전 검색 결과로 간다.

자, git diff로 달라진 점을 확인했다면 아래 명령을 치자.

git add 파일명

이렇게 파일을 staged 상태로 만들고 git commit 명령을 내려서 또 커밋을 하자.

파일을 git에서 삭제하기

파일을 git 저장소에서 지우려면 어떤 파일이 삭제됐다고 알려 줘야 한다.

git rm 파일명

이렇게 하면 된다.

그냥 파일시스템에서 탐색기로 파일을 지웠다면 어떻게 해야 할까? 마찬가지로 위 명령어로 git에게 파일이 삭제됐다고 알려 주면 된다. 현재 파일 시스템에 해당 파일이 없어도 상관 없다. 여튼 git 저장소에서 파일을 삭제하려면 git rm을 거쳐야 하는 것이다.

SVN도 마찬가진데, GUI 툴들은 탐색기 같은 데서 삭제하면 저장소에서도 지우는 걸 알아서 해 주는 거다. (이클립스에서 svn 커밋할 때 탐색기에서 지운 놈들은 deleted라고 표시되지 않고 missing이라고 표시되는 걸 봤을 거다.)

파일을 이동하거나 파일명을 바꾸려면 mv를 사용한다.

git mv 원래파일명 바꿀파일명
git mv 원래파일명 바꿀파일위치

파일명에 경로가 포함된 것으로 생각하면 파일명 변경이나 이동이나 어차피 같은 거라고 이해하기 쉬울 것이다.

즉, 개념상 /myfolder/mytext.txt 까지 전체를 파일명으로 이해하면 되겠다. 개념을 그렇게 잡으면 /myfolder/sub/mytext.txt는 파일명이 변경된 것으로 이해할 수 있게 된다.

저장소에서 작업 사본 받기

SVN의 checkout은 git에서 clone이다. SVN은 최신 작업 사본을 받는 것이지만, git은 저장소를 통째로 복사해 오는 것이므로 명령어가 clone인 것이다.

git clone 저장소주소

작업 사본을 받아 보자.

git clone https://github.com/left21wm/seminar.git

이렇게 치면 이 문서를 쓰고 있는 저장소를 복사해온다. 그런데 이 세미나 저장소는 쓰기는 안 되게 돼 있을 테니 자신의 저장소를 만들어 보자. github는 널리 사용되는 git 저장소니까 github를 이용해서 저장소를 만들어 보자.

저장소를 만들었으면 제공하는 주소를 통해서 저장소를 받아와 보자. 그리고 나서 아무 문서나 만들고 git status라고 치고 add하고 commit하자. 그리고 저장소로 보내 보자.

git push origin master

한 번 push하면 다음부터는 git push라고 치면 origin master로 간다.

origin은 기본 원격 저장소의 닉네임이다. 원격 저장소 닉네임은 마음대로 설정할 수 있다. 이건 나중에 설명. 여튼 내 컴에 있는 하나의 저장소를 여러 개의 원격 저장소에 연동할 수 있어서 이런 기능이 있는 것 같다.

master는 기본 branch인데, branch는 나중에 설명하자.

여튼간에 위 명령을 치면 저장소로 보내진다.

아래 명령은 저장소의 변경 사항을 받아 오는 명령이다.

git pull origin master

위와 같이 치면 변경 사항이 받아진다. origin과 master는 위에 설명한대로다.

여럿이 작업할 때 A가 push를 했는데, B가 pull하지 않고 push를 하려고 하면 push가 되지 않는다.

이 정도면 git를 일단 기본적으로는 사용할 만큼 됐을 거라 본다.