나도 git 좀 써보자 – 사용하기

이 글은 크몽 재능인, socurites님이 원고를 기고하셨습니다.

이 글은 총 4부 중, 2번째 git 사용하기와 관련한 내용입니다.

설치가 끝났으니 이제 프로젝트를 하나 만들어서 기본적인 활용법을 익혀보자.

저장소 만들기

서브버전을 사용해 왔다면 아마 저장소는 원격 서버에서 호스팅하고, 자신의 로컬 머신에는 복사본 또는 working copy를 유지했을 것이다. 반면 git에서는 복사본 또는 working tree뿐만 아니라, 저장소까지도 자신의 로컬 머신의 .git 디렉토리에 유지한다.

일단 비어 있는 프로젝트를 하나 만들자.

C:\Documents and Settings>mkdir my-project
C:\Documents and Settings>cd my-project
C:\Documents and Settings\my-project>git init
Initialized empty Git repository in C:/Documents and Settings/my-project/.git/

프로젝트 디렉토리 안에서 git init 명령어를 실행하면, git 저장소가 생성된다.

파일 추가하고 변경하기

비어 있는 프로젝트에 index.html 파일을 아래와 같이 만들어서 추가하자.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
</body>
</html>

이제 프로젝트에 변경 사항이 생겼으므로, 즉 파일이 하나 추가되었으므로 git에 변경사항이 발생했음을 알려주자. 새로운 관리 대상이 생겼으므로, 대상 추가 작업 및 커밋 작업 2단계를 거쳐야 한다.

C:\Documents and Settings\my-project>git add index.html
C:\Documents and Settings\my-project>git commit -m "add new index.html"
[master (root-commit) 9bb9136] add new index.html
1 file changed, 9 insertions(+)
create mode 100644 index.html

커밋 로그를 보면,

C:\Documents and Settings\my-project>git log
commit 9bb9136e023cddf5db8457069be9c317bbc3ab2b
Author: socurites <socurites@gmail.com>
Date: Mon Jun 10 15:51:57 2013 +0900

add new index.html

와 같이 index.html 파일이 추가되었다는 기록을 확인할 수있다.

파일을 변경하기 전에, 현재 작업중인 working tree의 상태를 살펴보자.

C:\Documents and Settings\my-project>git status
# On branch master
nothing to commit, working directory clean

보다시피 working tree는 저장소와 현재 동기화 된 상태임을 알 수 있다. 이제 index.html을 아래와 같이 수정한 후,

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
Hello Changed World
</body>
</html>

working tree의 상태를 다시 살펴보면,

C:\Documents and Settings\my-project>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: index.html
#
no changes added to commit (use "git add" and/or "git commit -a")

index.html 파일이 변경되었으며, 커밋을 하려면 스테이징이 필요하다는 메시지가 나온다.

git의 경우 파일을 세 군데에 저장한다.

  • 작업 트리(working tree)
    로컬에서 작업하는 공간으로, 서브버전에서는 working copy라고도 부른다.
  • 스테이징 영역(staging area)
    작업 트리와 저장소 사이의 버퍼 공간으로, 커밋할 대상을 올려두는 위치다.
  • 저장소(repository)
    실제 파일이 관리되는 공간이다.

git add 명령어를 사용하면, 작업 트리의 파일이 스테이징 영역으로 이동시킨다. 즉 파일을 스테이징하게 된다.

C:\Documents and Settings\my-project>git add index.html
C:\Documents and Settings\my-project>git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#

이제 파일을 저장소로 커밋하자.

C:\Documents and Settings\my-project>git commit -m "add body text" index.html
[master 0ca802d] add body text
1 file changed, 1 insertion(+)

C:\Documents and Settings\my-project>git status
# On branch master
nothing to commit, working directory clean

브랜치(branch) 만들기

