A2공간 - 도움되는 글을 쓰자

ani2life.egloos.com

포토로그


그냥 잡담

※방명록은 따로 없고 무조건 최신글에 댓글 남기시면 됩니다. ^^

위드블로그



SVN 사용자를 위한 Git 개발/플밍


SVN 사용자를 위한 Git

작성자: A2


< 문서의 소개 >
Git에 대한 튜토리얼이 아니므로 Git 자체에 대해서는 다른 문서를 참고하세요.
Git의 설치나 시스템 환경설정도 다루지 않습니다.
기존 SVN을 쓰던 사용자가 Git을 자연스럽게 익히기 위해 만들었습니다.
CVS도 SVN과 비슷하므로 CVS 사용자가 읽기에도 큰 문제는 없습니다.

< 문서의 목표 >
간단한 실습을 따라하며 Git의 사용을 자연스럽게 익힌다.
SVN과 달리 다수의 저장소를 가지는 Git에서 작업을 공유하는 방법을 익힌다.
Git의 명령어를 익히기 보다는 Git의 스타일을 익힌다.



< 환경설정 >
Git을 쓰기위한 기본적인 환경설정을 합니다.

$ git config --global user.name "이름"
$ git config --global user.email "이메일"


< 저장소 만들기 >
SVN은 중앙에 저장소를 하나 두고 다수가 그곳을 사용하지만 Git은 각자의 저장소를 가집니다.
SVN을 쓰던 분들은 여기서 궁금증이 마구 생겨날 것 입니다.
하지만 걱정마시고 궁금증은 잠시 접어두세요. ^^
일단은 개인 컴퓨터에 로컬 저장소를 만들고 사용하는 것 부터 시작합니다.

저장소로 사용할 디렉토리를 하나 만들고 해당 디렉토리 안에서 init 명령을 실행합니다.
이 문서에서는 디렉토리 이름을 d1으로 하겠습니다.

$ mkdir ./d1
$ cd ./d1
$ git init

이하 모든 작업들은 이 디렉토리에서 진행되며 '작업공간'이라고 부르겠습니다.
작업공간에는 .git 이라는 숨겨진 디렉토리가 생성되어 있습니다.
이곳에 저장소의 모든 정보들이 기록됩니다.

SVN의 .svn은 작업공간 내의 모든 디렉토리마다 하나씩 존재하지만 .git은 최상위 디렉토리에 딱 한개만 존재합니다.


< 파일 추가하기 >
지금 d1 디렉토리는 비어있습니다.
파일을 하나 만들어 보겠습니다.

$ echo 'AAA' > 1.txt

현재 상태를 확인해봅니다.

$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    1.txt
nothing added to commit but untracked files present (use "git add" to track)

뭔가 복잡해 보이지만 별거 없습니다.
Untracked files 항목에 1.txt가 보입니다.

이때 Git의 장점중에 하나가 위에 보이는데 어떤 명령이 가능한지 설명이 나옵니다.
(use "git add <file>..." to include in what will be committed)
그러니까 add 하라네요. ^^

$ git add 1.txt

다시 상태를 확인해 봅니다.

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#    new file:   1.txt
#

아까와는 달리 Changes to be committed 항목에 새로운 파일 1.txt가 있다고 표시됩니다.
취소하고 싶으면 어떻게 해야 할까요? 위에 표시된 설명대로 하면 됩니다. ^^
(use "git rm --cached <file>..." to unstage)


< 커밋하기 >
위에서 add한 파일을 커밋하겠습니다.

$ git commit -m'메시지'
[master (root-commit) 644da9d] 1.txt
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 1.txt

이제 저장소에 커밋이 되었습니다.

$ git status
# On branch master
nothing to commit (working directory clean)

작업공간이 깨끗하다네요.


< 파일 수정하기 >
커밋된 파일을 수정하겠습니다.

$ echo 'BBB' > 1.txt

상태를 확인해봅니다.

$ git status
# On branch master
# 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:   1.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

파일이 하나 바뀌었다네요.
SVN은 여기서 바로 커밋을 하면 적용되지만 Git은 먼저 add를 해야합니다.
(use "git add <file>..." to update what will be committed)
항상 표시되는 팁을 참고하세요.

$ git add 1.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    modified:   1.txt
#

이제 커밋을 합니다.

$ git commit -m'메시지'
[master efdbef4] 메시지
 1 files changed, 1 insertions(+), 1 deletions(-)


< 파일 지우기 >
커밋된 파일을 지우겠습니다.

$ git rm 1.txt
rm '1.txt'

상태를 확인해봅니다.

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    deleted:    1.txt
#

1.txt가 지워졌다는 것을 알 수 있습니다.
취소하는 방법도 친절하게 표시해줍니다.

이제 커밋하여 저장소에 적용합니다.

$ git commit -m'메시지'
[master 6e10ea8] 메시지
 1 files changed, 0 insertions(+), 1 deletions(-)
 delete mode 100644 1.txt


< 파일 이동 >
위의 작업들과 별다른 차이는 없습니다.

