From 7558c04c3bd1dbd32cb5c4288a632279074bf93f Mon Sep 17 00:00:00 2001 From: Sean Lee Date: Thu, 5 Mar 2015 19:47:43 +0900 Subject: [PATCH 1/5] chapter 8: translate --- book/08-customizing-git/1-customizing-git.asc | 16 + .../sections/attributes.asc | 204 ++++++++++++- book/08-customizing-git/sections/config.asc | 283 ++++++++++++++++++ book/08-customizing-git/sections/hooks.asc | 128 +++++++- book/08-customizing-git/sections/policy.asc | 210 +++++++++++++ 5 files changed, 838 insertions(+), 3 deletions(-) diff --git a/book/08-customizing-git/1-customizing-git.asc b/book/08-customizing-git/1-customizing-git.asc index 333ad16a..49babcad 100644 --- a/book/08-customizing-git/1-customizing-git.asc +++ b/book/08-customizing-git/1-customizing-git.asc @@ -1,9 +1,17 @@ [[_customizing_git]] +////////////////////////// == Customizing Git +////////////////////////// +== Git맞춤 +////////////////////////// So far, we've covered the basics of how Git works and how to use it, and we've introduced a number of tools that Git provides to help you use it easily and efficiently. In this chapter, we'll see how you can make Git operate in a more customized fashion, by introducing several important configuration settings and the hooks system. With these tools, it's easy to get Git to work exactly the way you, your company, or your group needs it to. +////////////////////////// +지금까지 Git이 어떻게 동작하고 Git을 어떻게 사용하는지 설명했다. 이제 Git을 좀 더 쉽고 편하게 사용할 수 있도록 도와주는 도구를 살펴본다. +이 장에서는 먼저 많이 쓰이는 설정 그리고 훅 시스템을 먼저 설명한다. 그 후에 Git을 내게 맞추어(Customize) 본다. +Git을 자신의 프로젝트에 맞추고 편하게 사용하자. include::sections/config.asc[] @@ -13,8 +21,16 @@ include::sections/hooks.asc[] include::sections/policy.asc[] +////////////////////////// === Summary +////////////////////////// +=== 요약 +////////////////////////// We've covered most of the major ways that you can customize your Git client and server to best fit your workflow and projects. You've learned about all sorts of configuration settings, file-based attributes, and event hooks, and you've built an example policy-enforcing server. You should now be able to make Git fit nearly any workflow you can dream up. +////////////////////////// +Git을 프로젝트에 맞추는 방법을 배웠다. +주요한 서버/클라이언트 설정 방법, 파일 단위로 설정하는 Git Attributes, 이벤트 훅, 정책을 강제하는 방법을 배웠다. +이제 필요한 Workflow를 만들고 Git을 거기에 맞게 설정할 수 있을 것이다. diff --git a/book/08-customizing-git/sections/attributes.asc b/book/08-customizing-git/sections/attributes.asc index 5c7b3aae..eebf8577 100644 --- a/book/08-customizing-git/sections/attributes.asc +++ b/book/08-customizing-git/sections/attributes.asc @@ -1,45 +1,90 @@ === Git Attributes (((attributes))) +////////////////////////// Some of these settings can also be specified for a path, so that Git applies those settings only for a subdirectory or subset of files. These path-specific settings are called Git attributes and are set either in a `.gitattributes` file in one of your directories (normally the root of your project) or in the `.git/info/attributes` file if you don't want the attributes file committed with your project. +////////////////////////// +디렉토리와 파일 단위로 다른 설정을 적용할 수도 있다. 이렇게 경로별로 설정하는 것을 Git Attribute 라고 부른다. +이 설정은 `.gitattributes`라는 파일에 저장하고 아무 디렉토리에나 둘 수 있지만, 보통은 프로젝트 최상위 디렉토리에 둔다. 그리고 이 파일을 커밋하고 싶지 않으면 `.gitattributes`가 아니라 `.git/info/attributes`로 파일을 만든다. +////////////////////////// Using attributes, you can do things like specify separate merge strategies for individual files or directories in your project, tell Git how to diff non-text files, or have Git filter content before you check it into or out of Git. In this section, you'll learn about some of the attributes you can set on your paths in your Git project and see a few examples of using this feature in practice. +////////////////////////// +이 Attribute로 Merge는 어떻게 할지, 텍스트가 아닌 파일은 어떻게 Diff할지, checkin/checkout할 때 어떻게 필터링할지 정해줄 수 있다. +이 절에서는 설정할 수 있는 Attribute가 어떤 것이 있는지, 그리고 어떻게 설정하는지 배우고 예제를 살펴본다. +////////////////////////// ==== Binary Files +////////////////////////// +==== 바이너리 파일 (((binary files))) +////////////////////////// One cool trick for which you can use Git attributes is telling Git which files are binary (in cases it otherwise may not be able to figure out) and giving Git special instructions about how to handle those files. For instance, some text files may be machine generated and not diffable, whereas some binary files can be diffed. You'll see how to tell Git which is which. +////////////////////////// +이 Attribute로 어떤 파일이 바이너리 파일인지 Git에게 알려줄 수 있다. 기본적으로 Git은 어떤 파일이 바이너리 파일인지 알지 못한다. 하지만, Git에는 파일을 어떻게 다뤄야 하는지 알려주는 방법이 있다. +텍스트 파일 중에서 프로그램이 생성하는 파일에는 바이너리 파일과 진배없는 파일이 있다. 이런 파일은 diff할 수 없으니 바이너리 파일이라고 알려줘야 한다. 반대로 바이너리 파일 중에서 취급 방법을 Git에 알려주면 diff할 수 있는 파일도 있다. +이어지는 내용으로 어떻게 설정할 수 있는지 살펴보자. +////////////////////////// ===== Identifying Binary Files +////////////////////////// +===== 바이너리 파일로 설정 +////////////////////////// Some files look like text files but for all intents and purposes are to be treated as binary data. For instance, Xcode projects on the Mac contain a file that ends in `.pbxproj`, which is basically a JSON (plain-text Javascript data format) dataset written out to disk by the IDE, which records your build settings and so on. Although it's technically a text file (because it's all UTF-8), you don't want to treat it as such because it's really a lightweight database – you can't merge the contents if two people change it, and diffs generally aren't helpful. The file is meant to be consumed by a machine. In essence, you want to treat it like a binary file. - +////////////////////////// +사실 텍스트 파일이지만 만든 목적과 의도를 보면 바이너리 파일인 것이 있다. +예를 들어 Mac의 Xcode는 `.pbxproj` 파일을 만든다. 이 파일은 IDE 설정 등을 디스크에 저장하는 파일로 JSON 포맷이다. +모든 것이 ASCII인 텍스트 파일이지만 실제로는 간단한 데이터베이스이기 때문에 텍스트 파일처럼 취급할 수 없다. 그래서 여러 명이 이 파일을 동시에 수정하고 Merge할 때 diff가 도움이 안 된다. +이 파일은 프로그램이 읽고 쓰는 파일이기 때문에 +바이너리 파일처럼 취급하는 것이 옳다. + +////////////////////////// To tell Git to treat all `pbxproj` files as binary data, add the following line to your `.gitattributes` file: +////////////////////////// +모든 `pbxproj` 파일을 바이너리로 파일로 취급하는 설정은 아래와 같다. `.gitattributes` 파일에 넣으면 된다. [source] ---- *.pbxproj binary ---- +////////////////////////// Now, Git won't try to convert or fix CRLF issues; nor will it try to compute or print a diff for changes in this file when you run `git show` or `git diff` on your project. +////////////////////////// +이제 `pbxproj` 파일은 CRLF 변환이 적용되지 않는다. `git show`나 `git diff` 같은 명령을 실행할 때에도 통계를 계산하거나 diff를 출력하지 않는다. +////////////////////////// ===== Diffing Binary Files +////////////////////////// +===== 바이너리 파일 Diff하기 +////////////////////////// You can also use the Git attributes functionality to effectively diff binary files. You do this by telling Git how to convert your binary data to a text format that can be compared via the normal diff. +////////////////////////// +Git은 바이너리 파일도 diff할 수 있다. +Git Attribute를 통해 Git이 바이너리 파일을 텍스트 포맷으로 변환하고 그 결과를 diff로 비교하도록 하는 것이다. +////////////////////////// First, you'll use this technique to solve one of the most annoying problems known to humanity: version-controlling Microsoft Word documents. Everyone knows that Word is the most horrific editor around, but oddly, everyone still uses it. If you want to version-control Word documents, you can stick them in a Git repository and commit every once in a while; but what good does that do? If you run `git diff` normally, you only see something like this: +////////////////////////// +먼저 이 기술을 인류에게 알려진 가장 귀찮은 문제 중 하나인 Word 문서를 버전 관리하는 상황을 살펴보자. +모든 사람이 Word가 가장 끔찍한 편집기라고 말하지만 애석하게도 모두 Word를 사용한다. +Git 저장소에 넣고 이따금 커밋하는 것만으로도 Word 문서의 버전을 관리할 수 있다. +그렇지만 `git diff`를 실행하면 다음과 같은 메시지를 볼 수 있을 뿐이다. [source,console] ---- @@ -49,23 +94,39 @@ index 88839c4..4afcb7c 100644 Binary files a/chapter1.docx and b/chapter1.docx differ ---- +////////////////////////// You can't directly compare two versions unless you check them out and scan them manually, right? It turns out you can do this fairly well using Git attributes. Put the following line in your `.gitattributes` file: +////////////////////////// +직접 파일을 하나하나 까보지 않으면 두 버전이 뭐가 다른지 알 수 없다. +Git Attribute를 사용하면 이를 더 좋게 개선할 수 있다. +`.gitattributes` 파일에 아래와 같은 내용을 추가한다. [source] ---- *.docx diff=word ---- +////////////////////////// This tells Git that any file that matches this pattern (`.docx`) should use the ``word'' filter when you try to view a diff that contains changes. What is the ``word'' filter? You have to set it up. Here you'll configure Git to use the `docx2txt` program to convert Word documents into readable text files, which it will then diff properly. +////////////////////////// +이것은 `*.docx` 파일의 두 버전이 무엇이 다른지 diff할 때 ``word'' 필터를 사용하라고 설정하는 것이다. +그럼 ``word'' 필터는 뭘까? +이 ``word'' 필터도 정의해야 한다. +Word 문서에서 사람이 읽을 수 있는 텍스트를 추출해주는 `docx2txt` 프로그램을 사용하여 diff에 이용한다. +////////////////////////// First, you'll need to install `docx2txt`; you can download it from http://docx2txt.sourceforge.net[]. Follow the instructions in the `INSTALL` file to put it somewhere your shell can find it. Next, you'll write a wrapper script to convert output to the format Git expects. Create a file that's somewhere in your path called `docx2txt`, and add these contents: +////////////////////////// +우선 `docx2txt` 프로그램을 설채히야 하는데 http://docx2txt.sourceforge.net[] 사이트에서 다운로드 할 수 있다. `INSTALL` 부분의 설치과정을 참고하여 설치하고 쉘에서 실행할 수 있도록 설정한다. +그리고 Git에서 잘 쓸 수 있도록 Wrapper 스크립트를 +`docx2txt` 라는 이름으로 아래와 같이 작성한다. [source,console] ---- @@ -73,20 +134,33 @@ Create a file that's somewhere in your path called `docx2txt`, and add these con docx2txt.pl $1 - ---- +////////////////////////// Don't forget to `chmod a+x` that file. Finally, you can configure Git to use this script: +////////////////////////// +`chmod a+x`로 실행권한을 설정해두고 +다음과 같이 Git 설정을 추가한다. [source,console] ---- $ git config diff.word.textconv docx2txt ---- +////////////////////////// Now Git knows that if it tries to do a diff between two snapshots, and any of the files end in `.docx`, it should run those files through the ``word'' filter, which is defined as the `docx2txt` program. This effectively makes nice text-based versions of your Word files before attempting to diff them. +////////////////////////// +이제 Git은 확장자가 `.docx`인 파일의 스냅샷을 diff할 때 ``word'' 필터로 정의한 `docx2txt` 프로그램을 사용한다. +이 프로그램은 Word 파일을 텍스트 파일로 변환해 주기 때문에 diff할 수 있다. +////////////////////////// Here's an example: Chapter 1 of this book was converted to Word format and commited in a Git repository. Then a new paragraph was added. Here's what `git diff` shows: +////////////////////////// +이 책의 1장을 Word 파일로 만들어서 Git에 넣고 나서 단락 하나를 수정하고 저장하는 예를 살펴본다. +새로 단락을 하나 추가하고나서 +`git diff`를 실행하면 어디가 달려졌는지 확인할 수 있다. [source,console] ---- @@ -105,12 +179,21 @@ index 0b013ca..ba25db5 100644 Many people's version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they're clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you're in and accidentally write to the wrong file or copy over files you don't mean to. ---- +////////////////////////// Git successfully and succinctly tells me that I added the string ``Testing: 1, 2, 3.'', which is correct. It's not perfect – formatting changes wouldn't show up here – but it certainly works. +////////////////////////// +Git의 diff 결과를 보면 ``Testing: 1, 2, 3.'' 부분이 추가된 것을 확인할 수 있다. +물론 텍스트 형식 같은 완전한 정보는 아니지만 어쨋든 유용하다. +////////////////////////// Another interesting problem you can solve this way involves diffing image files. One way to do this is to run image files through a filter that extracts their EXIF information – metadata that is recorded with most image formats. If you download and install the `exiftool` program, you can use it to convert your images into text about the metadata, so at least the diff will show you a textual representation of any changes that happened: +////////////////////////// +이 방법으로 이미지 파일도 diff할 수 있다. +필터로 EXIF 정보를 추출해서 이미지 파일을 비교한다. EXIF 정보는 대부분의 이미지 파일에 들어 있는 메타데이터다. +`exiftool`이라는 프로그램을 설치하고 이미지 파일에서 메타데이터 텍스트를 추출한다. 그리고 그 결과를 diff해서 무엇이 달라졌는지 본다. [source,console] ---- @@ -118,7 +201,10 @@ $ echo '*.png diff=exif' >> .gitattributes $ git config diff.exif.textconv exiftool ---- +////////////////////////// If you replace an image in your project and run `git diff`, you see something like this: +////////////////////////// +프로젝트에 들어 있는 이미지 파일을 변경하고 `git diff`를 실행하면 아래와 같이 보여준다. [source] ---- @@ -142,20 +228,37 @@ index 88839c4..4afcb7c 100644 Color Type : RGB with Alpha ---- +////////////////////////// You can easily see that the file size and image dimensions have both changed. +////////////////////////// +이미지 파일의 크기와 해상도가 달라진 것을 쉽게 알 수 있다. [[_keyword_expansion]] +////////////////////////// ==== Keyword Expansion +////////////////////////// +==== 키워드 치환 (((keyword expansion))) +////////////////////////// SVN- or CVS-style keyword expansion is often requested by developers used to those systems. The main problem with this in Git is that you can't modify a file with information about the commit after you've committed, because Git checksums the file first. However, you can inject text into a file when it's checked out and remove it again before it's added to a commit. Git attributes offers you two ways to do this. +////////////////////////// +SVN이나 CVS에 익숙한 사람들은 해당 시스템에서 사용하던 키워드 치환(Keyword Expansion) 기능을 찾는다. +Git에서는 이것이 쉽지 않다. +Git은 먼저 체크섬을 계산하고 커밋하기 때문에 그 커밋에 대한 정보를 가지고 파일을 수정할 수 없다. +하지만, Checkout할 때 그 정보가 자동으로 파일에 삽입되도록 했다가 다시 커밋할 때 삭제되도록 할 수 있다. +////////////////////////// First, you can inject the SHA-1 checksum of a blob into an `$Id$` field in the file automatically. If you set this attribute on a file or set of files, then the next time you check out that branch, Git will replace that field with the SHA-1 of the blob. It's important to notice that it isn't the SHA of the commit, but of the blob itself: +////////////////////////// +파일 안에 `$Id$` 필드를 넣으면 Blob의 SHA-1 체크섬을 자동으로 삽입한다. +이 필드를 파일에 넣으면 Git은 앞으로 Checkout할 때 해당 Blob의 SHA-1 값으로 교체한다. +여기서 꼭 기억해야 할 것이 있다. 교체되는 체크섬은 커밋의 것이 아니라 Blob 그 자체의 SHA-1 체크섬이다. [source,console] ---- @@ -163,7 +266,10 @@ $ echo '*.txt ident' >> .gitattributes $ echo '$Id$' > test.txt ---- +////////////////////////// The next time you check out this file, Git injects the SHA of the blob: +////////////////////////// +Git은 이 파일을 Checkout할 때마다 SHA 값을 삽입해준다. [source,console] ---- @@ -173,31 +279,56 @@ $ cat test.txt $Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $ ---- +////////////////////////// However, that result is of limited use. If you've used keyword substitution in CVS or Subversion, you can include a datestamp – the SHA isn't all that helpful, because it's fairly random and you can't tell if one SHA is older or newer than another just by looking at them. +////////////////////////// +하지만 이것은 별로 유용하지 않다. +CVS나 SVN의 키워드 치환(Keyword Substitution)을 써봤으면 날짜(Datestamp)도 가능했다는 것을 알고 있을 것이다. SHA는 그냥 해시이고 식별할 수 있을 뿐이지 다른 것을 알려주진 않는다. SHA만으로는 예전 것보다 새 것인지 오래된 것인지는 알 수 없다. +////////////////////////// It turns out that you can write your own filters for doing substitutions in files on commit/checkout. These are called ``clean'' and ``smudge'' filters. In the `.gitattributes` file, you can set a filter for particular paths and then set up scripts that will process files just before they're checked out (``smudge'', see <>) and just before they're staged (``clean'', see <>). These filters can be set to do all sorts of fun things. +////////////////////////// +Commit/Checkout할 때 사용하는 필터를 직접 만들어 쓸 수 있다. +방향에 따라 ``clean'' 필터와 ``smudge'' 필터라고 부른다. +".gitattributes" 파일에 설정하고 파일 경로마다 다른 필터를 설정할 수 있다. Checkout할 때 파일을 처리하는 것이 ``smudge'' 필터이고(<>) 커밋할 때 처리하는 필터가 ``clean''(<>) 필터이다. +이 필터로 할 수 있는 일은 무궁무진하다. [[filters_a]] +////////////////////////// .The ``smudge'' filter is run on checkout. image::images/smudge.png[The ``smudge'' filter is run on checkout.] +////////////////////////// +.``smudge'' 필터는 Checkout할 때 실행된다. +image::images/smudge.png[``smudge'' 필터는 Checkout할 때 실행된다.] [[filters_b]] +////////////////////////// .The ``clean'' filter is run when files are staged. image::images/clean.png[The ``clean'' filter is run when files are staged.] +////////////////////////// +.``clean'' 필터는 파일을 Stage할 때 실행된다. +image::images/clean.png[``clean'' 필터는 파일을 Stage할 때 실행된다.] +////////////////////////// The original commit message for this feature gives a simple example of running all your C source code through the `indent` program before committing. You can set it up by setting the filter attribute in your `.gitattributes` file to filter `*.c` files with the ``indent'' filter: +////////////////////////// +이 기능은 사실 커밋메시지를 위한 기능이었지만 응용한다면 커밋하기 전에 `indent` 프로그램으로 C 코드 전부를 필터링하는 기능을 만들 수 있다.. +`*.c` 파일에 대해 indent 필터를 거치도록 `.gitattributes` 파일에 설정한다. [source] ---- *.c filter=indent ---- +////////////////////////// Then, tell Git what the ``indent'' filter does on smudge and clean: +////////////////////////// +아래처럼 ``indent'' 필터의 smudge와 clean이 무엇인지 설정한다. [source,console] ---- @@ -205,13 +336,23 @@ $ git config --global filter.indent.clean indent $ git config --global filter.indent.smudge cat ---- +////////////////////////// In this case, when you commit files that match `*.c`, Git will run them through the indent program before it stages them and then run them through the `cat` program before it checks them back out onto disk. The `cat` program does essentially nothing: it spits out the same data that it comes in. This combination effectively filters all C source code files through `indent` before committing. +////////////////////////// +`*.c` 파일을 커밋하면 indent 프로그램을 통해서 커밋되고 Checkout하면 `cat` 프로그램을 통해 Checkout된다. +`cat`은 입력된 데이터를 그대로 다시 내보내는 사실 아무것도 안 하는 프로그램이다. +이렇게 설정하면 모든 C 소스 파일은 `indent` 프로그램을 통해 커밋된다. +////////////////////////// Another interesting example gets `$Date$` keyword expansion, RCS style. To do this properly, you need a small script that takes a filename, figures out the last commit date for this project, and inserts the date into the file. Here is a small Ruby script that does that: +////////////////////////// +이제 RCS 처럼 `$Date$`를 치환하는 예제을 살펴보자. +이 기능을 구현하려면 간단한 스크립트가 하나 필요하다. 이 스크립트는 `$Date$` 필드를 프로젝트의 마지막 커밋 일자로 치환한다. 표준 입력을 읽어서 `$Date$` 필드를 치환한다. +아래는 Ruby로 구현한 스크립트다. [source,ruby] ---- @@ -221,10 +362,16 @@ last_date = `git log --pretty=format:"%ad" -1` puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$') ---- +////////////////////////// All the script does is get the latest commit date from the `git log` command, stick that into any `$Date$` strings it sees in stdin, and print the results – it should be simple to do in whatever language you're most comfortable in. You can name this file `expand_date` and put it in your path. Now, you need to set up a filter in Git (call it `dater`) and tell it to use your `expand_date` filter to smudge the files on checkout. You'll use a Perl expression to clean that up on commit: +////////////////////////// +`git log` 명령으로 마지막 커밋 정보를 얻고 표준 입력(STDIN)에서 `$Date$` 스트링을 찾아서 치환한다. 스크립트는 자신이 편한 언어로 만든다. +이 스크립트의 이름을 `expand_date`라고 짓고 실행 경로에 넣는다. +그리고 `dater`라는 Git 필터를 정의한다. +Checkout시 실행하는 smudge 필터로 `expand_date`를 사용하고 커밋할 때 실행하는 clean 필터는 Perl을 사용한다. [source,console] ---- @@ -232,8 +379,12 @@ $ git config filter.dater.smudge expand_date $ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"' ---- +////////////////////////// This Perl snippet strips out anything it sees in a `$Date$` string, to get back to where you started. Now that your filter is ready, you can test it by setting up a file with your `$Date$` keyword and then setting up a Git attribute for that file that engages the new filter: +////////////////////////// +이 Perl 코드는 `$Date$` 스트링에 있는 문자를 제거해서 원래대로 복원한다. +이제 필터가 준비됐으니 `$Date$` 키워드가 들어 있는 파일을 만들고 Git Attribute를 설정하고 새 필터를 시험해보자. [source,console] ---- @@ -241,7 +392,10 @@ $ echo '# $Date$' > date_test.txt $ echo 'date*.txt filter=dater' >> .gitattributes ---- +////////////////////////// If you commit those changes and check out the file again, you see the keyword properly substituted: +////////////////////////// +커밋하고 파일을 다시 Checkout 하면 해당 키워드가 적절히 치환된 것을 볼 수 있다. [source,console] ---- @@ -253,35 +407,62 @@ $ cat date_test.txt # $Date: Tue Apr 21 07:26:52 2009 -0700$ ---- +////////////////////////// You can see how powerful this technique can be for customized applications. You have to be careful, though, because the `.gitattributes` file is committed and passed around with the project, but the driver (in this case, `dater`) isn't, so it won't work everywhere. When you design these filters, they should be able to fail gracefully and have the project still work properly. +////////////////////////// +프로젝트를 맞춤설정하는데 두루두루 활용하기에 매우 강력한 기능이다. +`.gitattributes` 파일은 커밋하는 파일이기 때문에 필터 드라이버(여기서는 `dater`) 설정이 되지 않은 사람에게도 배포된다. 물론 `dater` 설정이 안되어있는 사람에게는 에러가 난다. +필터를 만들 때 이런 예외 상황도 고려해서 항상 잘 동작하게 해야 한다. +////////////////////////// ==== Exporting Your Repository +////////////////////////// +==== 저장소 익스포트하기 (((archiving))) +////////////////////////// Git attribute data also allows you to do some interesting things when exporting an archive of your project. +////////////////////////// +프로젝트를 익스포트해서 아카이브를 만들 때에도 Git Attribute가 유용하다. ===== `export-ignore` +////////////////////////// You can tell Git not to export certain files or directories when generating an archive. If there is a subdirectory or file that you don't want to include in your archive file but that you do want checked into your project, you can determine those files via the `export-ignore` attribute. +////////////////////////// +아카이브를 만들 때 제외할 파일이나 디렉토리가 무엇인지 설정할 수 있다. +특정 디렉토리나 파일을 프로젝트에는 포함하고 아카이브에는 포함하고 싶지 않을 때 `export-ignore` Attribute를 사용한다. +////////////////////////// For example, say you have some test files in a `test/` subdirectory, and it doesn't make sense to include them in the tarball export of your project. You can add the following line to your Git attributes file: +////////////////////////// +예를 들어 `test/` 디렉토리에 테스트 파일이 있다고 하자. 보통 tar 파일로 묶어서 익스포트할 때 테스트 파일은 포함하지 않는다. +Git Attribute 파일에 다음 라인을 추가하면 테스트 파일은 무시된다. [source] ---- test/ export-ignore ---- +////////////////////////// Now, when you run git archive to create a tarball of your project, that directory won't be included in the archive. +////////////////////////// +`git archive` 명령으로 tar 파일을 만들면 test 디렉토리는 아카이브에 포함되지 않는다. ===== `export-subst` +////////////////////////// Another thing you can do for your archives is some simple keyword substitution. Git lets you put the string `$Format:$` in any file with any of the `--pretty=format` formatting shortcodes, many of which you saw in Chapter 2. For instance, if you want to include a file named `LAST_COMMIT` in your project, and the last commit date was automatically injected into it when `git archive` ran, you can set up the file like this: +////////////////////////// +아카이브를 만들 때에도 키워드 치환을 할 수 있다. +파일을 하나 만들고 거기에 `$Format:$` 스트링을 넣으면 Git이 치환해준다. 이 스트링에 `--pretty=format` 옵션에 사용하는 것과 같은 포맷 코드를 넣을 수 있다. `--pretty=format`은 2장에서 배웠다. +예를 들어 `LAST_COMMIT`이라는 파일을 만들고 `git archive` 명령을 실행할 때 자동으로 이 파일에 마지막 커밋 날짜가 삽입되게 하려면 아래와 같이 해야 한다. [source,console] ---- @@ -291,7 +472,10 @@ $ git add LAST_COMMIT .gitattributes $ git commit -am 'adding LAST_COMMIT file for archives' ---- +////////////////////////// When you run `git archive`, the contents of that file when people open the archive file will look like this: +////////////////////////// +`git archive` 명령으로 아카이브를 만들고 나서 이 파일을 열어보면 아래와 같이 보인다. [source,console] ---- @@ -299,15 +483,27 @@ $ cat LAST_COMMIT Last commit date: $Format:Tue Apr 21 08:38:48 2009 -0700$ ---- +////////////////////////// ==== Merge Strategies +////////////////////////// +==== Merge 전략 (((merging, strategies))) +////////////////////////// You can also use Git attributes to tell Git to use different merge strategies for specific files in your project. One very useful option is to tell Git to not try to merge specific files when they have conflicts, but rather to use your side of the merge over someone else's. +////////////////////////// +파일마다 다른 Merge 전략을 사용하도록 설정할 수 있다. +Merge할 때 충돌이 날 것 같은 파일이 있다고 하자. Git Attrbute로 이 파일만 항상 타인의 코드 말고 내 코드를 사용하도록 설정할 수 있다. +////////////////////////// This is helpful if a branch in your project has diverged or is specialized, but you want to be able to merge changes back in from it, and you want to ignore certain files. Say you have a database settings file called `database.xml` that is different in two branches, and you want to merge in your other branch without messing up the database file. You can set up an attribute like this: +////////////////////////// +이 설정은 다양한 환경에서 운영하려고 만든 환경 브랜치를 Merge할 때 좋다. 이때는 환경 설정과 관련된 파일은 Merge하지 않고 무시하는 게 편리하다. +브랜치에 `database.xml`이라는 데이터베이스 설정파일이 있는데 이 파일은 브랜치마다 다르다. Database 설정 파일은 Merge하면 안된다. +Attribute를 아래와 같이 설정하면 이 파일은 그냥 두고 Merge한다. [source] ---- @@ -321,7 +517,10 @@ And then define a dummy `ours` merge strategy with: $ git config --global merge.ours.driver true +////////////////////////// If you merge in the other branch, instead of having merge conflicts with the `database.xml` file, you see something like this: +////////////////////////// +다른 브랜치로 이동해서 Merge를 실행했을 때 `database.xml` 파일에 대해 충돌이 발생하는 대신 아래와 같은 메시지를 보게 된다. [source,console] ---- @@ -330,4 +529,7 @@ Auto-merging database.xml Merge made by recursive. ---- +////////////////////////// In this case, `database.xml` stays at whatever version you originally had. +////////////////////////// +Merge했지만 `database.xml`은 원래 가지고 있던 파일 그대로다. diff --git a/book/08-customizing-git/sections/config.asc b/book/08-customizing-git/sections/config.asc index a91ef1a7..4bad012d 100644 --- a/book/08-customizing-git/sections/config.asc +++ b/book/08-customizing-git/sections/config.asc @@ -1,9 +1,16 @@ [[_git_config]] +////////////////////////// === Git Configuration +////////////////////////// +=== Git 설정하기 (((git commands, config))) +////////////////////////// As you briefly saw in <<_getting_started>>, you can specify Git configuration settings with the `git config` command. One of the first things you did was set up your name and e-mail address: +////////////////////////// +<<_getting_started>> 에서 `git config` 명령을 사용했다. +제일 먼저 해야 하는 것은 `git config` 명령으로 이름과 e-mail 주소를 설정하는 것이다. [source,console] ---- @@ -11,60 +18,108 @@ $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com ---- +////////////////////////// Now you'll learn a few of the more interesting options that you can set in this manner to customize your Git usage. +////////////////////////// +이렇게 설정하는 것들 중에서 중요한 것을 몇 가지 설명한다. +////////////////////////// First, a quick review: Git uses a series of configuration files to determine non-default behavior that you may want. The first place Git looks for these values is in an `/etc/gitconfig` file, which contains values for every user on the system and all of their repositories. If you pass the option `--system` to `git config`, it reads and writes from this file specifically. +////////////////////////// +우선 Git은 내장된 기본 규칙 따르지만, 설정된 것이 있으면 그에 따른다는 점을 생각해두자. +Git은 먼저 `/etc/gitconfig` 파일을 찾는다. 이 파일은 해당 시스템에 있는 모든 사용자와 모든 저장소에 적용되는 설정 파일이다. +`git config` 명령에 `--system` 옵션을 주면 이 파일을 사용한다. +////////////////////////// The next place Git looks is the `~/.gitconfig` (or `~/.config/git/config`) file, which is specific to each user. You can make Git read and write to this file by passing the `--global` option. +////////////////////////// +다음으로 `~/.gitconfig` 파일을 찾는다. 이 파일은 해당 사용자에게만 적용되는 설정 파일이다. +`--global` 옵션을 주면 Git은 이 파일을 사용한다. +////////////////////////// Finally, Git looks for configuration values in the configuration file in the Git directory (`.git/config`) of whatever repository you're currently using. These values are specific to that single repository. +////////////////////////// +마지막으로 현재 작업 중인 저장소의 Git 디렉토리에 있는 `.git/config` 파일을 찾는다. +이 파일은 해당 저장소에만 적용된다. +////////////////////////// Each of these ``levels'' (system, global, local) overwrites values in the previous level, so values in `.git/config` trump those in `/etc/gitconfig`, for instance. +////////////////////////// +각 설정 파일에 중복된 설정이 있으면 설명한 ``순서대로'' 덮어쓴다. 예를 들어 `.git/config`와 `/etc/gitconfig`에 같은 설정이 들어 있다면 `.git/config`에 있는 설정을 사용한다. [NOTE] ==== +////////////////////////// Git's configuration files are plain-text, so you can also set these values by manually editing the file and inserting the correct syntax. It's generally easier to run the `git config` command, though. +////////////////////////// +설정 파일 일반적인 텍스트파일로 쉽게 고쳐쓸 수 있다. +보통 `git config` 명령을 사용하는 것이 더 편하다. ==== +////////////////////////// ==== Basic Client Configuration +////////////////////////// +==== 클라이언트 설정 +////////////////////////// The configuration options recognized by Git fall into two categories: client-side and server-side. The majority of the options are client-side – configuring your personal working preferences. Many, _many_ configuration options are supported, but a large fraction of them are only useful in certain edge cases. We'll only be covering the most common and most useful here. If you want to see a list of all the options your version of Git recognizes, you can run +////////////////////////// +설정이 영향을 미치는 대상에 따라 클라이언트 설정과 서버 설정으로 나눠볼 수 있다. +대부분은 개인작업 환경과 관련된 클라이언트 설정이다. +Git에는 설정거리가 매우 많은데, 여기서는 Workflow를 관리하는 데 필요한 것과 주로 많이 사용하는 것만 설명한다. +한 번도 겪지 못할 상황에서나 유용한 옵션까지 다 포함하면 설정할 게 너무 많다. +Git 버전마다 옵션이 조금씩 다른데, 아래와 같이 실행하면 설치한 버전에서 사용할 수 있는 옵션을 모두 보여준다. [source,console] ---- $ man git-config ---- +////////////////////////// This command lists all the available options in quite a bit of detail. You can also find this reference material at http://git-scm.com/docs/git-config.html[]. +////////////////////////// +어떤 옵션을 사용할 수 있는지 매우 자세히 설명하고 있다. +http://git-scm.com/docs/git-config.html[] 페이지에서도 같은 내용을 볼 수 있다. ===== `core.editor` ((($EDITOR)))((($VISUAL, see $EDITOR))) +////////////////////////// By default, Git uses whatever you've set as your default text editor (`$VISUAL` or `$EDITOR`) or else falls back to the `vi` editor to create and edit your commit and tag messages. To change that default to something else, you can use the `core.editor` setting: +////////////////////////// +Git은 편집기를 설정(`$VISUAL`, `$EDITOR` 변수로 설정)하지 않았거나 설정한 편집기를 찾을 수 없으면 `vi`를 실행한다. 커밋할 때나 tag 메시지를 편집할 때 설정한 편집기를 실행한다. +`code.editor` 설정으로 편집기를 설정한다. [source,console] ---- $ git config --global core.editor emacs ---- +////////////////////////// Now, no matter what is set as your default shell editor, Git will fire up Emacs to edit messages. +////////////////////////// +이렇게 설정하면 메시지를 편집할 때 환경변수에 설정한 편집기가 아니라 Emacs를 실행한다. ===== `commit.template` (((commit templates))) +////////////////////////// If you set this to the path of a file on your system, Git will use that file as the default message when you commit. For instance, suppose you create a template file at `~/.gitmessage.txt` that looks like this: +////////////////////////// +커밋할 때 Git이 보여주는 커밋 메시지는 이 옵션에 설정한 템플릿 파일이다. +예를 들어 `~/.gitmessage.txt` 파일을 아래와 같이 만든다. [source] ---- @@ -75,7 +130,10 @@ what happened [ticket: X] ---- +////////////////////////// To tell Git to use it as the default message that appears in your editor when you run `git commit`, set the `commit.template` configuration value: +////////////////////////// +이 파일을 `commit.template`에 설정하면 Git은 `git commit` 명령이 실행하는 편집기에 이 메시지를 기본으로 넣어준다. [source,console] ---- @@ -83,7 +141,10 @@ $ git config --global commit.template ~/.gitmessage.txt $ git commit ---- +////////////////////////// Then, your editor will open to something like this for your placeholder commit message when you commit: +////////////////////////// +그러면 commit할 때 아래와 같은 메시지를 편집기에 자동으로 채워준다. [source] ---- @@ -105,33 +166,50 @@ what happened ".git/COMMIT_EDITMSG" 14L, 297C ---- +////////////////////////// If your team has a commit-message policy, then putting a template for that policy on your system and configuring Git to use it by default can help increase the chance of that policy being followed regularly. +////////////////////////// +소속 팀에 커밋 메시지 규칙이 있으면 그 규칙에 맞는 템플릿 파일을 만들고 시스템 설정에 설정해둔다. Git이 그 파일을 사용하도록 설정하면 규칙을 따르기가 쉬워진다. ===== `core.pager` (((pager))) +////////////////////////// This setting determines which pager is used when Git pages output such as `log` and `diff`. You can set it to `more` or to your favorite pager (by default, it's `less`), or you can turn it off by setting it to a blank string: +////////////////////////// +Git은 `log`나 `diff`같은 명령의 메시지를 출력할 때 페이지로 나누어 보여준다. +기본으로 사용하는 명령은 `less`다. `more`를 더 좋아하면 `more`라고 설정한다. 페이지를 나누고 싶지 않으면 빈 문자열로 설정한다. [source,console] ---- $ git config --global core.pager '' ---- +////////////////////////// If you run that, Git will page the entire output of all commands, no matter how long they are. +////////////////////////// +이 명령을 실행하면 Git은 길든지 짧든지 결과를 한 번에 다 보여 준다. ===== `user.signingkey` (((GPG))) +////////////////////////// If you're making signed annotated tags (as discussed in <<_signing>>), setting your GPG signing key as a configuration setting makes things easier. Set your key ID like so: +////////////////////////// +이 설정은 <<_signing>> 에서 설명했던 Annotated Tag를 만들 때 유용하다. 사용할 GPG 키를 설정해 둘 수 있다. +아래 처럼 GPG 키를 설정하면 서명할 때 편리하다. [source,console] ---- $ git config --global user.signingkey ---- +////////////////////////// Now, you can sign tags without having to specify your key every time with the `git tag` command: +////////////////////////// +`git tag` 명령을 실행할 때 키를 생략하고 서명할 수 있다. [source,console] ---- @@ -141,14 +219,25 @@ $ git tag -s ===== `core.excludesfile` (((excludes)))(((.gitignore))) +////////////////////////// You can put patterns in your project's `.gitignore` file to have Git not see them as untracked files or try to stage them when you run `git add` on them, as discussed in <<_ignoring>>. +////////////////////////// +Git에서 `git add` 명령으로 추적할 파일에 포함시키지 않을 파일은 `.gitignore`에 해당 패턴을 적으면 된다고 <<_ignoring>>에서 설명했다. +////////////////////////// But sometimes you want to ignore certain files for all repositories that you work with. If your computer is running Mac OS X, you're probably familiar with `.DS_Store` files. If your preferred editor is Emacs or Vim, you know about files that end with a `~`. +////////////////////////// +한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함시키기 않을 파일을 설정할 수 있다. +예를 들어 Mac을 쓰는 사람이라면 `.DS_Store` 파일을 많이 보았을 것이다. +Emacs나 Vim를 쓰다보면 이름 끝에 `~` 붙여둔 임시 파일도 있다. +////////////////////////// This setting lets you write a kind of global `.gitignore` file. If you create a `~/.gitignore_global` file with these contents: +////////////////////////// +`.gitignore` 파일처럼 무시할 파일을 설정할 수 있는데 `~/.gitignore_global` 파일 안에 아래 내용으로 입력해두고 [source] ---- @@ -156,12 +245,18 @@ If you create a `~/.gitignore_global` file with these contents: .DS_Store ---- +////////////////////////// …and you run `git config --global core.excludesfile ~/.gitignore_global`, Git will never again bother you about those files. +////////////////////////// +`git config --global core.excludesfile ~/.gitignore_global` 명령으로 설정을 추가하면 더 이상 위와 같은 파일이 포함되지 않을 것이다. ===== `help.autocorrect` (((autocorrect))) +////////////////////////// If you mistype a command, it shows you something like this: +////////////////////////// +명령어를 잘못 입력하면 Git은 메시지를 아래와 같이 보여 준다. [source,console] ---- @@ -172,8 +267,12 @@ Did you mean this? checkout ---- +////////////////////////// Git helpfully tries to figure out what you meant, but it still refuses to do it. If you set `help.autocorrect` to 1, Git will actually run this command for you: +////////////////////////// +Git은 어떤 명령을 입력하려고 했을지 추측해서 보여주긴 하지만 직접 실행하진 않는다. +그러나 `help.autocorrect`를 1로 설정하면 명령어를 잘못 입력해도 Git이 자동으로 해당 명령어를 찾아서 실행해준다. [source,console] ---- @@ -183,64 +282,117 @@ Continuing under the assumption that you meant 'checkout' in 0.1 seconds automatically... ---- +////////////////////////// Note that ``0.1 seconds'' business. `help.autocorrect` is actually an integer which represents tenths of a second. So if you set it to 50, Git will give you 5 seconds to change your mind before executing the autocorrected command. +////////////////////////// +여기서 재밌는 것은 ``0.1 seconds'' 이다. 사실 `help.autocorrect` 설정에 사용하는 값은 1/10 초 단위의 숫자를 나타낸다. +만약 50이라는 값으로 설정한다면 자동으로 고친 명령을 실행할 때 Git은 5초간 명령을 실행하지 않고 기다려줄 수 있다. +////////////////////////// ==== Colors in Git +////////////////////////// +==== 컬러 터미널 (((color))) +////////////////////////// Git fully supports colored terminal output, which greatly aids in visually parsing command output quickly and easily. A number of options can help you set the coloring to your preference. +////////////////////////// +사람이 쉽게 인식할 수 있도록 터미널에 결과를 컬러로 출력할 수 있다. +터미널 컬러와 관련된 옵션은 매우 다양하기 때문에 꼼꼼하게 설정할 수 있다. ===== `color.ui` +////////////////////////// Git automatically colors most of its output, but there's a master switch if you don't like this behavior. To turn off all Git's colored terminal output, do this: +////////////////////////// +Git은 기본적으로 터미널에 출력하는 결과물에 알아서 색칠하지만 이 색칠하는 기능을 끄고 싶다면 한 가지 설정만 해 두면 된다. +아래와 같은 명령을 실행하면 더 이상 색칠된 결과물을 내지 않는다. [source,console] ---- $ git config --global color.ui false ---- +////////////////////////// The default setting is `auto`, which colors output when it's going straight to a terminal, but omits the color-control codes when the output is redirected to a pipe or a file. +////////////////////////// +컬러 설정의 기본 값은 `auto`로 터미널에 출력할 때는 색칠하지만 결과가 리다이렉션되거나 파일로 출력되면 색칠하지 않는다. +////////////////////////// You can also set it to `always` to ignore the difference between terminals and pipes. You'll rarely want this; in most scenarios, if you want color codes in your redirected output, you can instead pass a `--color` flag to the Git command to force it to use color codes. The default setting is almost always what you'll want. +////////////////////////// +`always` 로 설정하면 터미널이든 다른 출력이든 상관없이 색칠하여 내보낸다. +대개의 경우 이 값을 설정해서 사용하지 않는다. `--color` 옵션을 사용하면 강제로 결과를 색칠해서 내도록 할 수 있기 때문이다. +기본값을 그대로 두어도 대부분의 경우에 들어맞는다. ===== `color.*` +////////////////////////// If you want to be more specific about which commands are colored and how, Git provides verb-specific coloring settings. Each of these can be set to `true`, `false`, or `always`: +////////////////////////// +Git은 좀 더 꼼꼼하게 컬러를 설정하는 방법을 제공한다. +아래와 같은 설정들이 있다. 모두 `true`, `false`, `always` 중 하나를 고를 수 있다. color.branch color.diff color.interactive color.status +////////////////////////// In addition, each of these has subsettings you can use to set specific colors for parts of the output, if you want to override each color. For example, to set the meta information in your diff output to blue foreground, black background, and bold text, you can run +////////////////////////// +또한, 각 옵션의 컬러를 직접 지정할 수도 있다. +아래처럼 설정하면 diff 명령에서 meta 정보의 포그라운드는 blue, 백그라운드는 black, 테스트는 bold로 바뀐다. $ git config --global color.diff.meta "blue black bold" +////////////////////////// You can set the color to any of the following values: `normal`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or `white`. If you want an attribute like bold in the previous example, you can choose from `bold`, `dim`, `ul` (underline), `blink`, and `reverse` (swap foreground and background). +////////////////////////// +컬러는 `normal`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white` 중에서 고를 수 있다. +텍스트 속성은 `bold`, `dim`, `ul` (underline), `blink`, `reverse` 중에서 고를 수 있다. [[_external_merge_tools]] +////////////////////////// ==== External Merge and Diff Tools +////////////////////////// +==== 다른 Merge, Diff 도구 사용하기 (((mergetool)))(((difftool))) +////////////////////////// Although Git has an internal implementation of diff, which is what we've been showing in this book, you can set up an external tool instead. You can also set up a graphical merge-conflict-resolution tool instead of having to resolve conflicts manually. We'll demonstrate setting up the Perforce Visual Merge Tool (P4Merge) to do your diffs and merge resolutions, because it's a nice graphical tool and it's free. +////////////////////////// +Git에 들어 있는 diff 도구 말고 다른 도구로 바꿀 수 있다. +화려한 GUI 도구로 바꿔서 좀 더 편리하게 충돌을 해결할 수 있다. +여기서는 Perforce의 Merge 도구인 P4Merge로 설정하는 것을 보여준다. P4Merge는 무료인데다 꽤 괜찮다. +////////////////////////// If you want to try this out, P4Merge works on all major platforms, so you should be able to do so. I'll use path names in the examples that work on Mac and Linux systems; for Windows, you'll have to change `/usr/local/bin` to an executable path in your environment. +////////////////////////// +P4Merge는 중요 플랫폼을 모두 지원하기 때문에 웬만한 환경이면 사용할 수 있다. +여기서는 Mac과 Linux 시스템에 설치하는 것을 보여준다. 윈도에서 사용하려면 `/usr/local/bin` 경로만 윈도 경로로 바꿔준다. +////////////////////////// To begin, download P4Merge from http://www.perforce.com/downloads/Perforce/[]. Next, you'll set up external wrapper scripts to run your commands. I'll use the Mac path for the executable; in other systems, it will be where your `p4merge` binary is installed. Set up a merge wrapper script named `extMerge` that calls your binary with all the arguments provided: +////////////////////////// +먼저 http://www.perforce.com/downloads/Perforce/[] 에서 P4Merge를 다운로드 받는다. +그 후에 P4Merge에 쓸 Wrapper 스크립트를 만든다. +필자는 Mac 사용자라서 Mac 경로를 사용한다. 어떤 시스템이든 `p4merge`가 설치된 경로를 사용하면 된다. +예제에서는 `extMerge`라는 Merge용 Wrapper 스크립트를 만들고 이 스크립트로 넘어오는 모든 아규먼트를 p4merge 프로그램으로 넘긴다. [source,console] ---- @@ -249,15 +401,22 @@ $ cat /usr/local/bin/extMerge /Applications/p4merge.app/Contents/MacOS/p4merge $* ---- +////////////////////////// The diff wrapper checks to make sure seven arguments are provided and passes two of them to your merge script. By default, Git passes the following arguments to the diff program: +////////////////////////// +그리고 diff용 Wrapper도 만든다. 이 스크립트로 넘어오는 아규먼트는 총 7개지만 그 중 2개만 Merge Wrapper로 넘긴다. +Git이 diff 프로그램에 넘겨주는 아규먼트는 아래와 같다. [source] ---- path old-file old-hex old-mode new-file new-hex new-mode ---- +////////////////////////// Because you only want the `old-file` and `new-file` arguments, you use the wrapper script to pass the ones you need. +////////////////////////// +이 중에서 `old-file`과 `new-file` 만 사용하는 wrapper 스크립트를 만든다. [source,console] ---- @@ -266,7 +425,10 @@ $ cat /usr/local/bin/extDiff [ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5" ---- +////////////////////////// You also need to make sure these tools are executable: +////////////////////////// +이 두 스크립트에 실행 권한을 부여한다. [source,console] ---- @@ -274,9 +436,14 @@ $ sudo chmod +x /usr/local/bin/extMerge $ sudo chmod +x /usr/local/bin/extDiff ---- +////////////////////////// Now you can set up your config file to use your custom merge resolution and diff tools. This takes a number of custom settings: `merge.tool` to tell Git what strategy to use, `mergetool..cmd` to specify how to run the command, `mergetool..trustExitCode` to tell Git if the exit code of that program indicates a successful merge resolution or not, and `diff.external` to tell Git what command to run for diffs. So, you can either run four config commands +////////////////////////// +Git config 파일에 이 스크립트를 모두 추가한다. 설정해야 하는 옵션이 좀 많다. +`merge.tool`로 무슨 Merge 도구를 사용할지, `mergetool.*.cmd`로 실제로 어떻게 명령어를 실행할지, `mergetool.trustExitCode`로 Merge 도구가 반환하는 exit 코드가 Merge의 성공여부를 나타내는지, `diff.external`은 diff할 때 실행할 명령어가 무엇인지를 설정할 때 사용한다. +모두 `git config` 명령으로 설정한다. [source,console] ---- @@ -286,7 +453,10 @@ $ git config --global mergetool.extMerge.cmd \ $ git config --global mergetool.extMerge.trustExitCode false $ git config --global diff.external extDiff ---- +////////////////////////// or you can edit your `~/.gitconfig` file to add these lines: +////////////////////////// +`~/.gitconfig/` 파일을 직접 편집해도 된다. [source,ini] ---- @@ -299,22 +469,35 @@ or you can edit your `~/.gitconfig` file to add these lines: external = extDiff ---- +////////////////////////// After all this is set, if you run diff commands such as this: +////////////////////////// +설정을 완료하고 나서 아래와 같이 diff 명령어를 실행한다: [source,console] ---- $ git diff 32d1776b1^ 32d1776b1 ---- +////////////////////////// Instead of getting the diff output on the command line, Git fires up P4Merge, which looks something like this: +////////////////////////// +diff 결과가 터미널에 출력되는 대신 P4Merge가 실행되어 아래처럼 Diff 결과를 보여준다. .P4Merge. image::images/p4merge.png[P4Merge.] +////////////////////////// If you try to merge two branches and subsequently have merge conflicts, you can run the command `git mergetool`; it starts P4Merge to let you resolve the conflicts through that GUI tool. +////////////////////////// +브랜치를 Merge할 때 충돌이 나면 `git mergetool` 명령을 실행한다. 이 명령을 실행하면 GUI 도구로 충돌을 해결할 수 있도록 P4Merge를 실행해준다. +////////////////////////// The nice thing about this wrapper setup is that you can change your diff and merge tools easily. For example, to change your `extDiff` and `extMerge` tools to run the KDiff3 tool instead, all you have to do is edit your `extMerge` file: +////////////////////////// +Wrapper를 만들어 설정해두면 다른 diff, Merge 도구로 바꾸기도 쉽다. +예를 들어, KDiff3를 사용하도록 `extDiff`와 `extMerge` 스크립트를 수정한다. [source,console] ---- @@ -323,10 +506,17 @@ $ cat /usr/local/bin/extMerge /Applications/kdiff3.app/Contents/MacOS/kdiff3 $* ---- +////////////////////////// Now, Git will use the KDiff3 tool for diff viewing and merge conflict resolution. +////////////////////////// +이제부터 Git은 diff 결과를 보여주거나 충돌을 해결할 때 KDiff3 도구를 사용한다. +////////////////////////// Git comes preset to use a number of other merge-resolution tools without your having to set up the cmd configuration. To see a list of the tools it supports, try this: +////////////////////////// +어떤 Merge 도구는 Git에 미리 설정이 들어 있다. 그래서 추가로 스크립트를 작성하거나 하는 설정 없이 사용할 수 있는 것도 있다. +아래와 같은 명령으로 확인해볼 수 있다. [source,console] ---- @@ -358,49 +548,81 @@ Some of the tools listed above only work in a windowed environment. If run in a terminal-only session, they will fail. ---- +////////////////////////// If you're not interested in using KDiff3 for diff but rather want to use it just for merge resolution, and the kdiff3 command is in your path, then you can run +////////////////////////// +diff 도구로는 다른 것을 사용하지만, Merge 도구로는 KDiff3를 사용하고 싶은 경우에는 kdiff3 명령을 실행경로로 넣고 아래와 같이 설정하기만 하면 된다. [source,console] ---- $ git config --global merge.tool kdiff3 ---- +////////////////////////// If you run this instead of setting up the `extMerge` and `extDiff` files, Git will use KDiff3 for merge resolution and the normal Git diff tool for diffs. +////////////////////////// +`extMerge`와 `extDiff` 파일을 만들지 않고도 이렇게 Merge 도구만 kdiff3로 설정하고 diff 도구는 Git에 원래 들어 있는 것을 사용할 수 있다. ==== Formatting and Whitespace (((whitespace))) +////////////////////////// Formatting and whitespace issues are some of the more frustrating and subtle problems that many developers encounter when collaborating, especially cross-platform. It's very easy for patches or other collaborated work to introduce subtle whitespace changes because editors silently introduce them, and if your files ever touch a Windows system, their line endings might be replaced. Git has a few configuration options to help with these issues. +////////////////////////// +협업할 때 겪는 소스 포맷(Formatting)과 공백 문제는 미묘하고 난해하다. 동료 사이에 사용하는 플랫폼이 다를 때는 특히 더 심하다. +다른 사람이 보내온 Patch는 공백 문자 패턴이 미묘하게 다를 확률이 높다. 편집기가 몰래 공백문자를 추가해 버릴 수도 있고 크로스-플랫폼 프로젝트에서 윈도 개발자가 줄 끝에 CR(Carriage-Return) 문자를 추가해 버렸을 수도 있다. +Git에는 이 이슈를 돕는 몇 가지 설정이 있다. ===== `core.autocrlf` (((crlf)))(((line endings))) +////////////////////////// If you're programming on Windows and working with people who are not (or vice-versa), you'll probably run into line-ending issues at some point. This is because Windows uses both a carriage-return character and a linefeed character for newlines in its files, whereas Mac and Linux systems use only the linefeed character. This is a subtle but incredibly annoying fact of cross-platform work; many editors on Windows silently replace existing LF-style line endings with CRLF, or insert both line-ending characters when the user hits the enter key. +////////////////////////// +윈도에서 개발하는 동료와 함께 일하면 줄 바꿈(New Line) 문자에 문제가 생긴다. +윈도는 줄 바꿈 문자로 CR(Carriage-Return)과 LF(Line Feed) 문자를 둘 다 사용하지만, Mac과 Linux는 LF 문자만 사용한다. +아무것도 아닌 것 같지만, 크로스 플랫폼 프로젝트에서는 꽤 성가신 문제다. 윈도에서 사용하는 많은 편집기들이 자동으로 LF 스타일의 줄바꿈 스타일을 CRLF로 바꾸거나 Enter키를 입력하면 CRLF 스타일을 사용하기 때문이다. +////////////////////////// Git can handle this by auto-converting CRLF line endings into LF when you add a file to the index, and vice versa when it checks out code onto your filesystem. You can turn on this functionality with the `core.autocrlf` setting. If you're on a Windows machine, set it to `true` – this converts LF endings into CRLF when you check out code: +////////////////////////// +Git은 커밋할 때 자동으로 CRLF를 LF로 변환해주고 반대로 Checkout할 때 LF를 CRLF로 변환해 주는 기능이 있다. +`core.autocrlf` 설정으로 이 기능을 켤 수 있다. +윈도에서 이 값을 true로 설정하면 Checkout할 때 LF 문자가 CRLR 문자로 변환된다. [source,console] ---- $ git config --global core.autocrlf true ---- +////////////////////////// If you're on a Linux or Mac system that uses LF line endings, then you don't want Git to automatically convert them when you check out files; however, if a file with CRLF endings accidentally gets introduced, then you may want Git to fix it. You can tell Git to convert CRLF to LF on commit but not the other way around by setting `core.autocrlf` to input: +////////////////////////// +줄 바꿈 문자로 LF를 사용하는 Linux와 Mac에서는 Checkout할 때 Git이 LF를 CRLF로 변환할 필요가 없다. 게다가 우연히 CRLF가 들어간 파일이 저장소에 들어 있어도 Git이 알아서 고쳐주면 좋을 것이다. +`core.autocrlf` 값을 input으로 설정하면 커밋할 때만 CRLF를 LF로 변환한다. [source,console] ---- $ git config --global core.autocrlf input ---- +////////////////////////// This setup should leave you with CRLF endings in Windows checkouts, but LF endings on Mac and Linux systems and in the repository. +////////////////////////// +이 설정을 이용하면 윈도에서는 CRLF를 사용하고 Mac, Linux, 저장소에서는 LF를 사용할 수 있다. +////////////////////////// If you're a Windows programmer doing a Windows-only project, then you can turn off this functionality, recording the carriage returns in the repository by setting the config value to `false`: +////////////////////////// +윈도 플랫폼에서만 개발하면 이 기능이 필요 없다. +이 옵션을 `false`라고 설정하면 이 기능이 꺼지고 CR 문자도 저장소에도 저장된다. [source,console] ---- @@ -409,16 +631,31 @@ $ git config --global core.autocrlf false ===== `core.whitespace` +////////////////////////// Git comes preset to detect and fix some whitespace issues. It can look for six primary whitespace issues – three are enabled by default and can be turned off, and three are disabled by default but can be activated. +////////////////////////// +Git에는 공백 문자를 다루는 방법으로 네 가지가 미리 정의돼 있다. +두 가지는 기본적으로 켜져 있지만 끌 수 있고 나머지 두 가지는 꺼져 있지만 켤 수 있다. +////////////////////////// The ones that are turned on by default are `blank-at-eol`, which looks for spaces at the end of a line; `blank-at-eof`, which notices blank lines at the end of a file; and `space-before-tab`, which looks for spaces before tabs at the beginning of a line. +////////////////////////// +먼저 기본적으로 켜져 있는 것을 살펴보자. `blank-at-eol`는 각 줄 끝에 공백이 있는지 찾고, `blank-at-eof`는 파일 끝에 추가한 빈 줄이 있는지 찾고, `space-before-tab`은 모든 줄 처음에 tab보다 공백이 먼저 나오는지 찾는다. +////////////////////////// The three that are disabled by default but can be turned on are `indent-with-non-tab`, which looks for lines that begin with spaces instead of tabs (and is controlled by the `tabwidth` option); `tab-in-indent`, which watches for tabs in the indentation portion of a line; and `cr-at-eol`, which tells Git that carriage returns at the end of lines are OK. +////////////////////////// +기본적으로 꺼져 있는 나머지 세 개는 `indent-with-non-tab`과 `tab-in-indent`과 `cr-at-eol`이다. `intent-with-non-tab`은 tab이 아니라 공백으로(`tabwidth` 설정에 영향받음) 시작하는 줄이 있는지 찾고 `cr-at-eol`은 줄 끝에 CR 문자가 있어도 괜찮다고 Git에 알리는 것이다. +////////////////////////// You can tell Git which of these you want enabled by setting `core.whitespace` to the values you want on or off, separated by commas. You can disable settings by either leaving them out of the setting string or prepending a `-` in front of the value. For example, if you want all but `cr-at-eol` to be set, you can do this: +////////////////////////// +`core.whitespace` 옵션으로 이 네 가지 방법을 켜고 끌 수 있다. +설정에서 해당 옵션을 빼버리거나 이름이 `-`로 시작하면 기능이 꺼진다. +예를 들어, 다른 건 다 켜고 `cr-at-eol` 옵션만 끄려면 아래와 같이 설정한다. [source,console] ---- @@ -426,67 +663,113 @@ $ git config --global core.whitespace \ trailing-space,space-before-tab,indent-with-non-tab ---- +////////////////////////// Git will detect these issues when you run a `git diff` command and try to color them so you can possibly fix them before you commit. It will also use these values to help you when you apply patches with `git apply`. When you're applying patches, you can ask Git to warn you if it's applying patches with the specified whitespace issues: +////////////////////////// +`git diff` 명령을 실행하면 Git은 이 설정에 따라 검사해서 컬러로 표시해준다. +그래서 좀 더 쉽게 검토해서 커밋할 수 있다. +`git apply` 명령으로 Patch를 적용할 때도 이 설정을 이용할 수 있다. 아래처럼 명령어를 실행하면 해당 Patch가 공백문자 정책에 들어맞는지 확인할 수 있다. [source,console] ---- $ git apply --whitespace=warn ---- +////////////////////////// Or you can have Git try to automatically fix the issue before applying the patch: +////////////////////////// +아니면 Git이 자동으로 고치도록 할 수 있다. [source,console] ---- $ git apply --whitespace=fix ---- +////////////////////////// These options apply to the `git rebase` command as well. If you've committed whitespace issues but haven't yet pushed upstream, you can run `git rebase --whitespace=fix` to have Git automatically fix whitespace issues as it's rewriting the patches. +////////////////////////// +이 옵션은 `git rebase` 명령에서도 사용할 수 있다. +공백 문제가 있는 커밋을 서버로 Push하기 전에 `--whitespace=fix` 옵션을 주고 Rebase하면 Git은 다시 Patch를 적용하면서 공백을 설정한 대로 고친다. +////////////////////////// ==== Server Configuration +////////////////////////// +==== 서버 설정 +////////////////////////// Not nearly as many configuration options are available for the server side of Git, but there are a few interesting ones you may want to take note of. +////////////////////////// +서버 설정은 많지 않지만, 꼭 짚고 넘어가야 하는 것이 몇 개 있다. ===== `receive.fsckObjects` +////////////////////////// Git is capable of making sure every object received during a push still matches its SHA-1 checksum and points to valid objects. However, it doesn't do this by default; it's a fairly expensive operation, and might slow down the operation, especially on large repositories or pushes. If you want Git to check object consistency on every push, you can force it to do so by setting `receive.fsckObjects` to true: +////////////////////////// +Git은 Push할 때마다 각 개체가 SHA-1 체크섬에 맞는지 잘못된 개체가 가리키고 있는지 검사하게 할 수 있다. +기본적으로 이 기능이 동작하지 않게 설정이 되어 있는데 개체를 점검하데 상당히 시간이 걸리기 때문에 Push하는 시간이 늘어난다. 얼마나 늘어나는지는 저장소 크기와 Push하는 양에 달렸다. +`receive.fsckOBjects` 값을 true로 설정하면 Git이 Push할 때마다 검증한다. [source,console] ---- $ git config --system receive.fsckObjects true ---- +////////////////////////// Now, Git will check the integrity of your repository before each push is accepted to make sure faulty (or malicious) clients aren't introducing corrupt data. +////////////////////////// +이렇게 설정하면 Push할 때마다 검증하기 때문에 클라이언트는 잘못된 데이터를 Push하지 못한다. ===== `receive.denyNonFastForwards` +////////////////////////// If you rebase commits that you've already pushed and then try to push again, or otherwise try to push a commit to a remote branch that doesn't contain the commit that the remote branch currently points to, you'll be denied. This is generally good policy; but in the case of the rebase, you may determine that you know what you're doing and can force-update the remote branch with a `-f` flag to your push command. +////////////////////////// +이미 Push한 커밋을 Rebase해서 다시 Push하지 못하게 할 수 있다. 브랜치를 Push할 때 해당 리모트 브랜치가 가리키는 커밋이 Push하려는 브랜치에 없을 때 Push하지 못하게 할 수 있다. +보통은 이런 정책이 좋고 `git push` 명령에 `-f` 옵션을 주면 강제로 Push할 수 있다. +////////////////////////// To tell Git to refuse force-pushes, set `receive.denyNonFastForwards`: +////////////////////////// +`receive.denyNonFastForwards` 옵션을 켜면 Fast-forward로 Push할 수 없는 브랜치는 아예 Push하지 못한다. [source,console] ---- $ git config --system receive.denyNonFastForwards true ---- +////////////////////////// The other way you can do this is via server-side receive hooks, which we'll cover in a bit. That approach lets you do more complex things like deny non-fast-forwards to a certain subset of users. +////////////////////////// +사용자마다 다른 정책을 적용하고 싶으면 서버 훅을 사용해야 한다. +서버의 receive 훅으로 할 수 있고 이 훅도 이 장에서 설명한다. ===== `receive.denyDeletes` +////////////////////////// One of the workarounds to the `denyNonFastForwards` policy is for the user to delete the branch and then push it back up with the new reference. To avoid this, set `receive.denyDeletes` to true: +////////////////////////// +`receive.denyNonFastForwards`와 비슷한 정책으로 `receive.denyDeletes`라는 것이 있다. +이 설정을 켜면 브랜치를 삭제하는 Push가 거절된다. [source,console] ---- $ git config --system receive.denyDeletes true ---- +////////////////////////// This denies any deletion of branches or tags – no user can do it. To remove remote branches, you must remove the ref files from the server manually. There are also more interesting ways to do this on a per-user basis via ACLs, as you'll learn in <<_an_example_git_enforced_policy>>. +////////////////////////// +이제 브랜치나 Tag를 삭제하는 Push는 거절된다. 아무도 삭제할 수 없다. +리모트 브랜치를 삭제하려면 직접 손으로 server의 ref 파일을 삭제해야 한다. +그리고 사용자마다 다른 정책을 적용시키는 ACL을 만드는 방법도 있다. 이 방법은 <<_an_example_git_enforced_policy>> 에서 다룬다. diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index f2215c8a..6b8ab9d2 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -2,27 +2,55 @@ === Git Hooks (((hooks))) +////////////////////////// Like many other Version Control Systems, Git has a way to fire off custom scripts when certain important actions occur. There are two groups of these hooks: client-side and server-side. Client-side hooks are triggered by operations such as committing and merging, while server-side hooks run on network operations such as receiving pushed commits. You can use these hooks for all sorts of reasons +////////////////////////// +Git도 다른 버전 관리 시스템처럼 어떤 이벤트가 생겼을 때 자동으로 특정 스크립트를 실행하도록 할 수 있다. +이 훅은 클라이언트 훅과 서버 훅으로 나눌 수 있다. +클라이언트 훅은 커밋이나 Merge할 때 실행되고 서버 훅은 Push할 때 서버에서 실행된다. +이 절에서는 어떤 훅이 있고 어떻게 사용하는지 배운다. +////////////////////////// ==== Installing a Hook +////////////////////////// +==== 훅 설치하기 +////////////////////////// The hooks are all stored in the `hooks` subdirectory of the Git directory. In most projects, that's `.git/hooks`. When you initialize a new repository with `git init`, Git populates the hooks directory with a bunch of example scripts, many of which are useful by themselves; but they also document the input values of each script. All the examples are written as shell scripts, with some Perl thrown in, but any properly named executable scripts will work fine – you can write them in Ruby or Python or what have you. If you want to use the bundled hook scripts, you'll have to rename them; their file names all end with `.sample`. - +////////////////////////// +훅은 Git 디렉토리 밑에 `hooks`라는 디렉토리에 저장한다. +기본 훅 디렉토리는 `.git/hooks`이다. +이 디렉토리에 가보면 Git이 자동으로 넣어준 매우 유용한 스크립트 예제가 몇 개 있다. 그리고 스크립트가 입력받는 값이 어떤 값인지 파일 안에 자세히 설명돼 있다. +모든 예제는 쉘과 Perl 스크립트로 작성돼 있지만 실행할 수만 있으면 되고 Ruby나 Python같은 다른 스크립트 언어로 만들어도 된다. +예제 스크립트의 파일 이름에는 `.sample`이라는 확장자가 붙어 있다. 그래서 이름만 바꿔주면 그 훅을 바로 사용할 수 있다. + +////////////////////////// To enable a hook script, put a file in the `hooks` subdirectory of your Git directory that is named appropriately and is executable. From that point forward, it should be called. I'll cover most of the major hook filenames here. +////////////////////////// +실행할 수 있는 스크립트 파일을 저장소의 `hooks` 디렉토리에 넣으면 훅 스크립트가 켜진다. +이 스크립트는 앞으로 계속 호출된다. +중요한 주요 훅에 대해서 설명한다. +////////////////////////// ==== Client-Side Hooks +////////////////////////// +==== 클라이언트 훅 +////////////////////////// There are a lot of client-side hooks. This section splits them into committing-workflow hooks, e-mail-workflow scripts, and everything else. +////////////////////////// +클라이언트 훅은 매우 다양하다. +이 절에서는 클라이언트 훅을 커밋 Workflow 훅, E-mail Workflow 훅, 그리고 나머지로 분류해서 설명한다. [NOTE] ==== @@ -30,67 +58,138 @@ It's important to note that client-side hooks are *not* copied when you clone a If your intent with these scripts is to enforce a policy, you'll probably want to do that on the server side; see the example in <<_an_example_git_enforced_policy>>. ==== +////////////////////////// ===== Committing-Workflow Hooks +////////////////////////// +===== 커밋 Workflow 훅 +////////////////////////// The first four hooks have to do with the committing process. +////////////////////////// +먼저 커밋과 관련된 훅을 살펴보자. 커밋과 관련된 훅은 모두 네 가지다. +////////////////////////// The `pre-commit` hook is run first, before you even type in a commit message. It's used to inspect the snapshot that's about to be committed, to see if you've forgotten something, to make sure tests run, or to examine whatever you need to inspect in the code. Exiting non-zero from this hook aborts the commit, although you can bypass it with `git commit --no-verify`. You can do things like check for code style (run `lint` or something equivalent), check for trailing whitespace (the default hook does exactly this), or check for appropriate documentation on new methods. +////////////////////////// +`pre-commit` 훅은 커밋할 때 가장 먼저 호출되는 훅으로 커밋 메시지를 작성하기 전에 호출된다. +이 훅에서 커밋하는 Snapshot을 점검한다. 빠트린 것은 없는지, 테스트는 확실히 했는지 등을 검사한다. 커밋할 때 꼭 확인해야 할 게 있으면 이 훅으로 확인한다. +그리고 이 훅의 Exit 코드가 0이 아니면 커밋은 취소된다. 물론 `git commit --no-verify`라고 실행하면 이 훅을 일시적으로 생략할 수 있다. +`lint` 같은 프로그램으로 코드 스타일을 검사하거나, 줄 끝의 공백 문자를 검사하거나(예제로 들어 있는 `pre-commit` 훅이 하는 게 이 일이다), 새로 추가한 코드에 주석을 달았는지 검사하는 일은 이 훅으로 하는 것이 좋다. +////////////////////////// The `prepare-commit-msg` hook is run before the commit message editor is fired up but after the default message is created. It lets you edit the default message before the commit author sees it. This hook takes a few parameters: the path to the file that holds the commit message so far, the type of commit, and the commit SHA-1 if this is an amended commit. This hook generally isn't useful for normal commits; rather, it's good for commits where the default message is auto-generated, such as templated commit messages, merge commits, squashed commits, and amended commits. You may use it in conjunction with a commit template to programmatically insert information. - +////////////////////////// +`prepare-commit-msg` 훅은 Git이 커밋 메시지를 생성하고 나서 편집기를 실행하기 전에 실행된다. +이 훅은 사람이 커밋 메시지를 수정하기 전에 먼저 프로그램으로 손보고 싶을 때 사용한다. +이 훅은 커밋 메시지가 들어 있는 파일의 경로, 커밋의 종류를 아규먼트로 받는다. 그리고 최근 커밋을 수정할 때에는(Amending 커밋) SHA-1 값을 추가 아규먼트로 더 받는다. +사실 이 훅은 일반 커밋에는 별로 필요 없고 커밋 메시지를 자동으로 생성하는 커밋에 좋다. 커밋 메시지에 템플릿을 적용하거나, Merge 커밋, Squash 커밋, Amend 커밋일 때 유용하다. +이 스크립트로 커밋 메시지 템플릿에 정보를 삽입할 수 있다. + +////////////////////////// The `commit-msg` hook takes one parameter, which again is the path to a temporary file that contains the commit message written by the developer. If this script exits non-zero, Git aborts the commit process, so you can use it to validate your project state or commit message before allowing a commit to go through. In the last section of this chapter, I'll demonstrate using this hook to check that your commit message is conformant to a required pattern. +////////////////////////// +`commit-msg` 훅은 커밋 메시지가 들어 있는 임시 파일의 경로를 아규먼트로 받는다. +그리고 이 스크립트가 0이 아닌 값을 반환하면 커밋되지 않는다. 이 훅에서 최종적으로 커밋이 완료되기 전에 프로젝트 상태나 커밋 메시지를 검증한다. +이 장의 마지막 절에서 이 훅을 사용하는 예제를 보여준다. 커밋 메시지가 정책에 맞는지 검사하는 스크립트를 만들어 보자. +////////////////////////// After the entire commit process is completed, the `post-commit` hook runs. It doesn't take any parameters, but you can easily get the last commit by running `git log -1 HEAD`. Generally, this script is used for notification or something similar. +////////////////////////// +커밋이 완료되면 `post-commit` 훅이 실행된다. +이 훅은 넘겨받는 아규먼트가 하나도 없지만 커밋 해시정보는 `git log -1 HEAD` 명령으로 쉽게 가져올 수 있다. +일반적으로 이 스크립트는 커밋된 것을 누군가 혹은 다른 프로그램에게 알릴 때 사용한다. [[_email_hooks]] +////////////////////////// ===== E-mail Workflow Hooks +////////////////////////// +===== E-mail Workflow 훅 +////////////////////////// You can set up three client-side hooks for an e-mail-based workflow. They're all invoked by the `git am` command, so if you aren't using that command in your workflow, you can safely skip to the next section. If you're taking patches over e-mail prepared by `git format-patch`, then some of these may be helpful to you. +////////////////////////// +E-mail Workflow에 해당하는 클라이언트 훅은 세 가지이다. +이 훅은 모두 `git am` 명령으로 실행된다. 이 명령어를 사용할 일이 없으면 이 절은 읽지 않아도 된다. +하지만, 언젠가는 `git format-patch` 명령으로 만든 Patch를 E-mail로 받는 날이 올지도 모른다. +////////////////////////// The first hook that is run is `applypatch-msg`. It takes a single argument: the name of the temporary file that contains the proposed commit message. Git aborts the patch if this script exits non-zero. You can use this to make sure a commit message is properly formatted, or to normalize the message by having the script edit it in place. +////////////////////////// +제일 먼저 실행하는 훅은 `applypatch-msg`이다. +이 훅의 아규먼트는 Author가 보내온 커밋 메시지 파일의 이름이다. +이 스크립트가 종료할 때 0이 아닌 값을 반환하면 Git은 Patch하지 않는다. +커밋 메시지가 규칙에 맞는지 확인하거나 자동으로 메시지를 수정할 때 이 훅을 사용한다. +////////////////////////// The next hook to run when applying patches via `git am` is `pre-applypatch`. Somewhat confusingly, it is run _after_ the patch is applied but before a commit is made, so you can use it to inspect the snapshot before making the commit. You can run tests or otherwise inspect the working tree with this script. If something is missing or the tests don't pass, exiting non-zero aborts the `git am` script without committing the patch. +////////////////////////// +`git am`으로 Patch할 때 두 번째로 실행되는 훅이 `pre-applypatch`이다. +이 훅은 아규먼트가 없고 단순히 Patch를 적용하고 나서 실행된다. 그래서 커밋할 스냅샷을 검사하는 데 사용한다. +이 스크립트로 테스트를 수행하고 파일을 검사할 수 있다. +테스트에 실패하거나 뭔가 부족하면 0이 아닌 값을 반환시켜서 `git am` 명령을 취소시킬 수 있다. +////////////////////////// The last hook to run during a `git am` operation is `post-applypatch`, which runs after the commit is made. You can use it to notify a group or the author of the patch you pulled in that you've done so. You can't stop the patching process with this script. +////////////////////////// +`git am` 명령에서 마지막으로 실행되는 훅은 `post-applypatch`다. +이 스크립트를 이용하면 자동으로 Patch를 보낸 사람이나 그룹에게 알림 메시지를 보낼 수 있다. +이 스크립트로는 Patch를 중단시킬 수 없다. [[_other_client_hooks]] +////////////////////////// ===== Other Client Hooks +////////////////////////// +===== 기타 훅 +////////////////////////// The `pre-rebase` hook runs before you rebase anything and can halt the process by exiting non-zero. You can use this hook to disallow rebasing any commits that have already been pushed. The example `pre-rebase` hook that Git installs does this, although it makes some assumptions that may not match with your workflow. +////////////////////////// +`pre-rebase` 훅은 Rebase하기 전에 실행된다. 이 훅이 0이 아닌 값을 반환하면 Rebase가 취소된다. +이 훅으로 이미 Push한 커밋을 Rebase하지 못하게 할 수 있다. +Git이 자동으로 넣어주는 `pre-rebase` 예제가 바로 그 예제다. 이 예제에는 기준 브랜치가 `next`라고 돼 있다. 참고하여 실제로 적용할 브랜치 이름으로 사용하면 된다. The `post-rewrite` hook is run by commands that replace commits, such as `git commit --amend` and `git rebase` (though not by `git filter-branch`). Its single argument is which command triggered the rewrite, and it receives a list of rewrites on `stdin`. This hook has many of the same uses as the `post-checkout` and `post-merge` hooks. +////////////////////////// After you run a successful `git checkout`, the `post-checkout` hook runs; you can use it to set up your working directory properly for your project environment. This may mean moving in large binary files that you don't want source controlled, auto-generating documentation, or something along those lines. +////////////////////////// +디렉토리에서 뭔가 할 일이 있을 때 사용한다. +그러니까 용량이 크거나 Git이 관리하지 않는 파일을 옮기거나, 문서를 자동으로 생성하는 데 쓴다. +////////////////////////// The `post-merge` hook runs after a successful `merge` command. You can use it to restore data in the working tree that Git can't track, such as permissions data. This hook can likewise validate the presence of files external to Git control that you may want copied in when the working tree changes. +////////////////////////// +`post-merge` 훅은 Merge가 끝나고 나서 실행된다. +이 훅은 파일 권한 같이 Git이 추적하지 않는 정보를 관리하는 데 사용한다. +Merge로 Working Tree가 변경될 때 Git이 관리하지 않는 파일이 원하는 대로 잘 배치됐는지 검사할 때도 좋다. The `pre-push` hook runs during `git push`, after the remote refs have been updated but before any objects have been transferred. It receives the name and location of the remote as parameters, and a list of to-be-updated refs through `stdin`. @@ -99,28 +198,53 @@ You can use it to validate a set of ref updates before a push occurs (a non-zero Git occasionally does garbage collection as part of its normal operation, by invoking `git gc --auto`. The `pre-auto-gc` hook is invoked just before the garbage collection takes place, and can be used to notify you that this is happening, or to abort the collection if now isn't a good time. +////////////////////////// ==== Server-Side Hooks +////////////////////////// +==== 서버 훅 +////////////////////////// In addition to the client-side hooks, you can use a couple of important server-side hooks as a system administrator to enforce nearly any kind of policy for your project. These scripts run before and after pushes to the server. The pre hooks can exit non-zero at any time to reject the push as well as print an error message back to the client; you can set up a push policy that's as complex as you wish. +////////////////////////// +클라이언트 훅으로도 어떤 정책을 강제할 수 있지만, 시스템 관리자에게는 서버 훅이 더 중요하다. +서버 훅은 모두 Push 전후에 실행된다. +Push 전에 실행되는 훅이 0이 아닌 값을 반환하면 해당 Push는 거절되고 클라이언트는 에러 메시지를 출력한다. 이 훅으로 아주 복잡한 Push 정책도 가능하다. ===== `pre-receive` +////////////////////////// The first script to run when handling a push from a client is `pre-receive`. It takes a list of references that are being pushed from stdin; if it exits non-zero, none of them are accepted. You can use this hook to do things like make sure none of the updated references are non-fast-forwards, or to do access control for all the refs and files they're modifying with the push. +////////////////////////// +Push하면 가장 처음 실행되는 훅은 `pre-receive` 훅이다. +이 스크립트는 표준 입력(STDIN)으로 Push하는 레퍼런스의 목록을 입력받는다. 0이 아닌 값을 반환하면 해당 레퍼런스가 전부 거절된다. +Fast-forward Push가 아니면 거절하거나, 브랜치 Push 권한을 제어하려면 이 훅에서 하는 것이 좋다. 관리자만 브랜치를 새로 Push하고 삭제할 수 있고 일반 개발자는 수정사항만 Push할 수 있게 할 수 있다. ===== `update` +////////////////////////// The `update` script is very similar to the `pre-receive` script, except that it's run once for each branch the pusher is trying to update. If the pusher is trying to push to multiple branches, `pre-receive` runs only once, whereas update runs once per branch they're pushing to. Instead of reading from stdin, this script takes three arguments: the name of the reference (branch), the SHA-1 that reference pointed to before the push, and the SHA-1 the user is trying to push. If the update script exits non-zero, only that reference is rejected; other references can still be updated. +////////////////////////// +update 스크립트는 각 브랜치마다 한 번씩 실행된다는 것을 제외하면 `pre-receive` 스크립트와 거의 같다. +한 번에 브랜치를 여러 개 Push하면 `pre-receive`는 딱 한 번만 실행되지만, update는 브랜치마다 실행된다. +이 스크립트는 표준 입력으로 데이터를 입력받는 것이 아니라 아규먼트로 브랜치 이름, 원래 가리키던 SHA-1 값, 사용자가 Push하는 SHA-1 값을 입력받는다. +update 스크립트가 0이 아닌 값을 반환하면 해당 레퍼런스만 거절되고 나머지 다른 레퍼런스는 상관없다. ===== `post-receive` +////////////////////////// The `post-receive` hook runs after the entire process is completed and can be used to update other services or notify users. It takes the same stdin data as the `pre-receive` hook. Examples include e-mailing a list, notifying a continuous integration server, or updating a ticket-tracking system – you can even parse the commit messages to see if any tickets need to be opened, modified, or closed. This script can't stop the push process, but the client doesn't disconnect until it has completed, so be careful if you try to do anything that may take a long time. +////////////////////////// +`post-receive` 훅은 Push한 후에 실행된다. 이 훅으로 사용자나 서비스에 알림 메시지를 보낼 수 있다. +그리고 `pre-receive` 훅처럼 표준 입력(STDIN)으로 레퍼런스 목록이 넘어간다. +이 훅으로 메일링리스트에 메일을 보내거나, CI(Continuous Integration) 서버나 Ticket-tracking 시스템의 정보를 수정할 수 있다. 심지어 커밋 메시지도 파싱할 수 있기 때문에 이 훅으로 Ticket을 만들고, 수정하고, 닫을 수 있다. +이 스크립트가 완전히 종료할 때까지 클라이언트와의 연결은 유지되고 Push를 중단시킬 수 없다. 그래서 이 스크립트로 시간이 오래 걸릴만한 일을 할 때는 조심해야 한다. diff --git a/book/08-customizing-git/sections/policy.asc b/book/08-customizing-git/sections/policy.asc index bbb57ab8..a92ebe08 100644 --- a/book/08-customizing-git/sections/policy.asc +++ b/book/08-customizing-git/sections/policy.asc @@ -1,25 +1,53 @@ [[_an_example_git_enforced_policy]] +////////////////////////// === An Example Git-Enforced Policy +////////////////////////// +=== 정책 구현하기 (((policy example))) +////////////////////////// In this section, you'll use what you've learned to establish a Git workflow that checks for a custom commit message format, and allows only certain users to modify certain subdirectories in a project. You'll build client scripts that help the developer know if their push will be rejected and server scripts that actually enforce the policies. +////////////////////////// +지금까지 배운 것을 한 번 적용해보자. 나름의 커밋 메시지 규칙으로 검사하고 Fast-forward Push만 허용하고 디렉토리마다 사용자의 수정 권한을 제어하는 Workflow를 만든다. +실질적으로 정책을 강제하려면 서버 훅으로 만들어야 한다. 하지만 개발자들이 Push할 수 없는 커밋은 아예 만들지 않도록 클라이언트 훅도 만든다. +////////////////////////// The scripts we'll show are written in Ruby; partly because of our intellectual inertia, but also because Ruby is easy to read, even if you can't necessarily write it. However, any language will work – all the sample hook scripts distributed with Git are in either Perl or Bash, so you can also see plenty of examples of hooks in those languages by looking at the samples. +////////////////////////// +훅 스크립트는 Ruby언어를 사용한다. 필자는 주로 사용하는 언어기도 하지만 코드가 쉽기 때문에 코드를 작성하는것은 어렵더라도 충분히 코드를 읽고 개념을 이해할 수 있을 것이다. +물론 Git은 언어를 가리지 않는다. Git이 자동으로 생성해주는 예제는 모두 Perl과 Bash로 작성돼 있다. 예제를 열어 보면 Perl과 Bash로 작성된 예제를 참고 할 수 있다. +////////////////////////// ==== Server-Side Hook +////////////////////////// +==== 서버 훅 +////////////////////////// All the server-side work will go into the `update` file in your `hooks` directory. The `update` hook runs once per branch being pushed and takes three arguments: +////////////////////////// +서버 정책은 전부 `update` 훅으로 만든다. +이 스크립트는 브랜치가 Push될 때마다 한 번 실행되고 다음 내용을 아규먼트로 받는다. +////////////////////////// * The name of the reference being pushed to * The old revision where that branch was * The new revision being pushed +////////////////////////// +* 해당 브랜치의 이름 +* 원래 브랜치가 가리키던 레퍼런스 +* 새로 Push된 레퍼런스 +////////////////////////// You also have access to the user doing the pushing if the push is being run over SSH. If you've allowed everyone to connect with a single user (like ``git'') via public-key authentication, you may have to give that user a shell wrapper that determines which user is connecting based on the public key, and set an environment variable accordingly. Here we'll assume the connecting user is in the `$USER` environment variable, so your update script begins by gathering all the information you need: +////////////////////////// +그리고 SSH를 통해서 Push하는 것이라면 누가 Push하는 지도 알 수 있다. +SSH로 접근하긴 하지만 공개키를 이용하여 개발자 모두 계정 하나로(``git'' 같은) Push하고 있다면 실제로 Push하는 사람이 누구인지 공개키를 비교하여 판별하고 환경변수를 설정해주는 스크립트가 필요하다. +아래 스크립트에서는 `$USER` 환경 변수에 현재 접속한 사용자 정보가 있다고 가정하며 `update` 스크립트는 필요한 정보를 수집하는 것으로 시작한다. [source,ruby] ---- @@ -34,19 +62,36 @@ puts "Enforcing Policies..." puts "(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})" ---- +////////////////////////// Yes, those are global variables. Don't judge – it's easier to demonstrate this way. +////////////////////////// +스크립트에서 전역변수를 쓰고 있지만 +데모의 이해를 돕기 위해서이니 너무 나무라지는 마시길 바란다. [[_enforcing_commit_message_format]] +////////////////////////// ===== Enforcing a Specific Commit-Message Format +////////////////////////// +===== 커밋 메시지 규칙 만들기 +////////////////////////// Your first challenge is to enforce that each commit message adheres to a particular format. Just to have a target, assume that each message has to include a string that looks like ``ref: 1234'' because you want each commit to link to a work item in your ticketing system. You must look at each commit being pushed up, see if that string is in the commit message, and, if the string is absent from any of the commits, exit non-zero so the push is rejected. +////////////////////////// +커밋 메시지 규칙부터 해보자. +일단 목표가 있어야 하니까 커밋 메시지에 ``ref: 1234'' 같은 스트링이 포함돼 있어야 한다고 가정하자. 보통 커밋은 이슈 트래커에 있는 이슈와 관련돼 있으니 그 이슈가 뭔지 커밋 메시지에 적어 놓으면 좋다. +Push할 때마다 커밋 메시지에 해당 스트링이 포함돼 있는지 확인한다. 만약 커밋 메시지에 해당 스트링이 없는 커밋이면 0이 아닌 값을 반환해서 Push를 거절한다. +////////////////////////// You can get a list of the SHA-1 values of all the commits that are being pushed by taking the `$newrev` and `$oldrev` values and passing them to a Git plumbing command called `git rev-list`. This is basically the `git log` command, but by default it prints out only the SHA-1 values and no other information. So, to get a list of all the commit SHAs introduced between one commit SHA and another, you can run something like this: +////////////////////////// +`$newrev`, `$oldrev` 변수와 `git rev-list`라는 Plumbing 명령어를 이용해서 Push하는 모든 커밋의 SHA-1 값을 알 수 있다. +`git log`와 근본적으로 같은 명령이고 옵션을 하나도 주지 않으면 다른 정보 없이 SHA-1 값만 보여준다. +이 명령으로 두 커밋 사이에 위치하는 커밋들의 SHA-1 값을 살펴보기 위해 아래와 같은 명령을 사용할 수 있다. [source,console] ---- @@ -58,11 +103,19 @@ dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a 17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475 ---- +////////////////////////// You can take that output, loop through each of those commit SHAs, grab the message for it, and test that message against a regular expression that looks for a pattern. +////////////////////////// +이 SHA-1 값으로 각 커밋의 메시지도 가져온다. 커밋 메시지를 가져와서 정규표현식으로 해당 패턴이 있는지 검사한다. +////////////////////////// You have to figure out how to get the commit message from each of these commits to test. To get the raw commit data, you can use another plumbing command called `git cat-file`. We'll go over all these plumbing commands in detail in <<_git_internals>>; but for now, here's what that command gives you: +////////////////////////// +커밋 메시지를 얻는 방법을 알아보자. +커밋의 raw 데이터는 `git cat-file`이라는 Plumbing 명령어로 얻을 수 있다. +<<_git_internals>> 에서 Plumbing 명령어에 대해 자세히 다루니까 지금은 커밋 메시지 얻는 것에 집중하자. [source,console] ---- @@ -75,8 +128,12 @@ committer Scott Chacon 1240030591 -0700 changed the version number ---- +////////////////////////// A simple way to get the commit message from a commit when you have the SHA-1 value is to go to the first blank line and take everything after that. You can do so with the `sed` command on Unix systems: +////////////////////////// +이 명령이 출력하는 메시지에서 커밋 메시지만 잘라내야 한다. +첫 번째 빈 줄 다음부터가 커밋 메시지니까 유닉스 명령어 `sed`로 첫 빈 줄 이후를 잘라낸다. [source,console] ---- @@ -84,9 +141,14 @@ $ git cat-file commit ca82a6 | sed '1,/^$/d' changed the version number ---- +////////////////////////// You can use that incantation to grab the commit message from each commit that is trying to be pushed and exit if you see anything that doesn't match. To exit the script and reject the push, exit non-zero. The whole method looks like this: +////////////////////////// +이제 커밋 메시지에서 찾는 패턴과 일치하는 문자열이 있는지 검사해서 있으면 통과시키고 없으면 거절한다. +스크립트가 종료할 때 0이 아닌 값을 반환하면 Push가 거절된다. +이 일을 하는 코드는 아래와 같다. [source,ruby] ---- @@ -106,20 +168,40 @@ end check_message_format ---- +////////////////////////// Putting that in your `update` script will reject updates that contain commits that have messages that don't adhere to your rule. +////////////////////////// +이 코드를 `update` 스크립트로 넣으면 규칙을 어긴 커밋은 Push할 수 없다. +////////////////////////// ===== Enforcing a User-Based ACL System +////////////////////////// +===== ACL로 사용자마다 다른 규칙 적용하기 +////////////////////////// Suppose you want to add a mechanism that uses an access control list (ACL) that specifies which users are allowed to push changes to which parts of your projects. Some people have full access, and others can only push changes to certain subdirectories or specific files. To enforce this, you'll write those rules to a file named `acl` that lives in your bare Git repository on the server. You'll have the `update` hook look at those rules, see what files are being introduced for all the commits being pushed, and determine whether the user doing the push has access to update all those files. +////////////////////////// +진행하는 프로젝트에 모듈이 여러 개 있어 모듈마다 특정 사용자들만 Push할 수 있게 ACL(Access Control List)을 설정해야 한다고 가정하자. +모든 권한을 다 가진 사람들도 있고 특정 디렉토리나 파일만 Push할 수 있는 사람도 있다. +이런 일을 강제하려면 먼저 서버의 Bare 저장소에 `acl`이라는 파일을 만들고 거기에 규칙을 기술한다. +그리고 `update` 훅에서 Push하는 파일이 무엇인지 확인하고 ACL과 비교해서 Push할 수 있는지 없는지 결정한다. +////////////////////////// The first thing you'll do is write your ACL. Here you'll use a format very much like the CVS ACL mechanism: it uses a series of lines, where the first field is `avail` or `unavail`, the next field is a comma-delimited list of the users to which the rule applies, and the last field is the path to which the rule applies (blank meaning open access). All of these fields are delimited by a pipe (`|`) character. +////////////////////////// +우선 ACL부터 작성한다. +CVS에서 사용하는 것과 비슷한 ACL을 만든다. 규칙은 한 줄에 하나씩 기술한다. 각 줄의 첫 번째 필드는 `avail`이나 `unavail`이고 두 번째 필드는 규칙을 적용할 사용자들의 목록을 CSV(Comma-Separated Values) 형식으로 적는다. 마지막 필드엔 규칙을 적용할 경로를 적는다. 만약 마지막 필드가 비워져 있으면 모든 경로를 의미한다. +이 필드는 파이프(`|`) 문자로 구분한다. +////////////////////////// In this case, you have a couple of administrators, some documentation writers with access to the `doc` directory, and one developer who only has access to the `lib` and `tests` directories, and your ACL file looks like this: +////////////////////////// +예를 하나 들어보자. 어떤 모듈의 모든 권한을 가지는 관리자도 여러 명이고 `doc` 디렉토리만 접근해서 문서를 만드는 사람도 여러 명이다. 하지만 `lib`과 `tests` 디렉토리에 접근하는 사람은 한 명이다. 이런 상황을 ACL로 만들면 아래와 같다. [source] ---- @@ -129,9 +211,14 @@ avail|schacon|lib avail|schacon|tests ---- +////////////////////////// You begin by reading this data into a structure that you can use. In this case, to keep the example simple, you'll only enforce the `avail` directives. Here is a method that gives you an associative array where the key is the user name and the value is an array of paths to which the user has write access: +////////////////////////// +이 ACL 정보는 스크립트에서 읽어 사용한다. +설명을 쉽게 하고자 여기서는 `avail`만 처리한다. +다음 메소드는 Associative Array를 반환하는데, 키는 사용자이름이고 값은 사용자가 Push할 수 있는 경로의 목록이다. [source,ruby] ---- @@ -151,7 +238,10 @@ def get_acl_access_data(acl_file) end ---- +////////////////////////// On the ACL file you looked at earlier, this `get_acl_access_data` method returns a data structure that looks like this: +////////////////////////// +이 `get_acl_access_data` 함수가 앞의 ACL 파일을 읽고 반환하는 결과는 아래와 같다. [source,ruby] ---- @@ -165,9 +255,15 @@ On the ACL file you looked at earlier, this `get_acl_access_data` method returns "ebronte"=>["doc"]} ---- +////////////////////////// Now that you have the permissions sorted out, you need to determine what paths the commits being pushed have modified, so you can make sure the user who's pushing has access to all of them. +////////////////////////// +이렇게 사용할 권한 정보를 만들었다. 이제 Push하는 파일을 그 사용자가 Push할 수 있는지 없는지 알아내야 한다. +////////////////////////// You can pretty easily see what files have been modified in a single commit with the `--name-only` option to the `git log` command (mentioned briefly in Chapter 2): +////////////////////////// +`git log` 명령에 `--name-only` 옵션을 주면 해당 커밋에서 수정된 파일이 뭔지 알려준다. (`git log` 명령은 *2장*에서 다루었다) [source,console] ---- @@ -177,7 +273,10 @@ README lib/test.rb ---- +////////////////////////// If you use the ACL structure returned from the `get_acl_access_data` method and check it against the listed files in each of the commits, you can determine whether the user has access to push all of their commits: +////////////////////////// +`get_acl_access_data` 메소드를 호출해서 ACL 정보를 구하고, 각 커밋에 들어 있는 파일 목록도 얻은 다음에, 사용자가 모든 커밋을 Push할 수 있는지 판단한다. [source,ruby] ---- @@ -209,14 +308,27 @@ end check_directory_perms ---- +////////////////////////// You get a list of new commits being pushed to your server with `git rev-list`. Then, for each of those commits, you find which files are modified and make sure the user who's pushing has access to all the paths being modified. +////////////////////////// +먼저 `git rev-list` 명령으로 서버에 Push하려는 커밋이 무엇인지 알아낸다. +그리고 각 커밋에서 수정한 파일이 어떤 것들이 있는지 찾고, 해당 사용자가 모든 파일에 대한 권한이 있는지 확인한다. +////////////////////////// Now your users can't push any commits with badly formed messages or with modified files outside of their designated paths. +////////////////////////// +이제 사용자는 메시지 규칙을 어겼거나 권한이 없는 파일이 포함된 커밋은 어떤 것도 Push하지 못한다. +////////////////////////// ===== Testing It Out +////////////////////////// +===== 새로 작성한 정책 테스트 +////////////////////////// If you run `chmod u+x .git/hooks/update`, which is the file into which you should have put all this code, and then try to push a commit with a non-compliant message, you get something like this: +////////////////////////// +이 정책을 다 구현해서 update 스크립트에 넣고 `chmod u+x .git/hooks/update` 명령으로 실행 권한을 준다. 그리고 틀린 형식으로 커밋메시지를 작성하고 Push하면 아래와 같이 실패한다. [source,console] ---- @@ -236,8 +348,12 @@ To git@gitserver:project.git error: failed to push some refs to 'git@gitserver:project.git' ---- +////////////////////////// There are a couple of interesting things here. First, you see this where the hook starts running. +////////////////////////// +정책과 관련해 하나씩 살펴보자. +먼저 훅이 실행될 때마다 다음 메시지가 출력된다. [source] ---- @@ -245,10 +361,17 @@ Enforcing Policies... (refs/heads/master) (fb8c72) (c56860) ---- +////////////////////////// Remember that you printed that out at the very beginning of your update script. Anything your script echoes to `stdout` will be transferred to the client. +////////////////////////// +이 내용은 스크립트 윗부분에서 표준출력(`stdout`)에 출력한 내용이다. +스크립트에서 표준출력으로 출력하면 클라이언트로 전송된다. +////////////////////////// The next thing you'll notice is the error message. +////////////////////////// +그리고 아래의 에러 메시지를 살펴보자. [source] ---- @@ -257,8 +380,12 @@ error: hooks/update exited with error code 1 error: hook declined to update refs/heads/master ---- +////////////////////////// The first line was printed out by you, the other two were Git telling you that the update script exited non-zero and that is what is declining your push. Lastly, you have this: +////////////////////////// +첫 번째 줄은 스크립트에서 직접 출력한 것이고 나머지 두 줄은 Git이 출력해 주는 것이다. 이 메시지는 update 스크립트에서 0이 아닌 값을 반환해서 Push할 수 없다는 메시지다. +그리고 마지막 메시지를 보자. [source] ---- @@ -267,31 +394,59 @@ To git@gitserver:project.git error: failed to push some refs to 'git@gitserver:project.git' ---- +////////////////////////// You'll see a remote rejected message for each reference that your hook declined, and it tells you that it was declined specifically because of a hook failure. +////////////////////////// +이 메시지는 훅에서 거절된 것이라고 말해주는 것이고 브랜치가 거부될 때마다 하나씩 출력된다. +////////////////////////// Furthermore, if someone tries to edit a file they don't have access to and push a commit containing it, they will see something similar. For instance, if a documentation author tries to push a commit modifying something in the `lib` directory, they see +////////////////////////// +그리고 누군가 권한이 없는 파일을 수정해서 Push해도 에러 메시지를 출력한다. +예를 들어 문서 담당자가 `lib` 디렉토리에 있는 파일을 수정해서 커밋하면 아래와 같은 메시지가 출력된다. [source] ---- [POLICY] You do not have access to push to lib/test.rb ---- +////////////////////////// From now on, as long as that `update` script is there and executable, your repository will never have a commit message without your pattern in it, and your users will be sandboxed. +////////////////////////// +이제부터는 `update` 스크립트가 항상 실행되기 때문에 커밋 메시지도 규칙대로 작성해야 하고, 권한이 있는 파일만 Push할 수 있다. +////////////////////////// ==== Client-Side Hooks +////////////////////////// +==== 클라이언트 훅 +////////////////////////// The downside to this approach is the whining that will inevitably result when your users' commit pushes are rejected. Having their carefully crafted work rejected at the last minute can be extremely frustrating and confusing; and furthermore, they will have to edit their history to correct it, which isn't always for the faint of heart. +////////////////////////// +서버 훅의 단점은 Push할 때까지 Push할 수 있는지 없는지 알 수 없다는데 있다. +기껏 공들여 정성껏 구현했는데 막상 Push할 수 없으면 곤혹스럽다. 히스토리를 제대로 고치는 일은 정신건강에 매우 해롭다. +////////////////////////// The answer to this dilemma is to provide some client-side hooks that users can run to notify them when they're doing something that the server is likely to reject. That way, they can correct any problems before committing and before those issues become more difficult to fix. Because hooks aren't transferred with a clone of a project, you must distribute these scripts some other way and then have your users copy them to their `.git/hooks` directory and make them executable. You can distribute these hooks within the project or in a separate project, but Git won't set them up automatically. +////////////////////////// +이 문제는 클라이언트 훅으로 해결한다. 클라이언트 훅으로 서버가 거부할지 말지 검사한다. +사람들은 커밋하기 전에, 그러니까 시간이 지나 고치기 어려워지기 전에 문제를 해결할 수 있다. +Clone할 때 이 훅은 전송되지 않기 때문에 다른 방법으로 동료에게 배포해야 한다. 그 훅을 가져다 `.git/hooks` 디렉토리에 복사하고 실행할 수 있게 만든다. +이 훅 파일을 프로젝트에 넣어서 배포해도 되고 Git 훅 프로젝트를 만들어서 배포해도 된다. 하지만, 자동으로 설치하는 방법은 없다. +////////////////////////// To begin, you should check your commit message just before each commit is recorded, so you know the server won't reject your changes due to badly formatted commit messages. To do this, you can add the `commit-msg` hook. If you have it read the message from the file passed as the first argument and compare that to the pattern, you can force Git to abort the commit if there is no match: +////////////////////////// +커밋 메시지부터 검사해보자. 이 훅이 있으면 커밋 메시지가 구리다고 서버가 뒤늦게 거절하지 않는다. +이것은 `commit-msg` 훅으로 구현한다. +이 훅은 커밋 메시지가 저장된 파일을 첫 번째 아규먼트로 입력받는다. 그 파일을 읽어 패턴을 검사한다. 필요한 패턴이 없으면 커밋을 중단시킨다. [source,ruby] ---- @@ -307,7 +462,10 @@ if !$regex.match(message) end ---- +////////////////////////// If that script is in place (in `.git/hooks/commit-msg`) and executable, and you commit with a message that isn't properly formatted, you see this: +////////////////////////// +이 스크립트를 `.git/hooks/commit-msg`라는 파일로 만들고 실행권한을 준다. 커밋이 메시지 규칙을 어기면 아래와 같은 메시지를 보여 준다. [source,console] ---- @@ -315,8 +473,12 @@ $ git commit -am 'test' [POLICY] Your message is not formatted correctly ---- +////////////////////////// No commit was completed in that instance. However, if your message contains the proper pattern, Git allows you to commit: +////////////////////////// +커밋하지 못했다. +하지만, 커밋 메지시를 바르게 작성하면 커밋할 수 있다. [source,console] ---- @@ -325,8 +487,12 @@ $ git commit -am 'test [ref: 132]' 1 file changed, 1 insertions(+), 0 deletions(-) ---- +////////////////////////// Next, you want to make sure you aren't modifying files that are outside your ACL scope. If your project's `.git` directory contains a copy of the ACL file you used previously, then the following `pre-commit` script will enforce those constraints for you: +////////////////////////// +그리고 아예 권한이 없는 파일을 수정 못하게 할 때는 `pre-commit` 훅을 이용한다. +사전에 `.git` 디렉토리 안에 ACL 파일을 가져다 놓고 아래와 같이 작성한다. [source,ruby] ---- @@ -358,50 +524,83 @@ end check_directory_perms ---- +////////////////////////// This is roughly the same script as the server-side part, but with two important differences. First, the ACL file is in a different place, because this script runs from your working directory, not from your `.git` directory. You have to change the path to the ACL file from this +////////////////////////// +내용은 서버 훅과 똑같지만 두 가지가 다르다. +첫째, 클라이언트 훅은 Git 디렉토리가 아니라 워킹 디렉토리에서 실행하기 때문에 ACL 파일 위치가 다르다. +그래서 ACL 파일 경로를 수정해야 한다. [source,ruby] ---- access = get_acl_access_data('acl') ---- +////////////////////////// to this: +////////////////////////// +이 부분을 아래와 같이 바꾼다. [source,ruby] ---- access = get_acl_access_data('.git/acl') ---- +////////////////////////// The other important difference is the way you get a listing of the files that have been changed. Because the server-side method looks at the log of commits, and, at this point, the commit hasn't been recorded yet, you must get your file listing from the staging area instead. Instead of +////////////////////////// +두 번째 차이점은 파일 목록을 얻는 방법이다. +서버 훅에서는 커밋에 있는 파일을 모두 찾았지만 여기서는 아직 커밋하지도 않았다. +그래서 Staging Area의 파일 목록을 이용한다. [source,ruby] ---- files_modified = `git log -1 --name-only --pretty=format:'' #{ref}` ---- +////////////////////////// you have to use +////////////////////////// +이 부분을 아래와 같이 바꾼다. [source,ruby] ---- files_modified = `git diff-index --cached --name-only HEAD` ---- +////////////////////////// But those are the only two differences – otherwise, the script works the same way. One caveat is that it expects you to be running locally as the same user you push as to the remote machine. If that is different, you must set the `$user` variable manually. +////////////////////////// +이 두 가지 점만 다르고 나머지는 똑같다. +보통은 리모트 저장소의 계정과 로컬의 계정도 같다. +다른 계정을 사용하려면 `$user` 환경변수에 누군지 알려야 한다. +////////////////////////// One other thing we can do here is make sure the user doesn't push non-fast-forwarded references. To get a reference that isn't a fast-forward, you either have to rebase past a commit you've already pushed up or try pushing a different local branch up to the same remote branch. +////////////////////////// +이렇게 훅을 이용해 Fast-forward가 아닌 Push를 하지 않도록 설정하는 것도 가능하다. +Fast-forward가 아닌 Push는 Rebase로 이미 Push한 커밋을 바꿔 버렸거나 전혀 다른 로컬 브랜치를 Push하는 경우다. +////////////////////////// Presumably, the server is already configured with `receive.denyDeletes` and `receive.denyNonFastForwards` to enforce this policy, so the only accidental thing you can try to catch is rebasing commits that have already been pushed. +////////////////////////// +이런 경우에 아마도 서버는 이미 `receive.denyDeletes` 나 `receive.denyNonFastForwards` 설정으로 이와 같은 정책을 설정해놓았을 것이다. 이렇게 되면 발생 가능한 상황은 이미 Push한 커밋을 Rebase했을 경우이다. +////////////////////////// Here is an example pre-rebase script that checks for that. It gets a list of all the commits you're about to rewrite and checks whether they exist in any of your remote references. If it sees one that is reachable from one of your remote references, it aborts the rebase. +////////////////////////// +아래는 이미 Push한 커밋을 Rebase하지 못하게 하는 pre-rebase 스크립트다. +이 스크립트는 먼저 Rebase할 커밋 목록을 구하고 커밋이 리모트 레퍼런스/브랜치에 들어 있는지 확인한다. +커밋이 한 개라도 리모트 레퍼런스/브랜치에 들어 있으면 Rebase할 수 없다. [source,ruby] ---- @@ -427,7 +626,10 @@ target_shas.each do |sha| end end ---- +////////////////////////// This script uses a syntax that wasn't covered in the Revision Selection section of Chapter 6. You get a list of commits that have already been pushed up by running this: +////////////////////////// +이 스크립트는 6장 '리비전 조회하기' 절에서 설명하지 않은 표현을 사용했다. 아래의 표현은 이미 Push한 커밋 목록을 얻어오는 부분이다. [source,ruby] ---- @@ -435,8 +637,16 @@ This script uses a syntax that wasn't covered in the Revision Selection section . ---- +////////////////////////// The `SHA^@` syntax resolves to all the parents of that commit. You're looking for any commit that is reachable from the last commit on the remote and that isn't reachable from any parent of any of the SHAs you're trying to push up – meaning it's a fast-forward. +////////////////////////// +`SHA^@`은 해당 커밋의 모든 부모를 가리킨다. +그러니까 이 명령은 지금 Push하려는 커밋에서 리모트 저장소의 커밋에 도달할 수 있는지 확인하는 명령이다. 즉, Fast-forward인지 확인하는 것이다. +////////////////////////// The main drawback to this approach is that it can be very slow and is often unnecessary – if you don't try to force the push with `-f`, the server will warn you and not accept the push. However, it's an interesting exercise and can in theory help you avoid a rebase that you might later have to go back and fix. +////////////////////////// +이 방법은 매우 느리고 보통은 필요 없다. 어차피 Fast-forward가 아닌 Push은 `-f` 옵션을 주어야 Push할 수 있다. +문제가 될만한 Rebase를 방지할 수 있다는 것을 보여주려고 이 예제를 설명했다. From 5dc048e5b7d53382f6568dbcbd6575605fa9f076 Mon Sep 17 00:00:00 2001 From: Sean Lee Date: Thu, 5 Mar 2015 19:50:41 +0900 Subject: [PATCH 2/5] chapter 8: translate added parts --- book/08-customizing-git/sections/hooks.asc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index 6b8ab9d2..264bf6a6 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -54,8 +54,12 @@ This section splits them into committing-workflow hooks, e-mail-workflow scripts [NOTE] ==== +////////////////////////// It's important to note that client-side hooks are *not* copied when you clone a repository. If your intent with these scripts is to enforce a policy, you'll probably want to do that on the server side; see the example in <<_an_example_git_enforced_policy>>. +////////////////////////// +여기서 한가지 알아둘 점은 저장소를 Clone 해도 클라이언트 훅은 복사되지 않는다는 점이다. +만든 정책이 반드시 적용되도록 하려면 서버 훅을 이용해야만 하며 작성은 <<_an_example_git_enforced_policy>> 부분을 참고한다. ==== ////////////////////////// @@ -171,9 +175,14 @@ The example `pre-rebase` hook that Git installs does this, although it makes som 이 훅으로 이미 Push한 커밋을 Rebase하지 못하게 할 수 있다. Git이 자동으로 넣어주는 `pre-rebase` 예제가 바로 그 예제다. 이 예제에는 기준 브랜치가 `next`라고 돼 있다. 참고하여 실제로 적용할 브랜치 이름으로 사용하면 된다. +////////////////////////// The `post-rewrite` hook is run by commands that replace commits, such as `git commit --amend` and `git rebase` (though not by `git filter-branch`). Its single argument is which command triggered the rewrite, and it receives a list of rewrites on `stdin`. This hook has many of the same uses as the `post-checkout` and `post-merge` hooks. +////////////////////////// +`post-rewrite` 훅은 커밋을 변경하는 명령을 실행했을 때 실행된다. 예를 들어 `git commit --amend` 이나 `git rebase` 같은 명령이 해당된다. `git filter-branch` 명령은 해당하지 않는다. +아규먼트로 커밋을 변경하게 만든 명령이 전달되고 `stdin`으로 변경된 커밋 목록이 전달된다. +훅의 용도는 `post-checkout` 이나 `post-merge` 훅과 비슷하다고 볼 수 있다. ////////////////////////// After you run a successful `git checkout`, the `post-checkout` hook runs; you can use it to set up your working directory properly for your project environment. @@ -191,12 +200,21 @@ This hook can likewise validate the presence of files external to Git control th 이 훅은 파일 권한 같이 Git이 추적하지 않는 정보를 관리하는 데 사용한다. Merge로 Working Tree가 변경될 때 Git이 관리하지 않는 파일이 원하는 대로 잘 배치됐는지 검사할 때도 좋다. +////////////////////////// The `pre-push` hook runs during `git push`, after the remote refs have been updated but before any objects have been transferred. It receives the name and location of the remote as parameters, and a list of to-be-updated refs through `stdin`. You can use it to validate a set of ref updates before a push occurs (a non-zero exit code will abort the push). +////////////////////////// +`pre-push` 훅은 `git push` 명령을 실행하면 동작하는데 리모트 정보를 업데이트 하고 난 후 리모트로 데이터를 전송하기 전에 동작한다. +리모트의 이름과 주소를 파라미터로 전달받으며 `stdin`을 통해 업데이트 할 해시 리스트를 전달받는다. +Push하기 전에 커밋이 유효한지 확인하는 용도로 사용할 수 있다. 훅에서 0이 아닌 값을 반환하면 Push를 중지시킨다. +////////////////////////// Git occasionally does garbage collection as part of its normal operation, by invoking `git gc --auto`. The `pre-auto-gc` hook is invoked just before the garbage collection takes place, and can be used to notify you that this is happening, or to abort the collection if now isn't a good time. +////////////////////////// +Git은 정상적으로 동작하는 중에도 이따금 `git gc --auto` 명령으로 가비지 컬렉션을 동작시킨다. +`pre-auto-gc` 훅은 가비지 컬렉션이 실행되기 직전에 호출되는 훅으로 가비지 컬렉션이 동작한다고 사용자에게 알려주거나 지금 시점에 가비지 컬렉션이 동작하기엔 좋지 않다고 Git에 알려주는 용도로 사용할 수 있다. ////////////////////////// ==== Server-Side Hooks From dd78b345759bb7cb6e0132d34bf4f8a6b8c8bfc8 Mon Sep 17 00:00:00 2001 From: Sean Lee Date: Thu, 5 Mar 2015 20:00:20 +0900 Subject: [PATCH 3/5] chapter 8: fix --- book/08-customizing-git/sections/config.asc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/08-customizing-git/sections/config.asc b/book/08-customizing-git/sections/config.asc index 4bad012d..867a92b4 100644 --- a/book/08-customizing-git/sections/config.asc +++ b/book/08-customizing-git/sections/config.asc @@ -472,7 +472,7 @@ or you can edit your `~/.gitconfig` file to add these lines: ////////////////////////// After all this is set, if you run diff commands such as this: ////////////////////////// -설정을 완료하고 나서 아래와 같이 diff 명령어를 실행한다: +설정을 완료하고 나서 아래와 같이 diff 명령어를 실행한다. [source,console] ---- From 6a1553854e63e630ada5f609abc42a3efa76a453 Mon Sep 17 00:00:00 2001 From: Changwoo Park Date: Fri, 3 Apr 2015 10:50:48 +0900 Subject: [PATCH 4/5] chapter 8: proofreading --- book/08-customizing-git/sections/config.asc | 10 ++++++---- book/08-customizing-git/sections/hooks.asc | 6 ++++-- book/08-customizing-git/sections/policy.asc | 5 +++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/book/08-customizing-git/sections/config.asc b/book/08-customizing-git/sections/config.asc index 867a92b4..d43cff21 100644 --- a/book/08-customizing-git/sections/config.asc +++ b/book/08-customizing-git/sections/config.asc @@ -21,7 +21,7 @@ $ git config --global user.email johndoe@example.com ////////////////////////// Now you'll learn a few of the more interesting options that you can set in this manner to customize your Git usage. ////////////////////////// -이렇게 설정하는 것들 중에서 중요한 것을 몇 가지 설명한다. +여기서는 이렇게 설정하는 것들 중에서 중요한 것만 몇 가지 배운다. ////////////////////////// First, a quick review: Git uses a series of configuration files to determine non-default behavior that you may want. @@ -52,11 +52,13 @@ Each of these ``levels'' (system, global, local) overwrites values in the previo 각 설정 파일에 중복된 설정이 있으면 설명한 ``순서대로'' 덮어쓴다. 예를 들어 `.git/config`와 `/etc/gitconfig`에 같은 설정이 들어 있다면 `.git/config`에 있는 설정을 사용한다. [NOTE] -==== ////////////////////////// +==== Git's configuration files are plain-text, so you can also set these values by manually editing the file and inserting the correct syntax. It's generally easier to run the `git config` command, though. +==== ////////////////////////// +==== 설정 파일 일반적인 텍스트파일로 쉽게 고쳐쓸 수 있다. 보통 `git config` 명령을 사용하는 것이 더 편하다. ==== @@ -229,7 +231,7 @@ But sometimes you want to ignore certain files for all repositories that you wor If your computer is running Mac OS X, you're probably familiar with `.DS_Store` files. If your preferred editor is Emacs or Vim, you know about files that end with a `~`. ////////////////////////// -한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함시키기 않을 파일을 설정할 수 있다. +한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함시키지 않을 파일을 설정할 수 있다. 예를 들어 Mac을 쓰는 사람이라면 `.DS_Store` 파일을 많이 보았을 것이다. Emacs나 Vim를 쓰다보면 이름 끝에 `~` 붙여둔 임시 파일도 있다. @@ -328,7 +330,7 @@ The default setting is almost always what you'll want. ////////////////////////// `always` 로 설정하면 터미널이든 다른 출력이든 상관없이 색칠하여 내보낸다. 대개의 경우 이 값을 설정해서 사용하지 않는다. `--color` 옵션을 사용하면 강제로 결과를 색칠해서 내도록 할 수 있기 때문이다. -기본값을 그대로 두어도 대부분의 경우에 들어맞는다. +대부분의 경우에 기본값이 낫다. ===== `color.*` diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index 264bf6a6..0f40d97c 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -38,7 +38,7 @@ I'll cover most of the major hook filenames here. ////////////////////////// 실행할 수 있는 스크립트 파일을 저장소의 `hooks` 디렉토리에 넣으면 훅 스크립트가 켜진다. 이 스크립트는 앞으로 계속 호출된다. -중요한 주요 훅에 대해서 설명한다. +여기서는 주요 훅 몇 가지에 대해서 설명한다. ////////////////////////// ==== Client-Side Hooks @@ -53,11 +53,13 @@ This section splits them into committing-workflow hooks, e-mail-workflow scripts 이 절에서는 클라이언트 훅을 커밋 Workflow 훅, E-mail Workflow 훅, 그리고 나머지로 분류해서 설명한다. [NOTE] -==== ////////////////////////// +==== It's important to note that client-side hooks are *not* copied when you clone a repository. If your intent with these scripts is to enforce a policy, you'll probably want to do that on the server side; see the example in <<_an_example_git_enforced_policy>>. +==== ////////////////////////// +==== 여기서 한가지 알아둘 점은 저장소를 Clone 해도 클라이언트 훅은 복사되지 않는다는 점이다. 만든 정책이 반드시 적용되도록 하려면 서버 훅을 이용해야만 하며 작성은 <<_an_example_git_enforced_policy>> 부분을 참고한다. ==== diff --git a/book/08-customizing-git/sections/policy.asc b/book/08-customizing-git/sections/policy.asc index a92ebe08..1b557ed8 100644 --- a/book/08-customizing-git/sections/policy.asc +++ b/book/08-customizing-git/sections/policy.asc @@ -16,7 +16,7 @@ You'll build client scripts that help the developer know if their push will be r The scripts we'll show are written in Ruby; partly because of our intellectual inertia, but also because Ruby is easy to read, even if you can't necessarily write it. However, any language will work – all the sample hook scripts distributed with Git are in either Perl or Bash, so you can also see plenty of examples of hooks in those languages by looking at the samples. ////////////////////////// -훅 스크립트는 Ruby언어를 사용한다. 필자는 주로 사용하는 언어기도 하지만 코드가 쉽기 때문에 코드를 작성하는것은 어렵더라도 충분히 코드를 읽고 개념을 이해할 수 있을 것이다. +훅 스크립트는 Ruby언어를 사용한다. 필자가 주로 사용하는 언어기도 하지만 코드가 쉽기 때문에 코드를 작성하는 것은 어렵더라도 코드를 읽고 개념을 이해할 수 있을 것이다. 물론 Git은 언어를 가리지 않는다. Git이 자동으로 생성해주는 예제는 모두 Perl과 Bash로 작성돼 있다. 예제를 열어 보면 Perl과 Bash로 작성된 예제를 참고 할 수 있다. ////////////////////////// @@ -184,7 +184,7 @@ Some people have full access, and others can only push changes to certain subdir To enforce this, you'll write those rules to a file named `acl` that lives in your bare Git repository on the server. You'll have the `update` hook look at those rules, see what files are being introduced for all the commits being pushed, and determine whether the user doing the push has access to update all those files. ////////////////////////// -진행하는 프로젝트에 모듈이 여러 개 있어 모듈마다 특정 사용자들만 Push할 수 있게 ACL(Access Control List)을 설정해야 한다고 가정하자. +진행하는 프로젝트에 모듈이 여러 개라서 모듈마다 특정 사용자들만 Push할 수 있게 ACL(Access Control List)을 설정해야 한다고 가정하자. 모든 권한을 다 가진 사람들도 있고 특정 디렉토리나 파일만 Push할 수 있는 사람도 있다. 이런 일을 강제하려면 먼저 서버의 Bare 저장소에 `acl`이라는 파일을 만들고 거기에 규칙을 기술한다. 그리고 `update` 훅에서 Push하는 파일이 무엇인지 확인하고 ACL과 비교해서 Push할 수 있는지 없는지 결정한다. @@ -626,6 +626,7 @@ target_shas.each do |sha| end end ---- + ////////////////////////// This script uses a syntax that wasn't covered in the Revision Selection section of Chapter 6. You get a list of commits that have already been pushed up by running this: ////////////////////////// From 9849b0dc7fbd38d0cbe4176cc246e371686cb061 Mon Sep 17 00:00:00 2001 From: Changwoo Park Date: Wed, 27 May 2015 19:26:44 +0900 Subject: [PATCH 5/5] chapter 8: correct typos, improve translation. --- .../sections/attributes.asc | 36 ++++++++-------- book/08-customizing-git/sections/config.asc | 42 +++++++++---------- book/08-customizing-git/sections/hooks.asc | 4 +- book/08-customizing-git/sections/policy.asc | 22 +++++----- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/book/08-customizing-git/sections/attributes.asc b/book/08-customizing-git/sections/attributes.asc index eebf8577..90d55918 100644 --- a/book/08-customizing-git/sections/attributes.asc +++ b/book/08-customizing-git/sections/attributes.asc @@ -72,8 +72,8 @@ Now, Git won't try to convert or fix CRLF issues; nor will it try to compute or You can also use the Git attributes functionality to effectively diff binary files. You do this by telling Git how to convert your binary data to a text format that can be compared via the normal diff. ////////////////////////// -Git은 바이너리 파일도 diff할 수 있다. -Git Attribute를 통해 Git이 바이너리 파일을 텍스트 포맷으로 변환하고 그 결과를 diff로 비교하도록 하는 것이다. +Git은 바이너리 파일도 Diff할 수 있다. +Git Attribute를 통해 Git이 바이너리 파일을 텍스트 포맷으로 변환하고 그 결과를 `diff` 명령으로 비교하도록 하는 것이다. ////////////////////////// First, you'll use this technique to solve one of the most annoying problems known to humanity: version-controlling Microsoft Word documents. @@ -114,17 +114,17 @@ What is the ``word'' filter? You have to set it up. Here you'll configure Git to use the `docx2txt` program to convert Word documents into readable text files, which it will then diff properly. ////////////////////////// -이것은 `*.docx` 파일의 두 버전이 무엇이 다른지 diff할 때 ``word'' 필터를 사용하라고 설정하는 것이다. +이것은 `*.docx` 파일의 두 버전이 무엇이 다른지 Diff할 때 ``word'' 필터를 사용하라고 설정하는 것이다. 그럼 ``word'' 필터는 뭘까? 이 ``word'' 필터도 정의해야 한다. -Word 문서에서 사람이 읽을 수 있는 텍스트를 추출해주는 `docx2txt` 프로그램을 사용하여 diff에 이용한다. +Word 문서에서 사람이 읽을 수 있는 텍스트를 추출해주는 `docx2txt` 프로그램을 사용하여 Diff에 이용한다. ////////////////////////// First, you'll need to install `docx2txt`; you can download it from http://docx2txt.sourceforge.net[]. Follow the instructions in the `INSTALL` file to put it somewhere your shell can find it. Next, you'll write a wrapper script to convert output to the format Git expects. Create a file that's somewhere in your path called `docx2txt`, and add these contents: ////////////////////////// -우선 `docx2txt` 프로그램을 설채히야 하는데 http://docx2txt.sourceforge.net[] 사이트에서 다운로드 할 수 있다. `INSTALL` 부분의 설치과정을 참고하여 설치하고 쉘에서 실행할 수 있도록 설정한다. +우선 `docx2txt` 프로그램을 설치해야 하는데 http://docx2txt.sourceforge.net[] 사이트에서 다운로드 할 수 있다. `INSTALL` 부분의 설치과정을 참고하여 설치하고 쉘에서 실행할 수 있도록 설정한다. 그리고 Git에서 잘 쓸 수 있도록 Wrapper 스크립트를 `docx2txt` 라는 이름으로 아래와 같이 작성한다. @@ -150,8 +150,8 @@ $ git config diff.word.textconv docx2txt Now Git knows that if it tries to do a diff between two snapshots, and any of the files end in `.docx`, it should run those files through the ``word'' filter, which is defined as the `docx2txt` program. This effectively makes nice text-based versions of your Word files before attempting to diff them. ////////////////////////// -이제 Git은 확장자가 `.docx`인 파일의 스냅샷을 diff할 때 ``word'' 필터로 정의한 `docx2txt` 프로그램을 사용한다. -이 프로그램은 Word 파일을 텍스트 파일로 변환해 주기 때문에 diff할 수 있다. +이제 Git은 확장자가 `.docx`인 파일의 스냅샷을 Diff할 때 ``word'' 필터로 정의한 `docx2txt` 프로그램을 사용한다. +이 프로그램은 Word 파일을 텍스트 파일로 변환해 주기 때문에 Diff할 수 있다. ////////////////////////// Here's an example: Chapter 1 of this book was converted to Word format and commited in a Git repository. @@ -159,7 +159,7 @@ Then a new paragraph was added. Here's what `git diff` shows: ////////////////////////// 이 책의 1장을 Word 파일로 만들어서 Git에 넣고 나서 단락 하나를 수정하고 저장하는 예를 살펴본다. -새로 단락을 하나 추가하고나서 +새로 단락을 하나 추가하고 나서 `git diff`를 실행하면 어디가 달려졌는지 확인할 수 있다. [source,console] @@ -183,17 +183,17 @@ index 0b013ca..ba25db5 100644 Git successfully and succinctly tells me that I added the string ``Testing: 1, 2, 3.'', which is correct. It's not perfect – formatting changes wouldn't show up here – but it certainly works. ////////////////////////// -Git의 diff 결과를 보면 ``Testing: 1, 2, 3.'' 부분이 추가된 것을 확인할 수 있다. -물론 텍스트 형식 같은 완전한 정보는 아니지만 어쨋든 유용하다. +`git diff` 명령의 결과를 보면 ``Testing: 1, 2, 3.'' 부분이 추가된 것을 확인할 수 있다. +물론 텍스트 형식 같은 완전한 정보는 아니지만 어쨌든 유용하다. ////////////////////////// Another interesting problem you can solve this way involves diffing image files. One way to do this is to run image files through a filter that extracts their EXIF information – metadata that is recorded with most image formats. If you download and install the `exiftool` program, you can use it to convert your images into text about the metadata, so at least the diff will show you a textual representation of any changes that happened: ////////////////////////// -이 방법으로 이미지 파일도 diff할 수 있다. +이 방법으로 이미지 파일도 Diff할 수 있다. 필터로 EXIF 정보를 추출해서 이미지 파일을 비교한다. EXIF 정보는 대부분의 이미지 파일에 들어 있는 메타데이터다. -`exiftool`이라는 프로그램을 설치하고 이미지 파일에서 메타데이터 텍스트를 추출한다. 그리고 그 결과를 diff해서 무엇이 달라졌는지 본다. +`exiftool`이라는 프로그램을 설치하고 이미지 파일에서 메타데이터 텍스트를 추출한다. 그리고 그 결과를 Diff해서 무엇이 달라졌는지 본다. [source,console] ---- @@ -283,8 +283,8 @@ $Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $ However, that result is of limited use. If you've used keyword substitution in CVS or Subversion, you can include a datestamp – the SHA isn't all that helpful, because it's fairly random and you can't tell if one SHA is older or newer than another just by looking at them. ////////////////////////// -하지만 이것은 별로 유용하지 않다. -CVS나 SVN의 키워드 치환(Keyword Substitution)을 써봤으면 날짜(Datestamp)도 가능했다는 것을 알고 있을 것이다. SHA는 그냥 해시이고 식별할 수 있을 뿐이지 다른 것을 알려주진 않는다. SHA만으로는 예전 것보다 새 것인지 오래된 것인지는 알 수 없다. +하지만, 이것은 별로 유용하지 않다. +CVS나 SVN의 키워드 치환(Keyword Substitution)을 써봤으면 날짜(Datestamp)도 가능했다는 것을 알고 있을 것이다. SHA는 그냥 해시이고 식별할 수 있을 뿐이지 다른 것을 알려주진 않는다. SHA만으로는 예전 것보다 새것인지 오래된 것인지는 알 수 없다. ////////////////////////// It turns out that you can write your own filters for doing substitutions in files on commit/checkout. @@ -317,7 +317,7 @@ image::images/clean.png[``clean'' 필터는 파일을 Stage할 때 실행된다. The original commit message for this feature gives a simple example of running all your C source code through the `indent` program before committing. You can set it up by setting the filter attribute in your `.gitattributes` file to filter `*.c` files with the ``indent'' filter: ////////////////////////// -이 기능은 사실 커밋메시지를 위한 기능이었지만 응용한다면 커밋하기 전에 `indent` 프로그램으로 C 코드 전부를 필터링하는 기능을 만들 수 있다.. +이 기능은 사실 커밋 메시지를 위한 기능이었지만 응용한다면 커밋하기 전에 `indent` 프로그램으로 C 코드 전부를 필터링하는 기능을 만들 수 있다. `*.c` 파일에 대해 indent 필터를 거치도록 `.gitattributes` 파일에 설정한다. [source] @@ -350,7 +350,7 @@ Another interesting example gets `$Date$` keyword expansion, RCS style. To do this properly, you need a small script that takes a filename, figures out the last commit date for this project, and inserts the date into the file. Here is a small Ruby script that does that: ////////////////////////// -이제 RCS 처럼 `$Date$`를 치환하는 예제을 살펴보자. +이제 RCS처럼 `$Date$`를 치환하는 예제를 살펴보자. 이 기능을 구현하려면 간단한 스크립트가 하나 필요하다. 이 스크립트는 `$Date$` 필드를 프로젝트의 마지막 커밋 일자로 치환한다. 표준 입력을 읽어서 `$Date$` 필드를 치환한다. 아래는 Ruby로 구현한 스크립트다. @@ -412,8 +412,8 @@ You can see how powerful this technique can be for customized applications. You have to be careful, though, because the `.gitattributes` file is committed and passed around with the project, but the driver (in this case, `dater`) isn't, so it won't work everywhere. When you design these filters, they should be able to fail gracefully and have the project still work properly. ////////////////////////// -프로젝트를 맞춤설정하는데 두루두루 활용하기에 매우 강력한 기능이다. -`.gitattributes` 파일은 커밋하는 파일이기 때문에 필터 드라이버(여기서는 `dater`) 설정이 되지 않은 사람에게도 배포된다. 물론 `dater` 설정이 안되어있는 사람에게는 에러가 난다. +이 기능은 매우 강력해서 입맛대로 프로젝트를 맞춤 설정할 수 있다. +`.git attributes` 파일은 커밋하는 파일이기 때문에 필터 드라이버(여기서는 `dater`) 설정이 되지 않은 사람에게도 배포된다. 물론 `dater` 설정이 안 돼 있는 사람에게는 에러가 난다. 필터를 만들 때 이런 예외 상황도 고려해서 항상 잘 동작하게 해야 한다. ////////////////////////// diff --git a/book/08-customizing-git/sections/config.asc b/book/08-customizing-git/sections/config.asc index d43cff21..d84d4402 100644 --- a/book/08-customizing-git/sections/config.asc +++ b/book/08-customizing-git/sections/config.asc @@ -21,7 +21,7 @@ $ git config --global user.email johndoe@example.com ////////////////////////// Now you'll learn a few of the more interesting options that you can set in this manner to customize your Git usage. ////////////////////////// -여기서는 이렇게 설정하는 것들 중에서 중요한 것만 몇 가지 배운다. +여기서는 이렇게 설정하는 것 중에서 중요한 것만 몇 가지 배운다. ////////////////////////// First, a quick review: Git uses a series of configuration files to determine non-default behavior that you may want. @@ -59,7 +59,7 @@ It's generally easier to run the `git config` command, though. ==== ////////////////////////// ==== -설정 파일 일반적인 텍스트파일로 쉽게 고쳐쓸 수 있다. +설정 파일 일반적인 텍스트파일로 쉽게 고쳐 쓸 수 있다. 보통 `git config` 명령을 사용하는 것이 더 편하다. ==== @@ -146,7 +146,7 @@ $ git commit ////////////////////////// Then, your editor will open to something like this for your placeholder commit message when you commit: ////////////////////////// -그러면 commit할 때 아래와 같은 메시지를 편집기에 자동으로 채워준다. +그러면 커밋할 때 아래와 같은 메시지를 편집기에 자동으로 채워준다. [source] ---- @@ -201,7 +201,7 @@ If you're making signed annotated tags (as discussed in <<_signing>>), setting y Set your key ID like so: ////////////////////////// 이 설정은 <<_signing>> 에서 설명했던 Annotated Tag를 만들 때 유용하다. 사용할 GPG 키를 설정해 둘 수 있다. -아래 처럼 GPG 키를 설정하면 서명할 때 편리하다. +아래처럼 GPG 키를 설정하면 서명할 때 편리하다. [source,console] ---- @@ -224,16 +224,16 @@ $ git tag -s ////////////////////////// You can put patterns in your project's `.gitignore` file to have Git not see them as untracked files or try to stage them when you run `git add` on them, as discussed in <<_ignoring>>. ////////////////////////// -Git에서 `git add` 명령으로 추적할 파일에 포함시키지 않을 파일은 `.gitignore`에 해당 패턴을 적으면 된다고 <<_ignoring>>에서 설명했다. +Git에서 `git add` 명령으로 추적할 파일에 포함하지 않을 파일은 `.gitignore`에 해당 패턴을 적으면 된다고 <<_ignoring>>에서 설명했다. ////////////////////////// But sometimes you want to ignore certain files for all repositories that you work with. If your computer is running Mac OS X, you're probably familiar with `.DS_Store` files. If your preferred editor is Emacs or Vim, you know about files that end with a `~`. ////////////////////////// -한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함시키지 않을 파일을 설정할 수 있다. -예를 들어 Mac을 쓰는 사람이라면 `.DS_Store` 파일을 많이 보았을 것이다. -Emacs나 Vim를 쓰다보면 이름 끝에 `~` 붙여둔 임시 파일도 있다. +한 저장소 안에서뿐 아니라 어디에서라도 Git에 포함하지 않을 파일을 설정할 수 있다. +예를 들어 Mac을 쓰는 사람이라면 `.DS_Store` 파일을 자주 보았을 것이다. +Emacs나 Vim를 쓰다 보면 이름 끝에 `~` 붙여둔 임시 파일도 있다. ////////////////////////// This setting lets you write a kind of global `.gitignore` file. @@ -250,7 +250,7 @@ If you create a `~/.gitignore_global` file with these contents: ////////////////////////// …and you run `git config --global core.excludesfile ~/.gitignore_global`, Git will never again bother you about those files. ////////////////////////// -`git config --global core.excludesfile ~/.gitignore_global` 명령으로 설정을 추가하면 더 이상 위와 같은 파일이 포함되지 않을 것이다. +`git config --global core.excludesfile ~/.gitignore_global` 명령으로 설정을 추가하면 더는 위와 같은 파일이 포함되지 않을 것이다. ===== `help.autocorrect` @@ -310,8 +310,8 @@ A number of options can help you set the coloring to your preference. Git automatically colors most of its output, but there's a master switch if you don't like this behavior. To turn off all Git's colored terminal output, do this: ////////////////////////// -Git은 기본적으로 터미널에 출력하는 결과물에 알아서 색칠하지만 이 색칠하는 기능을 끄고 싶다면 한 가지 설정만 해 두면 된다. -아래와 같은 명령을 실행하면 더 이상 색칠된 결과물을 내지 않는다. +Git은 기본적으로 터미널에 출력하는 결과물을 알아서 색칠하지만, 이 색칠하는 기능을 끄고 싶다면 한 가지 설정만 해 두면 된다. +아래와 같은 명령을 실행하면 더는 색칠된 결과물을 내지 않는다. [source,console] ---- @@ -321,7 +321,7 @@ $ git config --global color.ui false ////////////////////////// The default setting is `auto`, which colors output when it's going straight to a terminal, but omits the color-control codes when the output is redirected to a pipe or a file. ////////////////////////// -컬러 설정의 기본 값은 `auto`로 터미널에 출력할 때는 색칠하지만 결과가 리다이렉션되거나 파일로 출력되면 색칠하지 않는다. +컬러 설정의 기본 값은 `auto`로 터미널에 출력할 때는 색칠하지만, 결과가 리다이렉션되거나 파일로 출력되면 색칠하지 않는다. ////////////////////////// You can also set it to `always` to ignore the difference between terminals and pipes. @@ -329,8 +329,8 @@ You'll rarely want this; in most scenarios, if you want color codes in your redi The default setting is almost always what you'll want. ////////////////////////// `always` 로 설정하면 터미널이든 다른 출력이든 상관없이 색칠하여 내보낸다. -대개의 경우 이 값을 설정해서 사용하지 않는다. `--color` 옵션을 사용하면 강제로 결과를 색칠해서 내도록 할 수 있기 때문이다. -대부분의 경우에 기본값이 낫다. +대개 이 값을 설정해서 사용하지 않는다. `--color` 옵션을 사용하면 강제로 결과를 색칠해서 내도록 할 수 있기 때문이다. +대부분은 기본 값이 낫다. ===== `color.*` @@ -391,7 +391,7 @@ Next, you'll set up external wrapper scripts to run your commands. I'll use the Mac path for the executable; in other systems, it will be where your `p4merge` binary is installed. Set up a merge wrapper script named `extMerge` that calls your binary with all the arguments provided: ////////////////////////// -먼저 http://www.perforce.com/downloads/Perforce/[] 에서 P4Merge를 다운로드 받는다. +먼저 http://www.perforce.com/downloads/Perforce/[] 에서 P4Merge를 내려받는다. 그 후에 P4Merge에 쓸 Wrapper 스크립트를 만든다. 필자는 Mac 사용자라서 Mac 경로를 사용한다. 어떤 시스템이든 `p4merge`가 설치된 경로를 사용하면 된다. 예제에서는 `extMerge`라는 Merge용 Wrapper 스크립트를 만들고 이 스크립트로 넘어오는 모든 아규먼트를 p4merge 프로그램으로 넘긴다. @@ -444,7 +444,7 @@ This takes a number of custom settings: `merge.tool` to tell Git what strategy t So, you can either run four config commands ////////////////////////// Git config 파일에 이 스크립트를 모두 추가한다. 설정해야 하는 옵션이 좀 많다. -`merge.tool`로 무슨 Merge 도구를 사용할지, `mergetool.*.cmd`로 실제로 어떻게 명령어를 실행할지, `mergetool.trustExitCode`로 Merge 도구가 반환하는 exit 코드가 Merge의 성공여부를 나타내는지, `diff.external`은 diff할 때 실행할 명령어가 무엇인지를 설정할 때 사용한다. +`merge.tool`로 무슨 Merge 도구를 사용할지, `mergetool.*.cmd`로 실제로 어떻게 명령어를 실행할지, `mergetool.trustExitCode`로 Merge 도구가 반환하는 exit 코드가 Merge의 성공 여부를 나타내는지, `diff.external`은 diff할 때 실행할 명령어가 무엇인지를 설정할 때 사용한다. 모두 `git config` 명령으로 설정한다. [source,console] @@ -498,7 +498,7 @@ If you try to merge two branches and subsequently have merge conflicts, you can The nice thing about this wrapper setup is that you can change your diff and merge tools easily. For example, to change your `extDiff` and `extMerge` tools to run the KDiff3 tool instead, all you have to do is edit your `extMerge` file: ////////////////////////// -Wrapper를 만들어 설정해두면 다른 diff, Merge 도구로 바꾸기도 쉽다. +Wrapper를 만들어 설정해두면 다른 Diff, Merge 도구로 바꾸기도 쉽다. 예를 들어, KDiff3를 사용하도록 `extDiff`와 `extMerge` 스크립트를 수정한다. [source,console] @@ -511,7 +511,7 @@ $ cat /usr/local/bin/extMerge ////////////////////////// Now, Git will use the KDiff3 tool for diff viewing and merge conflict resolution. ////////////////////////// -이제부터 Git은 diff 결과를 보여주거나 충돌을 해결할 때 KDiff3 도구를 사용한다. +이제부터 Git은 Diff 결과를 보여주거나 충돌을 해결할 때 KDiff3 도구를 사용한다. ////////////////////////// Git comes preset to use a number of other merge-resolution tools without your having to set up the cmd configuration. @@ -553,7 +553,7 @@ environment. If run in a terminal-only session, they will fail. ////////////////////////// If you're not interested in using KDiff3 for diff but rather want to use it just for merge resolution, and the kdiff3 command is in your path, then you can run ////////////////////////// -diff 도구로는 다른 것을 사용하지만, Merge 도구로는 KDiff3를 사용하고 싶은 경우에는 kdiff3 명령을 실행경로로 넣고 아래와 같이 설정하기만 하면 된다. +Diff 도구로는 다른 것을 사용하지만, Merge 도구로는 KDiff3를 사용하고 싶은 경우에는 kdiff3 명령을 실행경로로 넣고 아래와 같이 설정하기만 하면 된다. [source,console] ---- @@ -563,7 +563,7 @@ $ git config --global merge.tool kdiff3 ////////////////////////// If you run this instead of setting up the `extMerge` and `extDiff` files, Git will use KDiff3 for merge resolution and the normal Git diff tool for diffs. ////////////////////////// -`extMerge`와 `extDiff` 파일을 만들지 않고도 이렇게 Merge 도구만 kdiff3로 설정하고 diff 도구는 Git에 원래 들어 있는 것을 사용할 수 있다. +`extMerge`와 `extDiff` 파일을 만들지 않고 이렇게 Merge 도구만 `kdiff3`로 설정하고 Diff 도구는 Git에 원래 들어 있는 것을 사용할 수 있다. ==== Formatting and Whitespace @@ -587,7 +587,7 @@ This is a subtle but incredibly annoying fact of cross-platform work; many edito ////////////////////////// 윈도에서 개발하는 동료와 함께 일하면 줄 바꿈(New Line) 문자에 문제가 생긴다. 윈도는 줄 바꿈 문자로 CR(Carriage-Return)과 LF(Line Feed) 문자를 둘 다 사용하지만, Mac과 Linux는 LF 문자만 사용한다. -아무것도 아닌 것 같지만, 크로스 플랫폼 프로젝트에서는 꽤 성가신 문제다. 윈도에서 사용하는 많은 편집기들이 자동으로 LF 스타일의 줄바꿈 스타일을 CRLF로 바꾸거나 Enter키를 입력하면 CRLF 스타일을 사용하기 때문이다. +아무것도 아닌 것 같지만, 크로스 플랫폼 프로젝트에서는 꽤 성가신 문제다. 윈도에서 사용하는 많은 편집기가 자동으로 LF 스타일의 줄 바꿈 스타일을 CRLF로 바꾸거나 Enter 키를 입력하면 CRLF 스타일을 사용하기 때문이다. ////////////////////////// Git can handle this by auto-converting CRLF line endings into LF when you add a file to the index, and vice versa when it checks out code onto your filesystem. diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index 0f40d97c..4d68cf88 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -182,8 +182,8 @@ The `post-rewrite` hook is run by commands that replace commits, such as `git co Its single argument is which command triggered the rewrite, and it receives a list of rewrites on `stdin`. This hook has many of the same uses as the `post-checkout` and `post-merge` hooks. ////////////////////////// -`post-rewrite` 훅은 커밋을 변경하는 명령을 실행했을 때 실행된다. 예를 들어 `git commit --amend` 이나 `git rebase` 같은 명령이 해당된다. `git filter-branch` 명령은 해당하지 않는다. -아규먼트로 커밋을 변경하게 만든 명령이 전달되고 `stdin`으로 변경된 커밋 목록이 전달된다. +`post-rewrite` 훅은 커밋을 변경하는 명령을 실행했을 때 실행된다. 예를 들어 `git commit --amend` 이나 `git rebase` 같은 명령이 해당한다. `git filter-branch` 명령은 해당하지 않는다. +아규먼트로 커밋을 변경하게 한 명령이 전달되고 `stdin`으로 변경된 커밋 목록이 전달된다. 훅의 용도는 `post-checkout` 이나 `post-merge` 훅과 비슷하다고 볼 수 있다. ////////////////////////// diff --git a/book/08-customizing-git/sections/policy.asc b/book/08-customizing-git/sections/policy.asc index 1b557ed8..8f23d4d4 100644 --- a/book/08-customizing-git/sections/policy.asc +++ b/book/08-customizing-git/sections/policy.asc @@ -10,13 +10,13 @@ In this section, you'll use what you've learned to establish a Git workflow that You'll build client scripts that help the developer know if their push will be rejected and server scripts that actually enforce the policies. ////////////////////////// 지금까지 배운 것을 한 번 적용해보자. 나름의 커밋 메시지 규칙으로 검사하고 Fast-forward Push만 허용하고 디렉토리마다 사용자의 수정 권한을 제어하는 Workflow를 만든다. -실질적으로 정책을 강제하려면 서버 훅으로 만들어야 한다. 하지만 개발자들이 Push할 수 없는 커밋은 아예 만들지 않도록 클라이언트 훅도 만든다. +실질적으로 정책을 강제하려면 서버 훅으로 만들어야 한다. 하지만, 개발자들이 Push할 수 없는 커밋은 아예 만들지 않도록 클라이언트 훅도 만든다. ////////////////////////// The scripts we'll show are written in Ruby; partly because of our intellectual inertia, but also because Ruby is easy to read, even if you can't necessarily write it. However, any language will work – all the sample hook scripts distributed with Git are in either Perl or Bash, so you can also see plenty of examples of hooks in those languages by looking at the samples. ////////////////////////// -훅 스크립트는 Ruby언어를 사용한다. 필자가 주로 사용하는 언어기도 하지만 코드가 쉽기 때문에 코드를 작성하는 것은 어렵더라도 코드를 읽고 개념을 이해할 수 있을 것이다. +훅 스크립트는 Ruby 언어를 사용한다. 필자가 주로 사용하는 언어기도 하지만 코드가 쉬워서 직접 작성하는 것은 어렵더라도 코드를 읽고 개념을 이해할 수 있을 것이다. 물론 Git은 언어를 가리지 않는다. Git이 자동으로 생성해주는 예제는 모두 Perl과 Bash로 작성돼 있다. 예제를 열어 보면 Perl과 Bash로 작성된 예제를 참고 할 수 있다. ////////////////////////// @@ -67,7 +67,7 @@ Yes, those are global variables. Don't judge – it's easier to demonstrate this way. ////////////////////////// 스크립트에서 전역변수를 쓰고 있지만 -데모의 이해를 돕기 위해서이니 너무 나무라지는 마시길 바란다. +데모의 이해를 돕기 위해서니 너무 나무라지는 마시길 바란다. [[_enforcing_commit_message_format]] ////////////////////////// @@ -91,7 +91,7 @@ So, to get a list of all the commit SHAs introduced between one commit SHA and a ////////////////////////// `$newrev`, `$oldrev` 변수와 `git rev-list`라는 Plumbing 명령어를 이용해서 Push하는 모든 커밋의 SHA-1 값을 알 수 있다. `git log`와 근본적으로 같은 명령이고 옵션을 하나도 주지 않으면 다른 정보 없이 SHA-1 값만 보여준다. -이 명령으로 두 커밋 사이에 위치하는 커밋들의 SHA-1 값을 살펴보기 위해 아래와 같은 명령을 사용할 수 있다. +이 명령으로 두 커밋 사이에 있는 커밋들의 SHA-1 값을 살펴보고자 아래와 같은 명령을 사용할 수 있다. [source,console] ---- @@ -106,7 +106,7 @@ dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a ////////////////////////// You can take that output, loop through each of those commit SHAs, grab the message for it, and test that message against a regular expression that looks for a pattern. ////////////////////////// -이 SHA-1 값으로 각 커밋의 메시지도 가져온다. 커밋 메시지를 가져와서 정규표현식으로 해당 패턴이 있는지 검사한다. +이 SHA-1 값으로 각 커밋의 메시지도 가져온다. 커밋 메시지를 가져와서 정규표현 식으로 해당 패턴이 있는지 검사한다. ////////////////////////// You have to figure out how to get the commit message from each of these commits to test. @@ -328,7 +328,7 @@ Now your users can't push any commits with badly formed messages or with modifie ////////////////////////// If you run `chmod u+x .git/hooks/update`, which is the file into which you should have put all this code, and then try to push a commit with a non-compliant message, you get something like this: ////////////////////////// -이 정책을 다 구현해서 update 스크립트에 넣고 `chmod u+x .git/hooks/update` 명령으로 실행 권한을 준다. 그리고 틀린 형식으로 커밋메시지를 작성하고 Push하면 아래와 같이 실패한다. +이 정책을 다 구현해서 update 스크립트에 넣고 `chmod u+x .git/hooks/update` 명령으로 실행 권한을 준다. 그리고 틀린 형식으로 커밋 메시지를 작성하고 Push하면 아래와 같이 실패한다. [source,console] ---- @@ -425,7 +425,7 @@ From now on, as long as that `update` script is there and executable, your repos The downside to this approach is the whining that will inevitably result when your users' commit pushes are rejected. Having their carefully crafted work rejected at the last minute can be extremely frustrating and confusing; and furthermore, they will have to edit their history to correct it, which isn't always for the faint of heart. ////////////////////////// -서버 훅의 단점은 Push할 때까지 Push할 수 있는지 없는지 알 수 없다는데 있다. +서버 훅의 단점은 Push할 때까지 Push할 수 있는지 없는지 알 수 없다는 데 있다. 기껏 공들여 정성껏 구현했는데 막상 Push할 수 없으면 곤혹스럽다. 히스토리를 제대로 고치는 일은 정신건강에 매우 해롭다. ////////////////////////// @@ -491,7 +491,7 @@ $ git commit -am 'test [ref: 132]' Next, you want to make sure you aren't modifying files that are outside your ACL scope. If your project's `.git` directory contains a copy of the ACL file you used previously, then the following `pre-commit` script will enforce those constraints for you: ////////////////////////// -그리고 아예 권한이 없는 파일을 수정 못하게 할 때는 `pre-commit` 훅을 이용한다. +그리고 아예 권한이 없는 파일을 수정 못 하게 할 때는 `pre-commit` 훅을 이용한다. 사전에 `.git` 디렉토리 안에 ACL 파일을 가져다 놓고 아래와 같이 작성한다. [source,ruby] @@ -585,13 +585,13 @@ If that is different, you must set the `$user` variable manually. One other thing we can do here is make sure the user doesn't push non-fast-forwarded references. To get a reference that isn't a fast-forward, you either have to rebase past a commit you've already pushed up or try pushing a different local branch up to the same remote branch. ////////////////////////// -이렇게 훅을 이용해 Fast-forward가 아닌 Push를 하지 않도록 설정하는 것도 가능하다. -Fast-forward가 아닌 Push는 Rebase로 이미 Push한 커밋을 바꿔 버렸거나 전혀 다른 로컬 브랜치를 Push하는 경우다. +이렇게 훅을 이용해 Fast-forward가 아닌 Push는 못 하게 만들 수 있다. +Fast-forward가 아닌 Push는 Rebase로 이미 Push한 커밋을 바꿔 버렸거나 전혀 다른 로컬 브랜치를 Push하지 못 하도록 하는 것이다. ////////////////////////// Presumably, the server is already configured with `receive.denyDeletes` and `receive.denyNonFastForwards` to enforce this policy, so the only accidental thing you can try to catch is rebasing commits that have already been pushed. ////////////////////////// -이런 경우에 아마도 서버는 이미 `receive.denyDeletes` 나 `receive.denyNonFastForwards` 설정으로 이와 같은 정책을 설정해놓았을 것이다. 이렇게 되면 발생 가능한 상황은 이미 Push한 커밋을 Rebase했을 경우이다. +서버에 이미 `receive.denyDeletes` 나 `receive.denyNonFastForwards` 설정을 했다면 더 좁혀진다. 이미 Push한 커밋을 Rebase해서 Push하지 못 하게 만들 때 유용하다. ////////////////////////// Here is an example pre-rebase script that checks for that.