이제 프로젝트의 스프린트가 마무리되었고, 릴리즈팀에서 릴리즈해야 한다고 해보자. 하지만 릴리즈와 돵시에프로젝트에 새로운 기능을 추가해야 한다고 해보자. 만약 새로운 기능을 추가할 때까지 릴리즈를 늦추어야 한다면, 사용자는 개발이 이미 완료된 기능을 다음 릴리즈까지 기다리게 하는 셈이다. 따라서 이번 이번 스프린트의 결과는 그대로 릴리즈하면서 동시에 새로운 기능을 개발하려고 할 때, 브랜치를 사용하면 효과적이다.

C:\Documents and Settings\my-project>git branch RB_1.0 master

git branch 명령어는 2개의 인자를 받는데, 첫 번째 인자는 브랜치명이며 두번째 인자는 브랜치할 프로젝트 명이다. 서브버전에서는 마스터 브랜치를 트렁크(trunk)라고 불렀다.

이제 릴리즈팀에서는 RB_1.0 브랜치에서 릴리즈를 하도록 내버려 두고, 개발팀은 마스터에서 새로운 기능을 추가한다. 예를 들어 index.html 파일을 수정해야한다고 해보자.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
Hello Changed World
Hello New World
</body>
</html>

변경사항을 마스터 브랜치에 커밋한다.


C:\Documents and Settings\my-project>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: index.html
#
no changes added to commit (use "git add" and/or "git commit -a")

C:\Documents and Settings\my-project>git commit -a -m "new world"
[master f8e64db] new world
1 file changed, 2 insertions(+)

C:\Documents and Settings\my-project>git status
# On branch master
nothing to commit, working directory clean

이와 동시에 릴리즈팀에서도 릴리즈 브랜치를 약간 수정할 작업이 생겼다. 작업 트리를 릴리즈 브랜치로 변경해 보자.

C:\Documents and Settings\my-project>git checkout RB_1.0
Switched to branch 'RB_1.0'

마스터에서 브랜치로 스위칭하면, 현재 수정한 index.html 파일의 내용이 변경 전의 내용으로 갱신된다. 왜냐하면 릴리즈 브랜치에서는 변경 작업이 발생하지 않았기 때문이다. 따라서 브랜치를 사용하면 릴리즈와 개발을 동시에 진행할 수 있게 된다.

이제 릴리즈 브랜치에서도 index.html을 약간 수정하자.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Hello World</title>
</head>
<body>
Hello World
Hello Changed World
Hello Release World
</body>
</html>

그리고 변경사항을 커밋한다.

C:\Documents and Settings\my-project>git commit -a -m "release world"
[RB_1.0 d22029a] release world
1 file changed, 2 insertions(+)

릴리즈 태깅(tagging)하기

이제 릴리즈 준비가 끝난 브랜치에 태깅을 해보자. 태깅이란 거창한게 아니라 단순히 이름, 즉 태그를 붙여서 저장소 이력의 특정 지점을 알기 쉽게 표시하는 것이다.


C:\Documents and Settings\my-project>git tag my-project-1.0 RB_1.0
C:\Documents and Settings\my-project>git tag
my-project-1.0

릴리즈가 완료되면, 릴리즈 브랜치에서 변경된 내용을 마스터 브랜치에도 반영을 해야 하는데, 이러한 작업을 브랜치 병합(merge) 또는 합치기라고 부른다. 먼저 작업 트리를 마스터 브랜치로 변경한다.

C:\Documents and Settings\my-project>git checkout master
Switched to branch 'master'

브랜치를 마스터에 합친다.

C:\Documents and Settings\my-project>git rebase RB_1.0
First, rewinding head to replay your work on top of it...

근데 문제가 생겼다. 릴리즈 브랜치와 마스터 브랜치에서 동일한 라인을 수정했기 때문에, 자동으로 합치는게 불가능해졌다. 이런 경우에는 사람이 직접 개입을 할 수밖에 없다.