$ git mv 1.txt 2.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    deleted:    1.txt
#    new file:   2.txt
#


< 브랜치 생성 >
[질문]
지금 브랜치 설명할 순서 맞나요?

[답변]
add, rm, mv와 같은 기초적인 것을 하다가 브랜치가 등장했습니다.
브랜치는 앞으로의 이해를 위해서 지금 짚고 넘어가야 합니다.
어렵지 않으니 걱정하지 마세요.

현재의 브랜치를 확인해봅니다.

$ git branch
* master

master라는 브랜치가 하나 있고 SVN과 달리 트렁크는 없습니다.
현재 상태를 확인합니다.

$ git status
# On branch master
nothing to commit (working directory clean)

On branch master 라고 보이시나요?
지금은 master 브랜치 상태 입니다.

1.0이라는 브랜치를 만들어봅니다.

$ git branch 1.0
$ git branch
  1.0
* master

새로운 브랜치가 나타났습니다.
그럼 현재 작업중인 master 브랜치에서 1.0 브랜치로 바꿔보겠습니다.

$ git checkout 1.0
Switched to branch '1.0'

브랜치가 바뀌었습니다.
현재 상태를 확인해봅니다.

$ git status
# On branch 1.0
nothing to commit (working directory clean)
$ git branch
* 1.0
  master

On branch 1.0 이라고 표시되는 것을 볼 수 있습니다.
그리고 branch 명령에서도 아까와 달리 1.0에 별표(*)가 있습니다.
브랜치 1.0에 파일을 추가하겠습니다.

$ echo 'BBB' > 2.txt
$ git add 2.txt
$ git commit -m'메시지'
[1.0 ed406cb] 메시지
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 2.txt
$ ls
1.txt  2.txt

2개의 파일이 존재합니다.
이제 다시 master 브랜치로 변경해봅니다.

$ git checkout master
Switched to branch 'master'
$ ls
1.txt

원래 master 브랜치의 상태였던 1개의 파일만 보입니다.


[질문]
파일 추가, 삭제도 했고 브랜치도 만들고 기초적인 부분은 알겠습니다.
그런데 처음 시작할때부터 궁금했던건데 여러사람과 어떻게 같이 사용하죠?

[답변]
이제부터 그걸 설명합니다.


< SVN과 Git의 저장소 >
지금까지는 개인 컴퓨터의 로컬 저장소에서 작업을 했습니다.
이렇게 하면 개인 버전관리는 되었지만 공동의 작업이 안됩니다.

우선 간단하게 설명하겠습니다.
  1. 기준이 되는 저장소를 하나 만듭니다.
  2. 기준이 되는 저장소를 각자 자신의 컴퓨터에 복사합니다.
  3. 자신의 컴퓨터에 저장된 저장소에서 작업 합니다.
  4. 자신의 저장소에서 한 작업을 원래의 저장소로 보냅니다.
  5. 다른 사람들은 원래의 저장소에서 자신의 저장소로 최신 내용을 받아옵니다.
[질문]
왠지 SVN이랑 차이가 없어 보여요.

[답변]
SVN은 저장소가 하나지만 Git은 각자 저장소를 가지고 있습니다.
즉, 프로젝트의 모든 이력을 각자 가지고 있습니다.
SVN은 중앙 저장소에 문제가 발생하면 이력관리를 진행하지 못하지만 Git은 각자의 저장소에서 관리하므로 지속적인 작업을 할 수가 있습니다.
한마디로 각자 저장소를 갖고 있어서 가능한 방법들이 장점 입니다.


< 저장소 복사하기 >
위에서 만든 d1 디렉토리의 저장소를 복사하겠습니다.

$ ls
d1
$ git clone ./d1 d2
$ git clone ./d1 d3
$ ls
d1 d2 d3

clone 명령으로 복사할 저장소의 경로를 적어주고 복사될 디렉토리명을 적으면 됩니다.
이제 d1은 원격 저장소, d2와 d3는 로컬 저장소로 칭하겠습니다.

[질문]
이거는 그냥 로컬 작업이잖아요?

[답변]
실습의 편의를 위해 로컬의 저장소를 복사했지만 원래의 d1을 원격 저장소라고 생각하시면 됩니다.
SVN처럼 저장소의 경로는 git, http, ssh 등 다양한 프로토콜로 접근 할 수 있습니다.


< 원격 저장소 설정 바꾸기 >
원격 저장소인 d1을 로컬 저장소인 d2와 d3가 같이 쓰려면 d1에 간단한 설정을 바꿔줘야 합니다.

$ cd d1
$ git config core.bare true
$ git status
fatal: This operation must be run in a work tree

이제 d1에서는 직접 저장소를 변경하는 작업들을 할 수 없습니다.
위 처럼 명령을 내리면 작업 트리에서만 가능한 명령이라는 메시지가 나옵니다.

처음 저장소를 만들때 bare 저장소를 만들 수도 있습니다.

$ git init --bare


< 로컬 저장소에서 작업하기 >
d2 디렉토리의 현재 상태를 확인해봅니다.

