3 분산관리식 시스템을 택한 Git은 개발자들이 history관리를 용이하게 할 수 있게 해줍니다. 그러나 프로그램의 과거를 들춰내려면 조심하세요: 당신이 소유하고 있는 파일들만 다시쓰기 하세요. 세계 각국의 나라들이 누군가 어떤 잘못을 하나하면 누가했는지 끝임없이 따지는 것처럼 만약 한 개발자가 당신이 가지고 있는 파일과 기록 (history)이 다른 파일들을 클론하여 갔을 때 추후 병합시 문제가 생길지도 모릅니다.
5 어떤 개발자들은 파일의 수정기록들이 절대로 조작되면 안되는 것이라고 믿고 있습니다. 반면에 어떤 개발자들은 수정 기록들이 깨끗하게 정리되어 보여져야 할 것만 선택하여 보여져야 한다고 합니다.
6 Git은 이렇게 다른 성향의 개발자들을 모두 포용할 수 있습니다. 클로닝, branch, 병합과 같은 기능들이 당신이 어떤 개발자 타입이던 당신의 일처리를 도와줄 것입니다. 어떻게 영리하게 사용하는지는 당신에게 달려있죠.
10 방금 commit을 했는데, 그 commit에 달린 메세지를 바꾸고 싶다고요? 그렇다면:
14 위 명령어를 사용하면 마지막으로 한 commit의 메세지를 바꿀 수 있습니다. 파일을 더하는 것을 잊어버리고 commit을 했다고요? *git add*를
17 마지막으로 했던 commit에 편집을 더 하고 싶으신가요? 그렇다면 작업 후에 다음 명령어를 쓰세요.
19 $ git commit --amend -a
23 이제 전보다 더 꼬인 상황을 마주했다고 생각합시다. 우선 당신이 긴 시간동안 작업해서 많은
24 commit을 하였다고 가정해봅시다. 그러나 당신은 그 commit들의 난잡한 구성이 마음에 들지
25 않습니다. 그리고 몇몇 commit 메세지들을 다시쓰고 싶다면:
27 $ git rebase -i HEAD~10
29 위 명령어를 사용한다면 당신의 작업용 에디터에 지난 열 개의 commit이 출력될 것입니다. 샘플을 보자면:
31 pick 5c6eb73 Added repo.or.cz link
32 pick a311a64 Reordered analogies in "Work How You Want"
33 pick 100834f Added push target to Makefile
35 여기서는 'log'와는 달리 가장 오래된 commit 부터 가장 최근의 commit의 순서로 나열되어 출력되었습니다.여기서는 5c6eb73 가 가장 오래된 commit이고 100834f이 가장 최근 commit 이죠. 그리고:
37 - 한 줄을 지움으로써 commit을 삭제합니다. 'revert' 명령어와 비슷하지만 기록에는 남지 않게 지웁니다: 이 방법은 마치 commit이 처음부터 존재하지 않던 것처럼 보여지게 해줍니다.
38 - Commit list를 재정렬하며 commit의 순서를 바꾸어 줍니다.
40 * `edit` 을 사용하여 개정시킬 commit을 마킹합니다.
41 * `reword`를 사용하여 로그메세지를 바꿉니다.
42 * `squash` 를 사용하여 전에 했던 commit과 합병합니다.
43 * `fixup` 를 사용하여 전에 했던 commit과 합병 후 log 메세지를 삭제합니다.
45 예를들어, 두번째 행의 'pick'을 'squash' 명령어로 바꾸어 봅니다:
47 pick 5c6eb73 Added repo.or.cz link
48 squash a311a64 Reordered analogies in "Work How You Want"
49 pick 100834f Added push target to Makefile
51 저장 후 프로그램을 종료하면, Git은 a311a64를 5c6eb73로 병합시킵니다. *squash* (짓누르기)는 지정된 commit을 바로 다음 commit으로 밀어붙어버린다고 생각하시면 됩니다.
53 또, Git은 로그메세지들을 합친후 나중에 편집할 수 있게 해주기도 합니다. *fixup* 명령어를
54 사용하면 이런 절차를 하지않아도 됩니다; 짓눌려진 (squash 된) 로그메세지들은 간단히 삭제되기 때문입니다.
56 *edit*을 이용하여 어떤 commit을 마킹해두었다면, Git은 같은 성향의 commit들 중에 가장
57 오래전에 했던 commit의 작업상태로 당신을 되돌려 보냅니다. 이 상태에서 아까 전 말했듯이
58 편집작업을 할 수도 있고, 그 상태에 맞는 새로운 commit을 만들수도 있습니다. 모든 수정작업이
59 만족스럽다면 다음 명령어를 사용해 앞으로 감기를 실행할 수 있습니다.:
61 $ git rebase --continue
63 Git은 다음 *edit*까지 아니면 아무런 *edit*이 없다면 현재 작업상태까지 commit을 반복실행 할것입니다.
65 새로운 rebase를 포기할 수도 있습니다:
69 그러니 commit을 부지런하게 자주하십시오: 나중에 rebase를 사용하여 정리할 수 있으니까요.
73 어떤 프로젝트를 진행하고 있습니다. 당신의 컴퓨터에서 commit을 하며 작업을 하다가
74 이제 공식적인 프로젝트 파일들이 있는 branch와 동기화 해야합니다. 이런 절차는 메인 branch에 올리기전에 거쳐야 할 과정이지요.
76 그러나 당신의 로컬 Git클론은 당신 혼자만 이해할 수 있는 수많은 기록이 뒤죽박죽 섞여있을 것입니다. 아무래도 개인적인 기록이 깨끗하게 정리되어 공식적인 기록만 볼 수 있게 된다면 좋겠지요:
78 위에서 설명했듯이 *git rebase* 명령어가 이 작업을 해줄것입니다. *--onto* 플래그를 사용하여 상호작용을 피할수도 있습니다.
80 *git help rebase*를 확인해서 좀 더 자세한 예를 한번 봐보세요. Commit을 나눌 수 있다는 걸 알게될 것입니다. 여러 branch들을 재정리할 수도있죠.
82 *rebase*는 유용한 명령어입니다. 여러가지 실험을 하기전에
83 *git clone*으로 복사본을 만들어두고 놀아보세요.
87 가끔은 어떤 그룹사진에서 포토샵으로 몇 사람지우는 기능과 같은 명령어가 필요할지도 모릅니다.
88 스탈린식 스타일로 사람을 무자비하게 지우는 명령어 말입니다. 예를들어
89 이제 어떤 프로젝트를 대중에게 공개할 시간이 왔다고 가정합니다. 그러나 어떤 파일들은
90 일반 유저들이 보지 못하도록 하고싶습니다. 당신 크레딧카드 번호를 실수로 썻다던지
91 했다면 더욱 더 그러고 싶겠지요. 이런 경우, 파일을 지우는 것 만으로는 부족합니다. 예전 commit으로 파일을 지워진 파일을 복구하는 것이 가능하기 때문이죠. 당신은 이 파일을 모든
92 commit으로 부터 없에야 할 것입니다:
94 $ git filter-branch --tree-filter 'rm top/secret/file' HEAD
96 *git help filter-branch*를 보세요. 여기서는 본 예시에 대해 설명하고 있고 더 빠른 방법을
97 제시하여 줄 것입니다. 대체적으로 *filter-branch*은 하나의 명령어만으로도
98 대량의 파일기록을 변화시킬 수 있을 것입니다.
100 그리고 +.git/refs/original+ 디렉토리는 이렇게 만든 변화가 오기 전의 기록을 보여줄 것입니다. *filter-branch* 명령어가 어떻게 작용했는지 확인하고, 필요하다면 이 디렉토리를 지우면 됩니다.
102 마지막으로, 당신의 클론을 새로운 버전의 클론으로 바꾸시면 됩니다.
107 어떤 프로젝트를 Git으로 옮겨오고 싶다고요? 다른 VCS에서 옮겨오는 것이라면, 어떤 개발자가 이미 프로젝트의 기록을 Git으로 쉽게 옮겨오는 스크립트를 써두었을지도 모릅니다.
109 아니라면, 특정 포맷으로 텍스트를 읽어 Git 기록을 처음부터 작성하여 주는
110 *git fast-import* 명령어를 확인해 보세요. 대체적으로 한번에 간편하게 프로젝트를 Git에서 사용할수 있게 해줄겁니다.
112 예를들어, '/tmp/history' 같은 임시파일에 다음 텍스트를 붙여넣기 해보세요:
113 ----------------------------------
114 commit refs/heads/master
115 committer Alice <alice@example.com> Thu, 01 Jan 1970 00:00:00 +0000
120 M 100644 inline hello.c
125 printf("Hello, world!\n");
131 commit refs/heads/master
132 committer Bob <bob@example.com> Tue, 14 Mar 2000 01:59:26 -0800
134 Replace printf() with write().
137 M 100644 inline hello.c
142 write(1, "Hello, world!\n", 14);
147 ----------------------------------
149 그리고 이 임시파일로 Git repository를 만들어보세요:
151 $ mkdir project; cd project; git init
152 $ git fast-import --date-format=rfc2822 < /tmp/history
156 $ git checkout master .
158 *git fast-export* 명령어는 아무 Git repository를 결과물이 사람들이 읽을 수
159 있는 포맷으로 바꾸어 주는 *git fast-import* 포맷으로 바꾸어 줍니다.
160 이 명령어들은 텍스트 파일들을 텍스트 파일 전용채널을 통해서
161 repository로 밀어넣기 해줍니다.
163 === 어디서부터 잘못되었을까? ===
165 당신은 몇 달전에는 잘 작동되던 프로그램이 갑자기 안 된다는 것을 발견했습니다. 아놔! 이 버그는 어디서부터 생긴 것일까요? 개발을 하면서 테스팅을 종종했더라면 진작에 알아챘을텐데요.
167 이미 그러기엔 너무 늦었습니다. 그러나 commit이라도 자주했다는 가정하에 Git은
171 $ git bisect bad HEAD
172 $ git bisect good 1b6d
174 Git에서 한 프로젝트를 자체적으로 테스팅을 실행합니다. 그리고 버그가 발견된다면:
178 버그가 더이상 없다면 위 명령어에서 "bad"를 "good"으로 바꾸세요. Git은 good 버전과 bad 버전 사이로 당신을 데려갈 겁니다. 물론 버그를 찾을 확률은 높아지지요. 몇 번이렇게 반복하다보면
179 결국엔 버그를 일으킨 commit을 찾아낼 수 있게 도와줄 것입니다. 버그찾기를 완료했다면
180 다시 처음 작업상태로 (이젠 버그가 없겠지요) 돌아가야 겠지요:
184 수동으로 테스팅하는 것보단, 다음 명령어로 테스팅을 자동화할 수 있습니다:
186 $ git bisect run my_script
188 Git 은 기존 대비할 스크립트에 약간의 변화를 주어서 이것이 좋은 변화인지
189 안 좋은 변화인지 체크합니다: 좋은 변화는 0으로 무시해야할 변화는 125로
190 안 좋은 변화는 1과 127사이의 번호로 테스팅을 종료합니다. 마이너스 숫자는
191 이분화 (bisect)를 강제종료하지요.
193 당신은 이것보다 더 많은 일을 할 수 있습니다. 도움말은 이분화를 시각화해주는 방법과,
194 이분화 기록을 다시보는 방법, 이미 확인된 이상없는 변화들은 건너띄어 테스팅을 가속 시켜주는 기능들을 배우실 수 있습니다.
198 다른 VCS들과 같이 Git은 누군가를 탓할 수 있는 기능이 있습니다:
202 이 명령어를 사용하면 누가 언제 마지막으로 어느 부분을 작업하였는지 표시하여 줍니다. 다른 VCS들과는 달리 모든 작업은 오프라인에서 진행됩니다.
206 중앙관리식 VCS에서는 파일들의 기록 변경은 어려울 뿐만아니라
207 관리자만이 변경할 수 있습니다. 클론, branch 만들기와 병합하기는
208 네트워크를 통해서만 할 수 있는 작업들입니다. 브라우징 기록보기, commit하기
209 역시 중앙관리식 VCS에서는 네트워크를 통해야만 합니다. 어떤 시스템에서는
210 네트워크 연결이 되어야지만 자기 자신이 작업한 기록을 보거나 편집할 수 있습니다.
212 중앙관리식 VCS는 개발자의 수가 늘어남에 비례해서 더 많은 네트워크 통신을
213 요구하기 때문에 오프라인에서 작업하는 것보다 비경제적일 수 밖에 없습니다. 그리고
214 제일 중요한 것은 모든 개발자들이 고급명령어들을 적재적소에 쓰지 않는다면
215 모든 작업이 어느정도는 무조건 느릴 수 밖에 없다는 것입니다. 극적인 경우에는
216 아주 기본적인 명령어 역시 잘못하면 느려질 수 밖에 없습니다. 무거운
217 명령어를 써야한다면 일의 효율성은 나쁜영향을 받을 수 밖에 없습니다.
219 저는 직접 이런 상황들을 겪어보았습니다. Git은 제가 사용한 가장 먼저 사용한 VCS였죠. 저는 Git의 여러기능들을 당연하다 생각하고 금방 적응하였습니다.
220 저는 당연히 다른 VCS들 역시 Git이 제공하는 기능들을 가지고 있을 것이라고
221 생각하였습니다: VCS를 선택하는 것은 텍스트 에디터나 웹 브라우저를
222 선택하는 것과 같은 맥락일 것이라고 생각하였습니다.
224 제가 나중에 강제로 중앙관리식 VCS를 사용하게 되었을땐 완전 쇼킹이였죠. 불안정한 인터넷연결은
225 Git을 사용할 때 중요치 않습니다. 그러나 이러한 인터넷연결은 로컬디스크에서 작업하는 것
226 만큼은 효율적 일수는 없죠. 그리고 저는 어떤 명령어는 연결 딜레이를 고려함에 따라
227 습관적으로 쓰지 않고있는 걸 시간이 지나며 깨달았습니다. 이런 습관은 제가 원하는 방식대로 작업을 할 수 없게하는 방해물들이었죠.
229 어쩔 수 없이 느린 명령어를 사용할 때는 저의 작업효율에 치명타를 입히기
230 일쑤였죠. 네트워크로 처리되야하는 작업이 완료되길 기다리면서 이메일 확인 및 다른 문서작업을 하며
231 시간을 때웠습니다. 그러다가 원래하던 작업에 돌아가면 다시 무엇을 했었는지
232 기억을 해내는데 시간이 많이 허비된 경험이 잦았습니다. 인간은 환경변화에
233 적응을 할 수는 있으나 그 적응이 결코 빠르진 않죠.
235 일을 하면서 발생하는 아이러니한 비극도 존재했죠: 네트워크 상황이 원활하지 않을 것이라는 걸 아는 개발자들은 미래에 딜레이를 줄이기위해 지금 하는 작업들이 오히려 현재 트래픽을 더 잡아먹을 수가
236 있다는 것입니다. 모든 개발자들이 네트워크를 원활하게하는 노력을 할수록 오히려 서로에게 해가 될 수있다는 것입니다. 이게 무슨 아이러니한 일입니까?