일단 동일한 파일의 동일한 라인을 2사람이 동시에 변경할 가능성이 적기 때문에, 이러한 긍정정 잠금(optimistic lock) 기능이 효과적이라고 하는 말에 개인적으로는 동의하지 않는다. 변경 가능성이 적더라도 언제나 충돌이 발생하기 마련이다. 특히 공통 파일 같은 경우 충돌이 발생하면, 정말이지 지옥의 문이 열리는 경우가 한두번이 아니기 때문이다.

어쨌든 충돌을 해결해 보자. 우선 마스터 브랜치에서 파일을 아래와 같이 정리하자.

C:\Documents and Settings\my-project>git commit -a -m "rebase conflict, merged by hand"
[detached HEAD 899bddf] rebase conflict, merged by hand
1 file changed, 2 insertions(+)

C:\Documents and Settings\my-project>git status
# HEAD detached from d22029a
# You are currently rebasing.
# (all conflicts fixed: run "git rebase --continue")
#
nothing to commit, working directory clean

일단 최신의 파일로 변경한 후 커밋했지만, 저장소의 상태는 문제가 있어 보인다. 그리고 rebase 명령어를 사용하는 경우, 나도 모르게 마스터 브랜치에서 릴리즈 브랜치로 이동한 상태가 되버렸다. 일단 이부분도 강제적으로 해결하자.

C:\Documents and Settings\my-project>git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

899bddf rebase conflict, merged by hand

If you want to keep them by creating a new branch, this may be a good timeto do so with:

git branch new_branch_name 899bddf

Switched to branch 'master'

C:\Documents and Settings\my-project>git status
# On branch master
# You are currently rebasing.
# (all conflicts fixed: run "git rebase --continue")
#
nothing to commit, working directory clean

C:\Documents and Settings\my-project>git commit -a -m "rebase conflict, merged by hand"
# On branch master
# You are currently rebasing.
# (all conflicts fixed: run "git rebase --continue")
#
nothing to commit, working directory clean

C:\Documents and Settings\my-project>git status
# On branch master
# You are currently rebasing.
# (all conflicts fixed: run "git rebase --continue")
#
nothing to commit, working directory clean

그럼 이제 불필요한 릴리즈 브랜치는 삭제하자. 릴리즈 브랜치는 태깅해두었기 때문에, 해당 브랜치에서 수정 작업이 필요하다면 태깅한 브랜치에서 얼마든지 다시 분기할 수 있다.

C:\Documents and Settings\my-project>git branch -d RB_1.0
error: The branch 'RB_1.0' is not fully merged.
If you are sure you want to delete it, run 'git branch -D RB_1.0'.

C:\Documents and Settings\my-project>git branch -D RB_1.0
Deleted branch RB_1.0 (was d22029a).

이제 my-project-1.0이라는 이름으로 태깅한 릴리즈를 압축하자.

C:\Documents and Settings\my-project>git archive --format=zip --prefix=my-project-1.0/ my-project-1.0 > mysite-1.0.zip

원격 저장소 사용하기

이제 개발팀에 새로운 팀원이 추가되었고, 프로젝트를 다른 팀원과 함께 개발해야 한다고 해보자. 그러면 지금까지 로컬 저장소에서 관리하던 프로젝트를 팀원과 공유해야 한다. 즉 원격 저장소가 필요하다.

원격 저장소를 만들었다면, 이제 원격 저장소에 지금가지 개발된 코드를 올린다. 그러면 새로운 팀원은 원격 저장소에서 코드를 복제한다. 이제 두명의 개발자가 동일한 프로젝트에서 작업하게 되었으며, 각각 자신만의 저장소를 가지게 되었다. 하지만 두 사람은 모두 변경된 사항을 원격에 푸시(push)해야만 서로간에 최신의 코드를 유지할 수 있다.

일단 원격 저장소 사용하는 법은 이어서 살펴보도록 하자.

크몽 재능

댓글 남기기