$ cd d2
$ git status
# On branch master
nothing to commit (working directory clean)
$ ls
1.txt

여기까지는 d1과 같습니다.
원격 저장소를 확인하는 remote 명령을 해봅니다.

$ git remote
origin

d1에서는 remote 명령을 내려도 출력되는 내용이 없지만 d2에서는 origin이라고 나옵니다.
remote -v 명령을 내리면 원격 저장소의 경로도 출력됩니다.
origin은 저장소를 복사하면 생기는 원격 저장소의 기본 별명(alias) 입니다.

d2 디렉토리에서 간단한 작업을 하겠습니다.

$ touch 3.txt
$ git add 3.txt
$ git commit -m'메시지'
[master 95a254d] 메시지
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 3.txt

d2의 master 브랜치에서 작업을 했습니다.
이제 d1과 d2의 내용이 달라졌습니다.
그렇다면 d2 저장소의 작업을 d1으로 보내서 d3에게도 공유가 가능하게 합니다.

$ git push
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 271 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To d1의 경로
   efdbef4..95a254d  master -> master

push 명령으로 d1에 적용이 되었습니다.


< 원격 저장소로 부터 최근 작업이력 가져오기 >
위에서 로컬 저장소 d2의 작업을 원격 저장소 d1에 적용했습니다.
하지만 아직 다른 로컬 저장소 d3는 d2의 작업이 공유되지 않았습니다.
이번에는 d3가 원격 저장소로 부터 최근 작업이력을 가져와보겠습니다.

$ cd d3
$ git fetch
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From d1의 경로
   5b96696..d19ea94  master     -> origin/master

fetch 명령으로 원격 저장소의 수정된 사항을 받아왔습니다.
하지만 그렇다고 d3의 작업공간에 변경이 발생한 것은 아닙니다.
최근 fetch한 정보는 FETCH_HEAD 심볼에 담겨져 있습니다.

물론 지금은 d3에 변경된 내용이 없지만 실무에서는 d3에서 작업을 하고 있었을 겁니다.
그렇기에 FETCH_HEAD의 내용을 현재 d3에 병합(merge)하겠습니다.

$ git merge FETCH_HEAD
Merge made by recursive.
 3.txt |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 3.txt

위의 fetch와 merge를 한번에 하는 명령이 있습니다.

$ git pull

왠지 pull을 쓰면 SVN의 update와 같아보이지만 전혀 다릅니다.
SVN에서는 현재 d3 디렉토리에서 3.txt 파일을 지우고 update 명령을 내리면 저장소로부터 최신 파일을 받아옵니다.
하지만 Git은 pull 명령을 내려도 이미 업데이트 되었다고 합니다.

$ git pull
Already up-to-date.

지워진(변경된) 파일을 복구(취소)하는 방법은 이 문서의 초반에 여러번 이야기 되었으니 설명하지 않습니다.


< 로컬 저장소 만든 브랜치를 원격 저장소에 적용하기 >
현재 d1, d2, d3 모두 master, 1.0 이렇게 2개의 브랜치를 갖고 있습니다.

$ git branch
  1.0
* master

d2에서 2.0 브랜치를 만들겠습니다.

$ cd d2
$ git branch 2.0

아직 원격 저장소 d1에는 적용되지 않은 상태입니다.

$ git branch
  1.0
  2.0
* master
$ git branch -r
  origin/1.0
  origin/HEAD -> origin/1.0
  origin/master

branch 명령으로 로컬의 브랜치를 보면 2.0 브랜치가 있습니다.
branch -r 명령으로 원격의 브랜치를 보면 2.0이 없습니다.
원격 저장소에 적용합니다.

$ git push origin 2.0
Total 0 (delta 0), reused 0 (delta 0)
To d1의 경로
 * [new branch]      2.0 -> 2.0
$ git branch -r
  origin/1.0
  origin/2.0
  origin/HEAD -> origin/1.0
  origin/master

로컬 저장소 d3에서 원격 저장소 d1에 새로 적용된 브랜치를 얻어오겠습니다.

$ git fetch
From d1의 경로
 * [new branch]      2.0        -> origin/2.0


< 마치며 >
Git에서 태그나 롤백 사용등 실무에 필요한 내용은 많습니다.
하지만 문서의 시작에 썼던 문서의 목표는 달성했다고 생각합니다.
SVN(또는 CVS)을 써봤기에 나머지 기능들은 다른 Git 문서를 통해서 어렵지 않게 배우실 수 있을 겁니다. ^^



덧글

  • Toris 2011/04/21 09:30 #

    안녕하세요..^^
    웹 관련 짜잘한 일을 하고 있는 1인입니다
    이글루스를 잘 안하는데 우연히 결혼정보회사 글을 보고 들어왔는데 주옥같은 글이 많네요..
    링크해놓고 간혹 들러도 될까요^^;

  • -A2- 2011/04/21 10:41 #

    안녕하세요~ 방문해주셔서 감사합니다.
    블로그 방문은 자유죠. ^^ ㅎㅎ
    언제든 오세요.