From 77cce999f6025c7e3d0728bd54e91e1da62b1557 Mon Sep 17 00:00:00 2001 From: Changwoo Ryu Date: Sun, 2 Mar 2014 12:12:54 +0900 Subject: [PATCH 1/3] Fix typos --- ko/02-git-basics/01-chapter2.markdown | 2 +- ko/03-git-branching/01-chapter3.markdown | 2 +- ko/04-git-server/01-chapter4.markdown | 4 ++-- ko/05-distributed-git/01-chapter5.markdown | 2 +- ko/06-git-tools/01-chapter6.markdown | 6 +++--- ko/08-git-and-other-scms/01-chapter8.markdown | 4 ++-- ko/09-git-internals/01-chapter9.markdown | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ko/02-git-basics/01-chapter2.markdown b/ko/02-git-basics/01-chapter2.markdown index 9353c88e3..5bf08bdfa 100644 --- a/ko/02-git-basics/01-chapter2.markdown +++ b/ko/02-git-basics/01-chapter2.markdown @@ -908,7 +908,7 @@ Git으로 커밋한 모든 것은 언제나 복구할 수 있다. 삭제한 브 v0.1 v1.3 -이 명령은 알파벳 순서로 태그을 보여준다. 사실 순서는 별로 중요한 게 아니다. +이 명령은 알파벳 순서로 태그를 보여준다. 사실 순서는 별로 중요한 게 아니다. 검색 패턴을 사용하여 태그를 검색할 수 있다. Git 소스 저장소는 240여 개의 태그가 있다. 만약 1.4.2 버전의 태그들만 검색하고 싶으면 아래와 같이 실행한다: diff --git a/ko/03-git-branching/01-chapter3.markdown b/ko/03-git-branching/01-chapter3.markdown index 9a66a6841..cf5dade52 100644 --- a/ko/03-git-branching/01-chapter3.markdown +++ b/ko/03-git-branching/01-chapter3.markdown @@ -2,7 +2,7 @@ 모든 버전 관리 시스템은 브랜치를 지원한다. 개발을 하다 보면 코드를 여러 개로 복사해야 하는 일이 자주 생긴다. 코드를 통째로 복사하고 나서 원래 코드와는 상관없이 독립적으로 개발을 진행할 수 있는데, 이렇게 독립적으로 개발하는 것이 브랜치다. -버전 관리 시스템에서 브랜치를 만드는 과정은 고생스럽다. 개발자가 수동으로 소스코드 디렉토리를 복사해서 브랜치를 만들어야 하고 소스코드의 양이 많으면 브린채를 만드는 시간도 오래 걸린다. +버전 관리 시스템에서 브랜치를 만드는 과정은 고생스럽다. 개발자가 수동으로 소스코드 디렉토리를 복사해서 브랜치를 만들어야 하고 소스코드의 양이 많으면 브랜치를 만드는 시간도 오래 걸린다. 사람들은 브랜치 모델이 Git의 최고의 장점이라고, Git이 다른 것들과 구분되는 특징이라고 말한다. 당최 어떤 점이 그렇게 특별한 것일까? Git의 브랜치는 매우 가볍다. 순식간에 브랜치를 새로 만들고 브랜치 사이를 이동할 수 있다. 다른 버전 관리 시스템과는 달리 Git은 브랜치를 만들어 작업하고 나중에 Merge하는 방법을 권장한다. 심지어 하루에 수십 번씩해도 괜찮다. Git 브랜치에 능숙해지면 개발 방식이 완전히 바뀌고 다른 도구를 사용할 수 없게 된다. diff --git a/ko/04-git-server/01-chapter4.markdown b/ko/04-git-server/01-chapter4.markdown index 2755518da..9917fd92b 100644 --- a/ko/04-git-server/01-chapter4.markdown +++ b/ko/04-git-server/01-chapter4.markdown @@ -12,7 +12,7 @@ Git 서버를 운영하는 것은 어렵지 않다. 우선 사용할 전송 프 Git은 Local, SSH, Git, HTTP 이렇게 네 가지의 네트워크 프로토콜을 사용할 수 있다. 이 절에서는 각각 어떤 경우에 유용한지 살펴볼 것이다. -HTTP 프로토콜를 제외한 나머지들은 모두 Git이 서버에 설치돼 있어야 한다. +HTTP 프로토콜을 제외한 나머지들은 모두 Git이 서버에 설치돼 있어야 한다. ### 로컬 프로토콜 ### @@ -482,7 +482,7 @@ Gitosis의 접근제어 방법은 매우 단순하다. 만약 이 프로젝트 readonly = iphone_project members = john -이제 John은 프로젝트를 Clone하거나 Fetch할 수는 있지만, 프로젝트에 Push할 수는 없다. 다양한 사용자와 프로젝트가 있어도 필요한 만큼 그룹을 만들어 사용하면 된다. 그리고 members 항목에 사용자 대신 그룹명을 사용할 수도 있다. 그룹명 앞에 `@`를 붙이면 그 그룹의 사용자을 그대로 상속한다: +이제 John은 프로젝트를 Clone하거나 Fetch할 수는 있지만, 프로젝트에 Push할 수는 없다. 다양한 사용자와 프로젝트가 있어도 필요한 만큼 그룹을 만들어 사용하면 된다. 그리고 members 항목에 사용자 대신 그룹명을 사용할 수도 있다. 그룹명 앞에 `@`를 붙이면 그 그룹의 사용자를 그대로 상속한다: [group mobile_committers] members = scott josie jessica diff --git a/ko/05-distributed-git/01-chapter5.markdown b/ko/05-distributed-git/01-chapter5.markdown index c1ea7508a..11ec5df3c 100644 --- a/ko/05-distributed-git/01-chapter5.markdown +++ b/ko/05-distributed-git/01-chapter5.markdown @@ -466,7 +466,7 @@ Insert 18333fig0518.png ### 대규모 공개 프로젝트 ### -대규모 프로젝트은 보통 수정사항이나 Patch를 수용하는 자신만의 규칙을 마련해놓고 있다. 프로젝트마다 규칙은 서로 다를 수 있으므로 각 프로젝트의 규칙을 미리 알아둘 필요가 있다. 대규모 프로젝트는 대부분 메일링리스트를 통해서 Patch를 받아들이는데 예제를 통해 살펴본다. +대규모 프로젝트는 보통 수정사항이나 Patch를 수용하는 자신만의 규칙을 마련해놓고 있다. 프로젝트마다 규칙은 서로 다를 수 있으므로 각 프로젝트의 규칙을 미리 알아둘 필요가 있다. 대규모 프로젝트는 대부분 메일링리스트를 통해서 Patch를 받아들이는데 예제를 통해 살펴본다. 토픽 브랜치를 만들어 수정하는 작업은 앞서 살펴본 바와 거의 비슷하지만, Patch를 제출하는 방식이 다르다. 프로젝트를 Fork 하여 Push하는 것이 아니라 커밋 내용을 메일로 만들어 개발자 메일링리스트에 제출한다: diff --git a/ko/06-git-tools/01-chapter6.markdown b/ko/06-git-tools/01-chapter6.markdown index 1af11f6b2..af810484d 100644 --- a/ko/06-git-tools/01-chapter6.markdown +++ b/ko/06-git-tools/01-chapter6.markdown @@ -223,7 +223,7 @@ Double Dot으로는 세 개 이상의 레퍼런스에 사용할 수 없지만 $ git log refA refB ^refC $ git log refA refB --not refC -이 조건을 잘 응용하면 작업 중인 브랜치와 다른 브랜치을 매우 상세하게 비교할 수 있다. +이 조건을 잘 응용하면 작업 중인 브랜치와 다른 브랜치를 매우 상세하게 비교할 수 있다. #### Triple Dot #### @@ -987,9 +987,9 @@ Merge해서 서브모듈의 HEAD 값이 변경됐다. 슈퍼프로젝트가 아 ### 슈퍼프로젝트 ### -프로젝트 규모가 크면 CVS나 Subversion에서는 모듈 프로젝트을 간단히 하위 디렉토리로 만들었다. 가끔 Git에서도 이런 Workflow을 사용하려는 개발자들이 있다. +프로젝트 규모가 크면 CVS나 Subversion에서는 모듈 프로젝트를 간단히 하위 디렉토리로 만들었다. 가끔 Git에서도 이런 Workflow을 사용하려는 개발자들이 있다. -Git에서는 각 하위 디렉토리를 별도의 Git 저장소로 만들어야 한다. 그리고 그 저장소을 포함하는 상위 저장소를 만든다. 슈퍼프로젝트의 태그와 브랜치를 이용해서 각 프로젝트의 관계를 구체적으로 정의할 수 있다는 것은 Git만의 장점이다. +Git에서는 각 하위 디렉토리를 별도의 Git 저장소로 만들어야 한다. 그리고 그 저장소를 포함하는 상위 저장소를 만든다. 슈퍼프로젝트의 태그와 브랜치를 이용해서 각 프로젝트의 관계를 구체적으로 정의할 수 있다는 것은 Git만의 장점이다. ### 서브모듈 사용할 때 주의할 점들 ### diff --git a/ko/08-git-and-other-scms/01-chapter8.markdown b/ko/08-git-and-other-scms/01-chapter8.markdown index 307c1a6d4..9ad050838 100644 --- a/ko/08-git-and-other-scms/01-chapter8.markdown +++ b/ko/08-git-and-other-scms/01-chapter8.markdown @@ -16,7 +16,7 @@ Git과 Subversion을 이어주는 명령은 `git svn` 으로 시작한다. 이 `git svn` 명령을 사용할 때는 절름발이인 Subversion을 사용하고 있다는 점을 염두하자. 우리가 로컬 브랜치와 Merge를 맘대로 쓸 수 있다고 하더라도 최대한 일직선으로 히스토리를 유지하는것이 좋다. Git 저장소처럼 사용하지 않는다. -히스토리를 재작성해서 Push하지 말아야 한다. Git을 사용하는 동료들끼기 따로 Git 저장소에 Push하지도 말아야 한다. Subversion은 단순하게 일직선 히스토리만 가능하다. 팀원중 일부는 SVN을 사용하고 일부는 Git을 사용하는 팀이라면 SVN Server를 사용해서 협업하는 것이 좋다. 그래야 삶이 편해진다. +히스토리를 재작성해서 Push하지 말아야 한다. Git을 사용하는 동료들끼리 따로 Git 저장소에 Push하지도 말아야 한다. Subversion은 단순하게 일직선 히스토리만 가능하다. 팀원중 일부는 SVN을 사용하고 일부는 Git을 사용하는 팀이라면 SVN Server를 사용해서 협업하는 것이 좋다. 그래야 삶이 편해진다. ### 설정하기 ### @@ -551,7 +551,7 @@ Mark는 정수 값을 사용해야 하기 때문에 디렉토리를 배열에 $author = 'Scott Chacon ' -이제 Importer에서 출력할 커밋 데이터는 다 준비했다. 이제 출력해보자. 사용할 브랜치, 해당 커밋과 관련된 Mark, 커미터 정보, 커밋 메시지, 이전 커밋를 출력한다. 코드로 만들면 아래와 같다: +이제 Importer에서 출력할 커밋 데이터는 다 준비했다. 이제 출력해보자. 사용할 브랜치, 해당 커밋과 관련된 Mark, 커미터 정보, 커밋 메시지, 이전 커밋을 출력한다. 코드로 만들면 아래와 같다: # print the import information puts 'commit refs/heads/master' diff --git a/ko/09-git-internals/01-chapter9.markdown b/ko/09-git-internals/01-chapter9.markdown index fcf02085b..a30e480e8 100644 --- a/ko/09-git-internals/01-chapter9.markdown +++ b/ko/09-git-internals/01-chapter9.markdown @@ -453,7 +453,7 @@ Git은 zlib으로 파일 내용을 압축하기 때문에 저장 공간이 많 $ du -b .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e 4102 .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e -피일을 수정하면 어떻게 되는지 살펴보자: +파일을 수정하면 어떻게 되는지 살펴보자: $ echo '# testing' >> repo.rb $ git commit -am 'modified repo a bit' From a335b61402bc3d5a13b8615258a8478b593e483a Mon Sep 17 00:00:00 2001 From: Changwoo Park Date: Thu, 27 Mar 2014 05:52:25 +0900 Subject: [PATCH 2/3] [ko] remove a slang. --- ko/04-git-server/01-chapter4.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ko/04-git-server/01-chapter4.markdown b/ko/04-git-server/01-chapter4.markdown index 9917fd92b..1f57aa7b7 100644 --- a/ko/04-git-server/01-chapter4.markdown +++ b/ko/04-git-server/01-chapter4.markdown @@ -16,7 +16,7 @@ HTTP 프로토콜을 제외한 나머지들은 모두 Git이 서버에 설치돼 ### 로컬 프로토콜 ### -가장 기본적인 것이 _로컬 프로토콜_ 이다. 리모트 저장소가 단순히 디스크의 다른 디렉토리에 있을 때 사용한다. 팀원들이 전부 한 시스템에 로그인하여 개발하거나 아니면 NFS같은 것으로 파일시스템을 공유하고 있을 때 사용한다. 전자는 문제가 될 수 있다. 모든 저장소가 한 시스템에 있기 때문에 한순간에 찌질해질 수 있다. +가장 기본적인 것이 _로컬 프로토콜_ 이다. 리모트 저장소가 단순히 디스크의 다른 디렉토리에 있을 때 사용한다. 팀원들이 전부 한 시스템에 로그인하여 개발하거나 아니면 NFS같은 것으로 파일시스템을 공유하고 있을 때 사용한다. 전자는 문제가 될 수 있다. 모든 저장소가 한 시스템에 있기 때문에 한순간에 모두 잃을 수 있다. 공유 파일시스템을 마운트했을 때는 로컬 저장소를 사용하는 것처럼 Clone하고 Push하고 Pull하면 된다. 일단 저장소를 Clone하거나 프로젝트에 리모트 저장소로 추가한다. 추가할 때 URL 자리에 저장소의 경로를 사용한다. 예를 들어 아래와 같이 로컬 저장소를 Clone한다: From 766b4a0cb5c03d6539e955213eb57e4635a78cfa Mon Sep 17 00:00:00 2001 From: Changwoo Park Date: Sat, 31 May 2014 00:12:13 +0900 Subject: [PATCH 3/3] [ko] update translation --- ko/01-introduction/01-chapter1.markdown | 2 +- ko/02-git-basics/01-chapter2.markdown | 300 +++++++++++---------- ko/03-git-branching/01-chapter3.markdown | 92 ++++--- ko/04-git-server/01-chapter4.markdown | 50 ++-- ko/05-distributed-git/01-chapter5.markdown | 37 ++- ko/06-git-tools/01-chapter6.markdown | 40 ++- ko/07-customizing-git/01-chapter7.markdown | 12 +- 7 files changed, 298 insertions(+), 235 deletions(-) diff --git a/ko/01-introduction/01-chapter1.markdown b/ko/01-introduction/01-chapter1.markdown index a7a24715b..131e80efb 100644 --- a/ko/01-introduction/01-chapter1.markdown +++ b/ko/01-introduction/01-chapter1.markdown @@ -163,7 +163,7 @@ Ubuntu같은 데비안류 배포판에서는 apt-get을 사용한다: Mac에 Git을 쉽게 설치하는 방법은 두 가지가 있다. GUI 인스톨러가 가장 쉽게 사용할 수 있다. Google Code 페이지에서 내려받는다: - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png 그림 1-7. OS X Git 인스톨러 diff --git a/ko/02-git-basics/01-chapter2.markdown b/ko/02-git-basics/01-chapter2.markdown index 5bf08bdfa..61764f4ab 100644 --- a/ko/02-git-basics/01-chapter2.markdown +++ b/ko/02-git-basics/01-chapter2.markdown @@ -54,8 +54,8 @@ Insert 18333fig0201.png 파일의 상태를 확인하려면 보통 `git status` 명령을 사용한다. Clone한 후에 바로 이 명령을 실행하면 아래과 같은 메시지를 볼 수 있다: $ git status - # On branch master - nothing to commit (working directory clean) + On branch master + nothing to commit, working directory clean 위의 내용은 파일을 하나도 수정하지 않았다는 것을 말해준다. Tracked나 Modified 상태인 파일이 없다는 의미다. Untracked 파일은 아직 없어서 목록에 나타나지 않는다. 그리고 현재 작업 중인 브랜치를 알려준다. 기본 브랜치가 master이기 때문에 현재 master로 나오는 것이다. 브랜치 관련 내용은 차차 알아가자. 다음 장에서 브랜치와 레퍼런스에 대해 자세히 다룬다. @@ -63,11 +63,12 @@ Insert 18333fig0201.png $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) `README` 파일은 `Untracked files` 부분에 속해 있는데 이것은 `README` 파일이 Untracked 상태라는 것을 말한다. Git은 Untracked 파일을 아직 스냅샷(커밋)에 넣어지지 않은 파일이라고 본다. 파일이 Tracked 상태가 되기 전까지는 Git은 절대 그 파일을 커밋하지 않는다. 그래서 일하면서 생성하는 바이너리 파일 같은 것을 커밋하는 실수는 하지 않게 된다. README 파일을 추가해서 직접 Tracked 상태로 만들어 보자. @@ -81,12 +82,12 @@ Insert 18333fig0201.png `git status` 명령을 다시 실행하면 README 파일이 Tracked 상태이면서 Staged 상태라는 것을 확인할 수 있다: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + 'Changes to be committed' 에 들어 있는 파일은 Staged 상태라는 것을 의미한다. 커밋하면 `git add`를 실행한 시점의 파일이 커밋되어 저장소 히스토리에 남는다. 앞에서 `git init` 명령을 실행했을 때, 그 다음 `git add (files)` 명령을 실행했던 걸 기억할 것이다. 이것은 작업 디렉토리에 있는 파일들을 추적하기 시작하게 하였다. `git add` 명령은 파일 또는 디렉토리의 경로명을 아규먼트로 받는다; 만일 디렉토리를 아규먼트로 줄 경우, 그 디렉토리 아래에 있는 모든 파일들을 재귀적으로 추가한다. @@ -95,58 +96,59 @@ Insert 18333fig0201.png 이미 Tracked 상태인 파일을 수정하는 법을 알아보자. `benchmarks.rb`라는 파일을 수정하고 나서 `git status` 명령을 다시 실행하면 결과는 아래와 같다: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + 이 `benchmarks.rb` 파일은 `Changes not staged for commit`에 있다. 이것은 수정한 파일이 Tracked 상태이지만 아직 Staged 상태는 아니라는 것이다. Staged 상태로 만들려면 `git add` 명령을 실행해야 한다. `git add`는 파일을 새로 추적할 때도 사용하고 수정한 파일을 Staged 상태로 만들 때도 사용한다. `git add`를 실행하여 benchmarks.rb 파일을 Staged 상태로 만들고 `git status` 명령으로 결과를 확인해보자: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + 두 파일 모두 Staged 상태이므로 다음 커밋에 포함된다. 하지만, 아직 더 수정해야 한다는 것을 알게 되어 바로 커밋하지 못하는 상황이 되었다고 하자. 이 상황에서 benchmark.rb 파일을 열고 수정한다. 아마 당신은 커밋할 준비가 다 됐다고 생각할 테지만, Git은 그렇지 않다. `git status` 명령으로 파일의 상태를 다시 확인해보자: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + + modified: benchmarks.rb + 헉! benchmarks.rb가 Staged 상태이면서 동시에 Unstaged 상태로 나온다. 어떻게 이런 일이 가능할까? `git add` 명령을 실행하면 Git은 파일을 바로 Staged 상태로 만든다. 지금 이 시점에서 커밋을 하면 `git commit` 명령을 실행하는 시점의 버전이 커밋되는 것이 아니라 마지막으로 `git add` 명령을 실행했을 때의 버전이 커밋된다. 그러니까 `git add` 명령을 실행한 후에 또 파일을 수정하면 `git add` 명령을 다시 실행해서 최신 버전을 Staged 상태로 만들어야 한다: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### 파일 무시하기 ### @@ -192,17 +194,18 @@ Glob 패턴은 정규표현식을 단순하게 만든 것으로 생각하면 되 README 파일을 수정해서 Staged 상태로 만들고 benchmarks.rb 파일은 그냥 수정만 해둔다. 이 상태에서 `git status` 명령을 실행하면 아래와 같은 메시지를 볼 수 있다: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + `git diff` 명령을 실행하면 수정했지만 아직 staged 상태가 아닌 파일을 비교해 볼 수 있다: @@ -247,16 +250,18 @@ benchmarks.rb 파일을 Stage한 후에 다시 수정해도 `git diff` 명령을 $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + `git diff` 명령으로 Unstaged 상태인 변경 부분을 확인해 볼 수 있다: @@ -305,10 +310,9 @@ Git 설정에 지정된 편집기가 실행되고, 아래와 같은 텍스트가 # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ @@ -319,8 +323,8 @@ Git 설정에 지정된 편집기가 실행되고, 아래와 같은 텍스트가 메시지를 인라인으로 첨부할 수도 있다. `commit` 명령을 실행할 때 아래와 같이 `-m` 옵션을 사용한다: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Story 182: Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README `commit` 명령은 몇 가지 정보를 출력하는데 위 예제는 master 브랜치에 커밋했고 체크섬은 `463dc4f`이라고 알려준다. 그리고 수정한 파일이 몇 개이고 삭제됐거나 추가된 줄이 몇 줄인지 알려준다. @@ -332,15 +336,17 @@ Git은 Staging Area에 속한 스냅샷을 커밋한다는 것을 기억해야 Staging Area는 커밋할 파일을 정리한다는 점에서 매우 유용하지만 복잡하기만 하고 필요하지 않은 때도 있다. 아주 쉽게 Staging Area를 생략할 수 있다. `git commit` 명령을 실행할 때 `-a` 옵션을 추가하면 Git은 Tracked 상태의 파일을 자동으로 Staging Area에 넣는다. 그래서 `git add` 명령을 실행하는 수고를 덜 수 있다: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) 이 예제에서는 커밋하기 전에 `git add` 명령으로 benchmarks.rb 파일을 추가하지 않았다는 점을 눈여겨보자. @@ -352,26 +358,26 @@ Git에서 파일을 제거하려면 `git rm` 명령으로 Tracked 상태의 파 $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") 그리고 `git rm` 명령을 실행하면 삭제한 파일은 staged 상태가 된다: $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + deleted: grit.gemspec + 커밋하면 파일은 삭제되고 Git은 이 파일을 더는 추적하지 않는다. 이미 파일을 수정했거나 Index에(역주, Staging Area을 Git Index라고도 부른다) 추가했다면 `-f`옵션을 주어 강제로 삭제해야 한다. 이 점은 실수로 데이터를 삭제하지 못하도록 하는 안전장치다. 한 번도 커밋한적 없는 데이터는 Git으로 복구할 수 없다. @@ -401,14 +407,12 @@ Git은 다른 VCS 시스템과는 달리 파일 이름의 변경이나 파일의 $ git mv README.txt README $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README.txt -> README + 사실 `git mv` 명령은 아래 명령어들을 수행한 것과 완전히 똑같다: @@ -525,7 +529,7 @@ Git은 다른 VCS 시스템과는 달리 파일 이름의 변경이나 파일의 changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -534,7 +538,7 @@ Git은 다른 VCS 시스템과는 달리 파일 이름의 변경이나 파일의 removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -545,7 +549,7 @@ Git은 다른 VCS 시스템과는 달리 파일 이름의 변경이나 파일의 README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) 이 결과에서 `--stat` 옵션은 어떤 파일이 수정됐는지, 얼마나 많은 파일이 변경됐는지, 또 얼마나 많은 줄을 추가하거나 삭제했는지 보여준다. 요약정보는 가장 뒤쪽에 보여준다. @@ -633,7 +637,9 @@ The lines must be formatted as follows 이 옵션은 다양한 형식을 지원한다. `2008-01-15`같이 정확한 날짜도 사용할 수 있고 `2 years 1 day 3 minutes ago`같이 상대적인 기간을 사용할 수도 있다. -또 다른 기준도 있다. `--author` 옵션으로 저자를 지정하여 검색할 수도 있고 `--grep` 옵션으로 커밋 메시지에서 키워드를 검색할 수도 있다(author와 grep 옵션을 나눠서 지정하고 싶지 않으면 `--all-match` 옵션으로 한 번에 검색할 수 있다). +또 다른 기준도 있다. `--author` 옵션으로 저자를 지정하여 검색할 수도 있고 `--grep` 옵션으로 커밋 메시지에서 키워드를 검색할 수도 있다(author와 grep 옵션을 함께 사용하면 모두 만족하는 커밋을 찾는다). + +grep 옵션을 여러개 사용하면 그중 하나이상 만족하는 커밋을 찾는다. 모두 만족하는 커밋을 찾으려면 `--all-match` 옵션을 추가해야 한다. 마지막으로 파일 경로로 검색하는 옵션이 있는데 이것도 정말 유용하다. 디렉토리나 파일 이름을 사용하여 그 파일이 변경된 log의 결과를 검색할 수 있다. 이 옵션은 `--`와 함께 경로 이름을 사용하는데 명령어 끝 부분에 쓴다(역주, `git log -- path1 path2`). @@ -701,31 +707,32 @@ Insert 18333fig0202.png $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + `Changes to be commited` 밑에 `git reset HEAD ...`이라는 문장을 볼 수 있다. 이 명령으로 Unstage 상태로 변경할 수 있다. benchmarks.rb 파일을 Unstage 상태로 변경해보자: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + 명령어가 낮설게 느껴질 수도 있지만 잘 동작한다. benchmarks.rb 파일은 Unstage 상태가 됐다. @@ -733,23 +740,23 @@ Insert 18333fig0202.png 어떻게 해야 benchmarks.rb 파일을 수정하고 나서 다시 되돌릴 수 있을까? 그러니까 최근 커밋된 버전으로(아니면 처음 Clone했을 때처럼 워킹 디렉토리에 처음 Checkout 한 그 내용으로) 되돌리는 방법이 무얼까? `git status` 명령이 친절하게 알려준다. 바로 위에 있는 예제에서 Unstaged 부분을 보자: - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + 위의 메시지는 수정한 파일을 되돌리는 방법을 꽤 정확하게 알려준다(적어도 Git 1.6.1이후 버전부터는 그렇다. 만약 예전 것을 아직 사용하고 있으면 업그레드하는 것이 좋다. 편의성이 많이 개선됐다). 알려주는 대로 한 번 해보자: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + 정상적으로 복원된 것을 알 수 있다. 하지만 이 명령은 꽤 위험한 명령이라는 것을 알아야 한다. 수정 이전의 파일로 덮어썼기 때문에 수정했던 내용은 전부 사라진다. 수정한 내용이 진짜 마음에 들지 않을 때에만 사용하자. 정말 이렇게 삭제해야 한다면 Stash와 Branch를 사용하자. 다음 장에서 다루는 이 방법들이 훨씬 낫다. @@ -764,12 +771,12 @@ Git으로 커밋한 모든 것은 언제나 복구할 수 있다. 삭제한 브 `git remote` 명령으로 현재 프로젝트에 등록된 리모트 저장소를 확인할 수 있다. 이 명령은 리모트 저장소의 단축 이름을 보여준다. 저장소를 Clone하면 origin이라는 리모트 저장소가 자동으로 등록되기 때문에 origin이라는 이름을 볼 수 있다: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -942,6 +949,7 @@ Annotated 태그를 만드는 방법은 간단하다. `tag` 명령을 실행할 Date: Mon Feb 9 14:45:11 2009 -0800 my version 1.4 + commit 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge: 4a447f7... a6b4c97... Author: Scott Chacon diff --git a/ko/03-git-branching/01-chapter3.markdown b/ko/03-git-branching/01-chapter3.markdown index cf5dade52..6b52978ce 100644 --- a/ko/03-git-branching/01-chapter3.markdown +++ b/ko/03-git-branching/01-chapter3.markdown @@ -104,7 +104,7 @@ Insert 18333fig0309.png 이때 중요한 문제가 생겨서 그것을 해결하는 Hotfix를 먼저 만들어야 한다. 그러면 다음과 같이 할 수 있다: -1. 새로운 이슈를 처리하기 이전의 운영(Production) 브랜치로 복원. +1. 새로운 이슈를 처리하기 이전의 운영(Production) 브랜치로 이동. 2. Hotfix 브랜치를 새로 하나 생성. 3. 수정한 Hotfix 테스트를 마치고 운영 브랜치로 Merge. 4. 다시 작업하던 브랜치로 옮겨가서 하던 일 진행. @@ -154,8 +154,8 @@ hotfix라는 브랜치를 만들고 새로운 이슈를 해결할 때까지 사 Switched to a new branch 'hotfix' $ vim index.html $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: 'fixed the broken email address' - 1 files changed, 0 insertions(+), 1 deletions(-) + [hotfix 3a0874c] fixed the broken email address + 1 files changed, 1 deletion(-) Insert 18333fig0313.png 그림 3-13. master 브랜치에서 갈라져 나온 hotfix 브랜치 @@ -165,11 +165,11 @@ Insert 18333fig0313.png $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) -Merge 메시지에서 'Fast forward'가 보이는가? Merge할 브랜치가 가리키고 있던 커밋이 현 브랜치가 가리키는 것보다 '앞으로 진행한' 커밋이기 때문에 master 브랜치 포인터는 최신 커밋으로 이동한다. 이런 Merge 방식을 'Fast forward'라고 부른다. 다시 말해서 A 브랜치에서 다른 B 브랜치를 Merge할 때 B가 A 이후의 커밋을 가리키고 있으면 그저 A가 B의 커밋을 가리키게 할 뿐이다. +Merge 메시지에서 'Fast-forward'가 보이는가? Merge할 브랜치가 가리키고 있던 커밋이 현 브랜치가 가리키는 것보다 '앞으로 진행한' 커밋이기 때문에 master 브랜치 포인터는 최신 커밋으로 이동한다. 이런 Merge 방식을 'Fast forward'라고 부른다. 다시 말해서 A 브랜치에서 다른 B 브랜치를 Merge할 때 B가 A 이후의 커밋을 가리키고 있으면 그저 A가 B의 커밋을 가리키게 할 뿐이다. 이제 hotfix는 master 브랜치에 포함됐고 운영환경에 적용할 수 있다(그림 3-14). @@ -179,7 +179,7 @@ Insert 18333fig0314.png 문제를 급히 해결하고 master 브랜치에 적용하고 나면 다시 일하던 브랜치로 돌아가야 한다. 하지만, 그전에 필요없는 hotfix 브랜치를 삭제한다. `git branch` 명령에 `-d` 옵션을 주고 브랜치를 삭제한다. $ git branch -d hotfix - Deleted branch hotfix (3a0874c). + Deleted branch hotfix (was 3a0874c). 자 이제 이슈 53번을 처리하던 환경으로 되돌아가서 하던 일을 계속 하자(그림 3-15): @@ -187,8 +187,8 @@ Insert 18333fig0314.png Switched to branch 'iss53' $ vim index.html $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: 'finished the new footer [issue 53]' - 1 files changed, 1 insertions(+), 0 deletions(-) + [iss53 ad82d7a] finished the new footer [issue 53] + 1 file changed, 1 insertion(+) Insert 18333fig0315.png 그림 3-15. master와 별개로 진행하는 iss53 브랜치 @@ -201,9 +201,10 @@ Insert 18333fig0315.png $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) hotfix를 Merge했을 때와 메시지가 다르다. 현 브랜치가 가리키는 커밋이 Merge할 브랜치의 조상이 아니므로 Git은 'Fast-forward'로 Merge하지 않는다. 이러면 Git은 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용하여 3-way Merge를 한다. 그림 3-16에 이 Merge에서 사용하는 커밋 세 개가 표시된다. @@ -232,25 +233,27 @@ iss53 브랜치를 master에 Merge하고 나면 더는 iss53 브랜치가 필요 Git은 자동으로 Merge하지 못해서 새 커밋이 생기지 않는다. 변경사항의 충돌을 개발자가 해결하지 않는 한 Merge 과정을 진행할 수 없다. Merge 충돌이 일어났을 때 Git이 어떤 파일을 Merge할 수 없었는지 살펴보려면 `git status` 명령을 이용한다: - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use 'git add ...' to update what will be committed) - # (use 'git checkout -- ...' to discard changes in working directory) - # - # unmerged: index.html - # + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") 충돌이 일어난 파일은 unmerged 상태로 표시된다. Git은 충돌이 난 부분을 표준 형식에 따라 표시해준다. 그러면 개발자는 해당 부분을 수동으로 해결한다. 충돌 난 부분은 다음과 같이 표시된다. - <<<<<<< HEAD:index.html + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 `=======` 위쪽의 내용은 HEAD 버전(merge 명령을 실행할 때 작업하던 master 브랜치)의 내용이고 아래쪽은 iss53 브랜치의 내용이다. 충돌을 해결하려면 위쪽이나 아래쪽 내용 중에서 고르거나 새로 작성하여 Merge한다. 다음은 아예 새로 작성하여 충돌을 해결하는 예제다: @@ -261,27 +264,32 @@ Git은 자동으로 Merge하지 못해서 새 커밋이 생기지 않는다. 변 충돌한 양쪽에서 조금씩 가져와서 새로 수정했다. 그리고 `<<<<<<<`, `=======`, `>>>>>>>` 가 포함된 행을 삭제하였다. 이렇게 충돌한 부분을 해결하고 `git add` 명령으로 다시 Git에 저장한다. 충돌을 쉽게 해결하기 위해 다른 Merge 도구도 이용할 수 있다. `git mergetool` 명령으로 실행한다: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): -Mac에서는 `opendiff`가 실행된다. 기본 도구 말고 사용할 수 있는 다른 Merge 도구도 있는데, 'merge tool candidates' 부분에 보여준다. 여기에 표시된 도구 중 하나를 고를 수 있다. Merge 도구를 변경하는 방법은 *7장*에서 다룬다. +Mac에서는 `opendiff`가 실행된다. 기본 도구 말고 사용할 수 있는 다른 Merge 도구도 있는데, "... one of the following tools:" 부분에 보여준다. 여기에 표시된 도구 중 하나를 고를 수 있다. Merge 도구를 변경하는 방법은 *7장*에서 다룬다. Merge 도구를 종료하면 Git은 잘 Merge했는지 물어본다. 잘 마쳤다고 입력하면 자동으로 `git add`가 수행되고 해당 파일이 Staging Area에 저장된다. `git status` 명령으로 충돌이 해결된 상태인지 다시 한번 확인해볼 수 있다. $ git status - # On branch master - # Changes to be committed: - # (use 'git reset HEAD ...' to unstage) - # - # modified: index.html - # + On branch master + Changes to be committed: + (use 'git reset HEAD ...' to unstage) + + modified: index.html + 충돌을 해결하고 나서 해당 파일이 Staging Area에 저장됐는지 확인했으면 `git commit` 명령으로 Merge 한 것을 커밋한다. 충돌을 해결하고 Merge할 때에는 커밋 메시지가 아래와 같다. @@ -290,9 +298,9 @@ Merge 도구를 종료하면 Git은 잘 Merge했는지 물어본다. 잘 마쳤 Conflicts: index.html # - # It looks like you may be committing a MERGE. + # It looks like you may be committing a merge. # If this is not correct, please remove the file - # .git/MERGE_HEAD + # .git/MERGE_HEAD # and try again. # @@ -332,7 +340,7 @@ iss53 브랜치는 앞에서 이미 Merge했기 때문에 목록에 나타난다 위에는 없었던 다른 브랜치가 보인다. 아직 Merge하지 않은 커밋을 담고 있기 때문에 `git branch -d` 명령으로 삭제되지 않는다: $ git branch -d testing - error: The branch 'testing' is not an ancestor of your current HEAD. + error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'. Merge하지 않은 브랜치를 강제로 삭제하려면 `-D` 옵션으로 삭제한다. @@ -445,7 +453,7 @@ Git은 serverfix라는 브랜치 이름을 `refs/heads/serverfix:refs/heads/serv 새로 받은 브랜치의 내용을 Merge하려면 `git merge origin/serverfix` 명령을 사용한다. Merge하지 않고 리모트 브랜치에서 시작하는 새 브랜치를 만들려면 아래와 같은 명령을 사용한다. $ git checkout -b serverfix origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. + Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' 그러면 origin/serverfix에서 시작하고 수정할 수 있는 serverfix라는 로컬 브랜치가 만들어진다. @@ -457,16 +465,16 @@ Git은 serverfix라는 브랜치 이름을 `refs/heads/serverfix:refs/heads/serv 서버로부터 저장소를 Clone해올 때도 Git은 자동으로 master 브랜치를 origin/master 브랜치의 트래킹 브랜치로 만든다. 그래서 `git push`, `git pull` 명령이 추가적인 아규먼트 없이도 동작한다. 트래킹 브랜치를 직접 만들 수 있는데 origin/master뿐만 아니라 다른 저장소의 다른 브랜치도 추적하게(Tracking) 할 수 있다. `git checkout -b [branch] [remotename]/[branch]` 명령으로 간단히 트래킹 브랜치를 만들 수 있다. Git 1.6.2 버전 이상을 사용하는 경우에는 --track 옵션도 사용할 수 있다. $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. + Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix' 리모트 브랜치와 다른 이름으로 브랜치를 만들려면 로컬 브랜치의 이름을 아래와 같이 다르게 지정한다: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. + Branch sf set up to track remote branch serverfix from origin. Switched to a new branch 'sf' -이제 sf 브랜치에서 Push나 Pull하면 자동으로 origin/serverfix에 데이터를 보내거나 가져온다. +이제 `sf` 브랜치에서 Push나 Pull하면 자동으로 `origin/serverfix`에 데이터를 보내거나 가져온다. ### 리모트 브랜치 삭제 ### diff --git a/ko/04-git-server/01-chapter4.markdown b/ko/04-git-server/01-chapter4.markdown index 1f57aa7b7..ff28be894 100644 --- a/ko/04-git-server/01-chapter4.markdown +++ b/ko/04-git-server/01-chapter4.markdown @@ -26,7 +26,7 @@ HTTP 프로토콜을 제외한 나머지들은 모두 Git이 서버에 설치돼 $ git clone file:///opt/git/project.git -Git은 파일 경로를 직접 쓸 때와 `file://`로 시작하는 URL을 사용할 때에 약간 다르게 처리한다. 디렉토리 경로를 그대로 사용하면 Git은 필요한 파일을 직접 복사하거나 하드 링크를 사용한다. 하지만 `file://`로 시작하면 Git은 네트워크를 통해서 데이터를 전송할 때처럼 프로세스를 별도로 생성하여 처리한다. 이 프로세스로 데이터를 전송하는 것은 효율이 좀 떨어지지만 그래도 `file://`를 사용하는 이유가 있다. 보통은 다른 버전 관리 시스템들에서 임포트한 후에 이렇게 사용하는데, 외부 레퍼런스나 개체들이 포함된 저장소의 복사본을 깨끗한 상태로 남겨두고자 할때 사용한다(*9장*에서 자세히 다룬다). 여기서는 속도가 빠른 디렉토리 경로를 사용한다. +Git은 파일 경로를 직접 쓸 때와 `file://`로 시작하는 URL을 사용할 때에 약간 다르게 처리한다. 디렉토리 경로를 사용해서 같은 파일시스템에 있는 저장소를 Clone할 때 Git은 하드링크를 만든다. 같은 파일시스템에 있는게 아니면 그냥 복사한다. 하지만 `file://`로 시작하면 Git은 네트워크를 통해서 데이터를 전송할 때처럼 프로세스를 별도로 생성하여 처리한다. 이 프로세스로 데이터를 전송하는 것은 효율이 좀 떨어지지만 그래도 `file://`를 사용하는 이유가 있다. 보통은 다른 버전 관리 시스템들에서 임포트한 후에 이렇게 사용하는데, 외부 레퍼런스나 개체들이 포함된 저장소의 복사본을 깨끗한 상태로 남겨두고자 할때 사용한다(*9장*에서 자세히 다룬다). 여기서는 속도가 빠른 디렉토리 경로를 사용한다. 이미 있는 Git 프로젝트에서 아래와 같이 로컬 저장소를 추가한다: @@ -70,7 +70,7 @@ SSH의 단점은 익명으로 접근할 수 없다는 것이다. 심지어 읽 ### Git 프로토콜 ### -Git 프로토콜은 Git에 포함된 데몬을 사용하는 방법이다. 포트는 9418이며 SSH 프로토콜과 비슷한 서비스를 제공하지만, 인증 메커니즘이 없다. 저장소에 git-daemon-export-ok 파일을 만들면 Git 프로토콜로 서비스할 수 있지만, 보안은 없다. 이 파일이 없는 저장소는 Git 프로토콜로 서비스할 수 없다. 이 저장소는 누구나 Clone할 수 있거나 아무도 Clone할 수 없거나 둘 중의 하나만 선택할 수 있다. 그래서 이 프로토콜로는 Push 가능하게 설정할 수 없다. 엄밀히 말해서 Push할 수 있도록 설정할 수 있지만, 인증하도록 할 수 없다. 그러니까 당신이 Push할 수 있으면 이 프로젝트의 URL을 아는 사람은 누구나 Push할 수 있다. 그냥 이런 것도 있지만 잘 안 쓴다고 알고 있으면 된다. +Git 프로토콜은 Git에 포함된 데몬을 사용하는 방법이다. 포트는 9418이며 SSH 프로토콜과 비슷한 서비스를 제공하지만, 인증 메커니즘이 없다. 저장소에 git-export-daemon-ok 파일을 만들면 Git 프로토콜로 서비스할 수 있지만, 보안은 없다. 이 파일이 없는 저장소는 Git 프로토콜로 서비스할 수 없다. 이 저장소는 누구나 Clone할 수 있거나 아무도 Clone할 수 없거나 둘 중의 하나만 선택할 수 있다. 그래서 이 프로토콜로는 Push 가능하게 설정할 수 없다. 엄밀히 말해서 Push할 수 있도록 설정할 수 있지만, 인증하도록 할 수 없다. 그러니까 당신이 Push할 수 있으면 이 프로젝트의 URL을 아는 사람은 누구나 Push할 수 있다. 그냥 이런 것도 있지만 잘 안 쓴다고 알고 있으면 된다. #### 장점 #### @@ -115,7 +115,13 @@ HTTP는 매우 보편적인 프로토콜이라서 거의 모든 회사가 트래 어떤 서버를 설치하더라도 일단 저장소를 Bare 저장소로 만들어야 한다. 다시 말하지만, Bare 저장소는 워킹 디렉토리가 없는 저장소이다. `--bare` 옵션을 주고 Clone하면 새로운 Bare 저장소가 만들어진다. Bare 저장소 디렉토리는 관례에 따라. git 확장자로 끝난다: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. + + 이 명령이 출력하는 메시지가 조금 이상해보일 수도 있다. 사실 `git clone` 명령은 `git init`을 하고 나서 `git fetch`를 실행한다. 그런데 빈 디렉토리밖에 만들지 않는 `git init` 명령의 메시지만 보여준다. 개체 전송에 관련된 메시지는 아무것도 보여주지 않는다. 전송 메시지를 보여주지 않지만 `my_project.git` 디렉토리를 보면 Git 데이터가 들어 있다. @@ -282,6 +288,13 @@ something, something.pub이라는 형식으로 된 파일을 볼 수 있다. som $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info SSH를 통해서 서버에 Push하면 Git은 이 명령어를 실행하여 HTTP를 통해서도 Fetch할 수 있도록 파일를 갱신한다. @@ -363,7 +376,7 @@ Gitosis는 Python이 필요하기 때문에 먼저 Python setuptools 패키지 그리고 Gitosis 프로젝트 사이트에서 Gitosis를 Clone한 후 설치한다: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -397,6 +410,7 @@ Gitosis가 키들을 관리할 것이기 때문에 현재 파일은 삭제하고 $ ssh git@gitserver PTY allocation request failed on channel 0 + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. fatal: unrecognized command 'gitosis-serve schacon@quaternion' Connection to gitserver closed. @@ -421,8 +435,8 @@ Gitosis가 키들을 관리할 것이기 때문에 현재 파일은 삭제하고 [gitosis] [group gitosis-admin] - writable = gitosis-admin members = scott + writable = gitosis-admin scott이라는 사용자는 Gitosis를 초기화할 때 사용한 공개키의 사용자이다. 이 사용자만 `gitosis-admin` 프로젝트에 접근할 수 있다. @@ -435,14 +449,14 @@ scott이라는 사용자는 Gitosis를 초기화할 때 사용한 공개키의 `gitosis-admin` 프로젝트를 수정하면 커밋하고 서버에 Push해야 수정한 설정이 적용된다: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master 로컬에 있는 `iphone_project` 프로젝트에 이 서버를 리모트 저장소로 추가하고 Push하면 서버에 새로운 저장소가 추가된다. 서버에 프로젝트를 새로 만들 때 이제는 수동으로 Bare 저장소를 만들 필요가 없다. 처음 Push할 때 Gitosis가 알아서 생성해 준다: @@ -451,7 +465,7 @@ scott이라는 사용자는 Gitosis를 초기화할 때 사용한 공개키의 $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. +> Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master @@ -467,20 +481,20 @@ Gitosis를 이용할 때에는 저장소 경로를 명시할 필요도 없고 이 세 사람을 모두 mobile 팀으로 추가하여 `iphone_project` 에 대한 읽기, 쓰기를 허용한다: [group mobile] - writable = iphone_project members = scott john josie jessica + writable = iphone_project 이 파일을 커밋하고 Push하고 나면 네 명 모두 `iphone_project`를 읽고 쓸 수 있게 된다. Gitosis의 접근제어 방법은 매우 단순하다. 만약 이 프로젝트에 대해서 John은 읽기만 가능하도록 설정하려면 아래와 같이 한다: [group mobile] - writable = iphone_project members = scott josie jessica + writable = iphone_project [group mobile_ro] - readonly = iphone_project members = john + readonly = iphone_project 이제 John은 프로젝트를 Clone하거나 Fetch할 수는 있지만, 프로젝트에 Push할 수는 없다. 다양한 사용자와 프로젝트가 있어도 필요한 만큼 그룹을 만들어 사용하면 된다. 그리고 members 항목에 사용자 대신 그룹명을 사용할 수도 있다. 그룹명 앞에 `@`를 붙이면 그 그룹의 사용자를 그대로 상속한다: @@ -488,12 +502,12 @@ Gitosis의 접근제어 방법은 매우 단순하다. 만약 이 프로젝트 members = scott josie jessica [group mobile] - writable = iphone_project members = @mobile_committers + writable = iphone_project [group mobile_2] - writable = another_iphone_project members = @mobile_committers john + writable = another_iphone_project `[gitosis]` 절에 `loglevel=DEBUG`라고 적으면 문제가 생겼을 때 해결하는데 도움이 된다. 그리고 설정이 꼬여버려서 Push할 수 없게 되면 서버에 있는 파일을 수동으로 고쳐도 된다. Gitosis는 `/home/git/.gitosis.conf` 파일의 정보를 읽기 때문에 이 파일을 고친다. `gitosis.conf`는 Push할 때 그 위치로 복사되기 때문에 수동으로 고친 파일은 `gitosis-admin` 프로젝트가 다음에 Push될 때까지 유지된다. diff --git a/ko/05-distributed-git/01-chapter5.markdown b/ko/05-distributed-git/01-chapter5.markdown index 11ec5df3c..acbe5dc68 100644 --- a/ko/05-distributed-git/01-chapter5.markdown +++ b/ko/05-distributed-git/01-chapter5.markdown @@ -169,7 +169,7 @@ John씨는 Jessica씨가 저장소로 Push했던 커밋과 를 로컬 저장소 Merge가 잘 이루어지면 John씨의 브랜치는 그림 5-5와 같은 상태가 된다. Insert 18333fig0505.png -그림 5-5. origin/master 브랜치를 Merge하고 난 후, John씨의 저장소 +그림 5-5. `origin/master` 브랜치를 Merge하고 난 후, John씨의 저장소 John씨는 Merge하고 나서 자신이 작업한 코드가 제대로 동작하는지 확인한다. 그 후에 공유하는 저장소에 Push한다: @@ -210,13 +210,13 @@ Insert 18333fig0508.png removed invalid default value -Merge할 내용을 확인한 Jessica씨는 자신이 작업한 내용과 John씨가 Push한 작업(origin/master)을 master 브랜치에 Merge하고 Push한다. 모든 내용을 합치기 전에 우선 master 브랜치를 Checkout한다: +Merge할 내용을 확인한 Jessica씨는 자신이 작업한 내용과 John씨가 Push한 작업(`origin/master`)을 `master` 브랜치에 Merge하고 Push한다. 모든 내용을 합치기 전에 우선 `master` 브랜치를 Checkout한다: $ git checkout master Switched to branch "master" Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. -origin/master, issue54 모두 master보다 Fast-forward된 브랜치이기 때문에 둘 중에 무엇을 먼저 Merge하든 상관이 없다. 물론 어떤 것을 먼저 Merge하느냐에 따라 히스토리 순서는 달라지지만, 최종 결과는 똑같다. Jessica씨는 먼저 issue54 브랜치를 Merge한다: +`origin/master`, `issue54` 모두 `master`보다 Fast-forward된 브랜치이기 때문에 둘 중에 무엇을 먼저 Merge하든 상관이 없다. 물론 어떤 것을 먼저 Merge하느냐에 따라 히스토리 순서는 달라지지만, 최종 결과는 똑같다. Jessica씨는 먼저 `issue54` 브랜치를 Merge한다: $ git merge issue54 Updating fbff5bc..4af4298 @@ -225,7 +225,7 @@ origin/master, issue54 모두 master보다 Fast-forward된 브랜치이기 때 lib/simplegit.rb | 6 +++++- 2 files changed, 6 insertions(+), 1 deletions(-) -보다시피 Fast-forward Merge이기 때문에 별 문제 없이 실행된다. 다음은 John씨의 커밋(origin/master)을 Merge한다: +보다시피 Fast-forward Merge이기 때문에 별 문제 없이 실행된다. 다음은 John씨의 커밋(`origin/master`)을 Merge한다: $ git merge origin/master Auto-merging lib/simplegit.rb @@ -238,7 +238,7 @@ origin/master, issue54 모두 master보다 Fast-forward된 브랜치이기 때 Insert 18333fig0509.png 그림 5-9. Merge 이후 Jessica씨의 저장소 -origin/master 브랜치가 Jessica씨의 master 브랜치로 나아갈(reachable) 수 있기 때문에 Push는 성공한다(물론 John씨가 그 사이에 Push를 하지 않았다면): +`origin/master` 브랜치가 Jessica씨의 `master` 브랜치로 나아갈(reachable) 수 있기 때문에 Push는 성공한다(물론 John씨가 그 사이에 Push를 하지 않았다면): $ git push origin master ... @@ -250,7 +250,7 @@ origin/master 브랜치가 Jessica씨의 master 브랜치로 나아갈(reachable Insert 18333fig0510.png 그림 5-10. Jessica씨가 서버로 Push하고 난 후의 저장소 -여기서 살펴본 예제가 가장 간단한 상황이다. 토픽 브랜치에서 수정하고 로컬의 master 브랜치에 Merge한다. 작업한 내용을 프로젝트의 공유 저장소에 Push하고자 할 때에는 우선 origin/master 브랜치를 Fetch하고 Merge한다. 그리고 나서 Merge한 결과를 다시 서버로 Push한다. 이런 Workflow가 일반적이고 그림 5-11로 나타낼 수 있다. +여기서 살펴본 예제가 가장 간단한 상황이다. 토픽 브랜치에서 수정하고 로컬의 `master` 브랜치에 Merge한다. 작업한 내용을 프로젝트의 공유 저장소에 Push하고자 할 때에는 우선 `origin/master` 브랜치를 Fetch하고 Merge한다. 그리고 나서 Merge한 결과를 다시 서버로 Push한다. 이런 Workflow가 일반적이고 그림 5-11로 나타낼 수 있다. Insert 18333fig0511.png 그림 5-11. 여러 개발자가 Git을 사용하는 Workflow @@ -518,7 +518,7 @@ format-patch 명령을 실행하면 생성한 파일 이름을 보여준다. -M 다행히 Git에는 Patch 메일을 그대로 보낼 수 있는 도구가 있다. IMAP 프로토콜로 보낸다. 저자가 사용하는 방법으로 Gmail을 사용하여 Patch 메일을 전송하는 방법을 살펴보자. 추가로 Git 프로젝트의 `Documentation/SubmittingPatches` 문서의 마지막 부분을 살펴보면 다양한 메일 프로그램으로 메일을 보내는 방법을 설명한다. -메일을 보내려면 먼저 ~/.gitconfig 파일에서 이메일 부분 설정한다. `git config` 명령으로 추가할 수도 있고 직접 파일을 열어서 추가할 수도 있다. 아무튼, 아래와 같이 설정을 한다: +메일을 보내려면 먼저 `~/.gitconfig` 파일에서 이메일 부분 설정한다. `git config` 명령으로 추가할 수도 있고 직접 파일을 열어서 추가할 수도 있다. 아무튼, 아래와 같이 설정을 한다: [imap] folder = "[Gmail]/Drafts" @@ -528,7 +528,26 @@ format-patch 명령을 실행하면 생성한 파일 이름을 보여준다. -M port = 993 sslverify = false -IMAP 서버가 SSL을 사용하지 않으면 마지막 두 줄은 필요 없고 host에서 `imaps://` 대신 `imap://`로 한다. 이렇게 설정하면 `git send-email` 명령으로 메일을 전송할 수 있다: +IMAP 서버가 SSL을 사용하지 않으면 마지막 두 줄은 필요 없고 host에서 `imaps://` 대신 `imap://`로 한다. 이렇게 설정하면 `git imap-send` 명령으로 메일을 전송할 수 있다: + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + +이후 Gmail의 Draft 폴더로 가서 To 부분을 메일링리스트의 주소로 변경하고 CC 부분에 해당 메일을 참고해야 하는 관리자나 개발자의 메일 주소를 적고 실제로 전송한다. + +SMTP 서버로도 패치를 보낼 수 있다. `git config` 명령으로 설정을 하나씩 입력하거나 `~/.gitconfig` 파일의 sendmail 부분을 손으로 직접 수정한다: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + +이렇게 했으면 `git send-mail`로 패치를 보낸다: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -555,8 +574,6 @@ Git으로 메일을 보내면 아래와 같은 로그 메시지가 출력된다: Result: OK -이후 Gmail의 Draft 폴더로 가서 To 부분을 메일링리스트의 주소로 변경하고 CC 부분에 해당 메일을 참고해야 하는 관리자나 개발자의 메일 주소를 적고 실제로 전송한다. - ### 요약 ### 이번 절에서는 다양한 Workflow에 따라 Git을 어떻게 사용하는 지 살펴보고 그에 필요한 도구들을 설명했다. 다음 절에서는 동전의 뒷면인 프로젝트를 운영하는 방법에 대하여 살펴본다. 즉 친절한 Dictator나 Integration-Manager가 되어 보는 것이다. diff --git a/ko/06-git-tools/01-chapter6.markdown b/ko/06-git-tools/01-chapter6.markdown index af810484d..231d2dc8c 100644 --- a/ko/06-git-tools/01-chapter6.markdown +++ b/ko/06-git-tools/01-chapter6.markdown @@ -82,13 +82,13 @@ Git은 자동으로 브랜치와 HEAD가 지난 몇 달 동안에 가리켰었 `git reflog`를 실행하면 Reflog를 볼 수 있다: $ git reflog - 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated - d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive. - 1c002dd... HEAD@{2}: commit: added some blame and merge stuff - 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD - 95df984... HEAD@{4}: commit: # This is a combination of two commits. - 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD - 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD + 734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated + d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive. + 1c002dd HEAD@{2}: commit: added some blame and merge stuff + 1c36188 HEAD@{3}: rebase -i (squash): updating HEAD + 95df984 HEAD@{4}: commit: # This is a combination of two commits. + 1c36188 HEAD@{5}: rebase -i (squash): updating HEAD + 7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD Git은 브랜치가 가리키는 것이 변경될 때마다 그 정보를 임시 영역에 저장한다. 그래서 예전에 뭘 가리켰었는지 확인할 수 있다. `@{n}` 규칙을 사용하면 아래와 같이 HEAD가 5번 전에 가리켰던 것을 알 수 있다: @@ -442,8 +442,8 @@ Stash 명령을 사용하면 워킹 디렉토리에서 수정한 파일만 저 $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log Stash 두 개는 원래 있었던 것이다. 그래서 현재 총 세 개의 Stash를 사용할 수 있다. 이제 `git stash apply`를 사용하여 Stash를 적용할 수 있다. `git stash` 명령을 실행하면 이 명령에 대한 도움말을 보여주기 때문에 편리하다. 다른 Stash를 고르고 싶으면 Stash 이름을 입력해야 한다. 이름이 없으면 Git은 가장 최근의 Stash를 적용한다: @@ -477,8 +477,8 @@ Git은 Stash를 적용할 때 Staged 상태였던 파일을 자동으로 다시 $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log $ git stash drop stash@{0} Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43) @@ -562,12 +562,19 @@ Git으로 일하다 보면 어떤 이유로든 커밋 히스토리를 수정해 # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out 이 커밋은 모두 `log` 명령과는 정반대의 순서로 나열된다. `log` 명령을 실행하면 아래와 같은 결과를 볼 수 있다: @@ -586,6 +593,10 @@ Git으로 일하다 보면 어떤 이유로든 커밋 히스토리를 수정해 저장하고 편집기를 종료하면 Git은 목록에 있는 커밋 중에서 가장 오래된 커밋으로 이동하고, 아래와 같은 메시지를 보여주고, 명령 프롬프트를 보여준다: + + $ git rebase -i HEAD~3 Stopped at 7482e0d... updated the gemspec to hopefully work better You can amend the commit now, with @@ -628,12 +639,19 @@ Git으로 일하다 보면 어떤 이유로든 커밋 히스토리를 수정해 # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out "pick"이나 "edit"말고 "squash"를 입력하면 Git은 해당 커밋과 바로 이전 커밋을 합칠 것이고 커밋 메시지도 Merge한다. 그래서 3개의 커밋을 모두 합치려면 스크립트를 아래와 같이 수정한다: diff --git a/ko/07-customizing-git/01-chapter7.markdown b/ko/07-customizing-git/01-chapter7.markdown index 8e363021f..901c2d27c 100644 --- a/ko/07-customizing-git/01-chapter7.markdown +++ b/ko/07-customizing-git/01-chapter7.markdown @@ -612,14 +612,12 @@ update 스크립트는 각 브랜치마다 한 번씩 실행된다는 것을 제 #!/usr/bin/env ruby - $refname = ARGV[0] - $oldrev = ARGV[1] - $newrev = ARGV[2] - $user = ENV['USER'] - - puts "Enforcing Policies... \n(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})" + refname = ARGV[0] + oldrev = ARGV[1] + newrev = ARGV[2] + user = ENV['USER'] -쉽게 설명하기 위해 전역 변수를 사용했다. 비판하지 말기 바란다. + puts "Enforcing Policies... \n(#{refname}) (#{oldrev[0,6]}) (#{newrev[0,6]})" #### 커밋 메시지 규칙 만들기 ####