blob: 63e5d1ec9995a018790cbfe03b5b89e6bfc243a7 [file] [log] [blame]
Junio C Hamano1a4e8412005-12-27 08:17:231<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4<head>
5<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
Junio C Hamano341071d2006-06-04 07:24:486<meta name="generator" content="AsciiDoc 7.0.2" />
Junio C Hamano1a4e8412005-12-27 08:17:237<style type="text/css">
8/* Debug borders */
9p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
10/*
11 border: 1px solid red;
12*/
13}
14
15body {
16 margin: 1em 5% 1em 5%;
17}
18
19a { color: blue; }
20a:visited { color: fuchsia; }
21
22em {
23 font-style: italic;
24}
25
26strong {
27 font-weight: bold;
28}
29
30tt {
31 color: navy;
32}
33
34h1, h2, h3, h4, h5, h6 {
35 color: #527bbd;
36 font-family: sans-serif;
37 margin-top: 1.2em;
38 margin-bottom: 0.5em;
39 line-height: 1.3;
40}
41
42h1 {
43 border-bottom: 2px solid silver;
44}
45h2 {
46 border-bottom: 2px solid silver;
47 padding-top: 0.5em;
48}
49
50div.sectionbody {
51 font-family: serif;
52 margin-left: 0;
53}
54
55hr {
56 border: 1px solid silver;
57}
58
59p {
60 margin-top: 0.5em;
61 margin-bottom: 0.5em;
62}
63
64pre {
65 padding: 0;
66 margin: 0;
67}
68
69span#author {
70 color: #527bbd;
71 font-family: sans-serif;
72 font-weight: bold;
73 font-size: 1.2em;
74}
75span#email {
76}
77span#revision {
78 font-family: sans-serif;
79}
80
81div#footer {
82 font-family: sans-serif;
83 font-size: small;
84 border-top: 2px solid silver;
85 padding-top: 0.5em;
86 margin-top: 4.0em;
87}
88div#footer-text {
89 float: left;
90 padding-bottom: 0.5em;
91}
92div#footer-badges {
93 float: right;
94 padding-bottom: 0.5em;
95}
96
97div#preamble,
98div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
99div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
100div.admonitionblock {
101 margin-right: 10%;
102 margin-top: 1.5em;
103 margin-bottom: 1.5em;
104}
105div.admonitionblock {
106 margin-top: 2.5em;
107 margin-bottom: 2.5em;
108}
109
110div.content { /* Block element content. */
111 padding: 0;
112}
113
114/* Block element titles. */
115div.title, caption.title {
116 font-family: sans-serif;
117 font-weight: bold;
118 text-align: left;
119 margin-top: 1.0em;
120 margin-bottom: 0.5em;
121}
122div.title + * {
123 margin-top: 0;
124}
125
126td div.title:first-child {
127 margin-top: 0.0em;
128}
129div.content div.title:first-child {
130 margin-top: 0.0em;
131}
132div.content + div.title {
133 margin-top: 0.0em;
134}
135
136div.sidebarblock > div.content {
137 background: #ffffee;
138 border: 1px solid silver;
139 padding: 0.5em;
140}
141
142div.listingblock > div.content {
143 border: 1px solid silver;
144 background: #f4f4f4;
145 padding: 0.5em;
146}
147
148div.quoteblock > div.content {
149 padding-left: 2.0em;
150}
151div.quoteblock .attribution {
152 text-align: right;
153}
154
155div.admonitionblock .icon {
156 vertical-align: top;
157 font-size: 1.1em;
158 font-weight: bold;
159 text-decoration: underline;
160 color: #527bbd;
161 padding-right: 0.5em;
162}
163div.admonitionblock td.content {
164 padding-left: 0.5em;
165 border-left: 2px solid silver;
166}
167
168div.exampleblock > div.content {
169 border-left: 2px solid silver;
170 padding: 0.5em;
171}
172
173div.verseblock div.content {
174 white-space: pre;
175}
176
177div.imageblock div.content { padding-left: 0; }
178div.imageblock img { border: 1px solid silver; }
179span.image img { border-style: none; }
180
181dl {
182 margin-top: 0.8em;
183 margin-bottom: 0.8em;
184}
185dt {
186 margin-top: 0.5em;
187 margin-bottom: 0;
188 font-style: italic;
189}
190dd > *:first-child {
191 margin-top: 0;
192}
193
194ul, ol {
195 list-style-position: outside;
196}
197ol.olist2 {
198 list-style-type: lower-alpha;
199}
200
201div.tableblock > table {
202 border-color: #527bbd;
203 border-width: 3px;
204}
205thead {
206 font-family: sans-serif;
207 font-weight: bold;
208}
209tfoot {
210 font-weight: bold;
211}
212
213div.hlist {
214 margin-top: 0.8em;
215 margin-bottom: 0.8em;
216}
217td.hlist1 {
218 vertical-align: top;
219 font-style: italic;
220 padding-right: 0.8em;
221}
222td.hlist2 {
223 vertical-align: top;
224}
225
226@media print {
227 div#footer-badges { display: none; }
228}
229/* Workarounds for IE6's broken and incomplete CSS2. */
230
231div.sidebar-content {
232 background: #ffffee;
233 border: 1px solid silver;
234 padding: 0.5em;
235}
236div.sidebar-title, div.image-title {
237 font-family: sans-serif;
238 font-weight: bold;
239 margin-top: 0.0em;
240 margin-bottom: 0.5em;
241}
242
243div.listingblock div.content {
244 border: 1px solid silver;
245 background: #f4f4f4;
246 padding: 0.5em;
247}
248
249div.quoteblock-content {
250 padding-left: 2.0em;
251}
252
253div.exampleblock-content {
254 border-left: 2px solid silver;
255 padding-left: 0.5em;
256}
257</style>
258<title>git for CVS users</title>
259</head>
260<body>
261<div id="header">
262<h1>git for CVS users</h1>
263</div>
264<div id="preamble">
265<div class="sectionbody">
Junio C Hamano341071d2006-06-04 07:24:48266<p>So you're a CVS user. That's OK, it's a treatable condition. The job of
Junio C Hamanocfa7ad02006-01-31 07:10:49267this document is to put you on the road to recovery, by helping you
268convert an existing cvs repository to git, and by showing you how to use a
269git repository in a cvs-like fashion.</p>
270<p>Some basic familiarity with git is required. This
271<a href="tutorial.html">tutorial introduction to git</a> should be sufficient.</p>
272<p>First, note some ways that git differs from CVS:</p>
273<ul>
274<li>
275<p>
276Commits are atomic and project-wide, not per-file as in CVS.
277</p>
278</li>
279<li>
280<p>
281Offline work is supported: you can make multiple commits locally,
282 then submit them when you're ready.
283</p>
284</li>
285<li>
286<p>
287Branching is fast and easy.
288</p>
289</li>
290<li>
291<p>
292Every working tree contains a repository with a full copy of the
293 project history, and no repository is inherently more important than
294 any other. However, you can emulate the CVS model by designating a
295 single shared repository which people can synchronize with; see below
296 for details.
297</p>
298</li>
299</ul>
Junio C Hamano1a4e8412005-12-27 08:17:23300</div>
301</div>
302<h2>Importing a CVS archive</h2>
303<div class="sectionbody">
Junio C Hamanocfa7ad02006-01-31 07:10:49304<p>First, install version 2.1 or higher of cvsps from
305<a href="http://www.cobite.com/cvsps/">http://www.cobite.com/cvsps/</a> and make
306sure it is in your path. The magic command line is then</p>
307<div class="listingblock">
Junio C Hamano1a4e8412005-12-27 08:17:23308<div class="content">
Junio C Hamanocfa7ad02006-01-31 07:10:49309<pre><tt>$ git cvsimport -v -d &lt;cvsroot&gt; -C &lt;destination&gt; &lt;module&gt;</tt></pre>
Junio C Hamano1a4e8412005-12-27 08:17:23310</div></div>
Junio C Hamanocfa7ad02006-01-31 07:10:49311<p>This puts a git archive of the named CVS module in the directory
312&lt;destination&gt;, which will be created if necessary. The -v option makes
313the conversion script very chatty.</p>
314<p>The import checks out from CVS every revision of every file. Reportedly
315cvsimport can average some twenty revisions per second, so for a
316medium-sized project this should not take more than a couple of minutes.
317Larger projects or remote repositories may take longer.</p>
318<p>The main trunk is stored in the git branch named <tt>origin</tt>, and additional
319CVS branches are stored in git branches with the same names. The most
320recent version of the main trunk is also left checked out on the <tt>master</tt>
321branch, so you can start adding your own changes right away.</p>
322<p>The import is incremental, so if you call it again next month it will
323fetch any CVS updates that have been made in the meantime. For this to
324work, you must not modify the imported branches; instead, create new
325branches for your own changes, and merge in the imported branches as
326necessary.</p>
Junio C Hamano1a4e8412005-12-27 08:17:23327</div>
Junio C Hamanocfa7ad02006-01-31 07:10:49328<h2>Development Models</h2>
Junio C Hamano1a4e8412005-12-27 08:17:23329<div class="sectionbody">
Junio C Hamanocfa7ad02006-01-31 07:10:49330<p>CVS users are accustomed to giving a group of developers commit access to
331a common repository. In the next section we'll explain how to do this
332with git. However, the distributed nature of git allows other development
333models, and you may want to first consider whether one of them might be a
334better fit for your project.</p>
335<p>For example, you can choose a single person to maintain the project's
336primary public repository. Other developers then clone this repository
337and each work in their own clone. When they have a series of changes that
338they're happy with, they ask the maintainer to pull from the branch
339containing the changes. The maintainer reviews their changes and pulls
340them into the primary repository, which other developers pull from as
341necessary to stay coordinated. The Linux kernel and other projects use
342variants of this model.</p>
343<p>With a small group, developers may just pull changes from each other's
344repositories without the need for a central maintainer.</p>
345</div>
346<h2>Emulating the CVS Development Model</h2>
347<div class="sectionbody">
348<p>Start with an ordinary git working directory containing the project, and
349remove the checked-out files, keeping just the bare .git directory:</p>
350<div class="listingblock">
351<div class="content">
352<pre><tt>$ mv project/.git /pub/repo.git
353$ rm -r project/</tt></pre>
354</div></div>
355<p>Next, give every team member read/write access to this repository. One
356easy way to do this is to give all the team members ssh access to the
357machine where the repository is hosted. If you don't want to give them a
358full shell on the machine, there is a restricted shell which only allows
359users to do git pushes and pulls; see <a href="git-shell.html">git-shell(1)</a>.</p>
360<p>Put all the committers should in the same group, and make the repository
361writable by that group:</p>
362<div class="listingblock">
363<div class="content">
364<pre><tt>$ chgrp -R $group repo.git
365$ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
366$ GIT_DIR=repo.git git repo-config core.sharedrepository true</tt></pre>
367</div></div>
368<p>Make sure committers have a umask of at most 027, so that the directories
369they create are writable and searchable by other group members.</p>
370<p>Suppose this repository is now set up in /pub/repo.git on the host
Junio C Hamano33db4372006-06-07 19:51:45371foo.com. Then as an individual committer you can clone the shared
Junio C Hamanocfa7ad02006-01-31 07:10:49372repository:</p>
373<div class="listingblock">
374<div class="content">
375<pre><tt>$ git clone foo.com:/pub/repo.git/ my-project
376$ cd my-project</tt></pre>
377</div></div>
378<p>and hack away. The equivalent of <tt>cvs update</tt> is</p>
379<div class="listingblock">
380<div class="content">
381<pre><tt>$ git pull origin</tt></pre>
382</div></div>
383<p>which merges in any work that others might have done since the clone
384operation.</p>
385<div class="admonitionblock">
386<table><tr>
387<td class="icon">
388<div class="title">Note</div>
389</td>
390<td class="content">
391<p>The first <tt>git clone</tt> places the following in the
392<tt>my-project/.git/remotes/origin</tt> file, and that's why the previous step
393and the next step both work.</p>
394<div class="listingblock">
395<div class="content">
396<pre><tt>URL: foo.com:/pub/project.git/ my-project
397Pull: master:origin</tt></pre>
398</div></div>
399</td>
400</tr></table>
401</div>
402<p>You can update the shared repository with your changes using:</p>
403<div class="listingblock">
404<div class="content">
405<pre><tt>$ git push origin master</tt></pre>
406</div></div>
407<p>If someone else has updated the repository more recently, <tt>git push</tt>, like
408<tt>cvs commit</tt>, will complain, in which case you must pull any changes
409before attempting the push again.</p>
410<p>In the <tt>git push</tt> command above we specify the name of the remote branch
411to update (<tt>master</tt>). If we leave that out, <tt>git push</tt> tries to update
412any branches in the remote repository that have the same name as a branch
413in the local repository. So the last <tt>push</tt> can be done with either of:</p>
414<div class="listingblock">
415<div class="content">
416<pre><tt>$ git push origin
417$ git push repo.shared.xz:/pub/scm/project.git/</tt></pre>
418</div></div>
419<p>as long as the shared repository does not have any branches
420other than <tt>master</tt>.</p>
421<div class="admonitionblock">
422<table><tr>
423<td class="icon">
424<div class="title">Note</div>
425</td>
426<td class="content">
Junio C Hamano341071d2006-06-04 07:24:48427<p>Because of this behavior, if the shared repository and the developer's
Junio C Hamanocfa7ad02006-01-31 07:10:49428repository both have branches named <tt>origin</tt>, then a push like the above
429attempts to update the <tt>origin</tt> branch in the shared repository from the
430developer's <tt>origin</tt> branch. The results may be unexpected, so it's
431usually best to remove any branch named <tt>origin</tt> from the shared
432repository.</p>
433</td>
434</tr></table>
435</div>
436</div>
437<h2>Advanced Shared Repository Management</h2>
438<div class="sectionbody">
439<p>Git allows you to specify scripts called "hooks" to be run at certain
440points. You can use these, for example, to send all commits to the shared
441repository to a mailing list. See <a href="hooks.txt">Hooks used by git</a>.</p>
442<p>You can enforce finer grained permissions using update hooks. See
443<a href="howto/update-hook-example.txt">Controlling access to branches using
444update hooks</a>.</p>
Junio C Hamano1a4e8412005-12-27 08:17:23445</div>
446<h2>CVS annotate</h2>
447<div class="sectionbody">
448<p>So, something has gone wrong, and you don't know whom to blame, and
449you're an ex-CVS user and used to do "cvs annotate" to see who caused
450the breakage. You're looking for the "git annotate", and it's just
451claiming not to find such a script. You're annoyed.</p>
452<p>Yes, that's right. Core git doesn't do "annotate", although it's
453technically possible, and there are at least two specialized scripts out
454there that can be used to get equivalent information (see the git
455mailing list archives for details).</p>
456<p>git has a couple of alternatives, though, that you may find sufficient
457or even superior depending on your use. One is called "git-whatchanged"
458(for obvious reasons) and the other one is called "pickaxe" ("a tool for
Junio C Hamano235a91e2006-01-07 01:13:58459the software archaeologist").</p>
Junio C Hamano1a4e8412005-12-27 08:17:23460<p>The "git-whatchanged" script is a truly trivial script that can give you
461a good overview of what has changed in a file or a directory (or an
462arbitrary list of files or directories). The "pickaxe" support is an
463additional layer that can be used to further specify exactly what you're
464looking for, if you already know the specific area that changed.</p>
465<p>Let's step back a bit and think about the reason why you would
466want to do "cvs annotate a-file.c" to begin with.</p>
467<p>You would use "cvs annotate" on a file when you have trouble
468with a function (or even a single "if" statement in a function)
469that happens to be defined in the file, which does not do what
470you want it to do. And you would want to find out why it was
471written that way, because you are about to modify it to suit
472your needs, and at the same time you do not want to break its
473current callers. For that, you are trying to find out why the
474original author did things that way in the original context.</p>
475<p>Many times, it may be enough to see the commit log messages of
476commits that touch the file in question, possibly along with the
477patches themselves, like this:</p>
478<div class="literalblock">
479<div class="content">
480<pre><tt>$ git-whatchanged -p a-file.c</tt></pre>
481</div></div>
482<p>This will show log messages and patches for each commit that
483touches a-file.</p>
484<p>This, however, may not be very useful when this file has many
485modifications that are not related to the piece of code you are
486interested in. You would see many log messages and patches that
487do not have anything to do with the piece of code you are
488interested in. As an example, assuming that you have this piece
489of code that you are interested in in the HEAD version:</p>
490<div class="literalblock">
491<div class="content">
492<pre><tt>if (frotz) {
493 nitfol();
494}</tt></pre>
495</div></div>
496<p>you would use git-rev-list and git-diff-tree like this:</p>
497<div class="literalblock">
498<div class="content">
499<pre><tt>$ git-rev-list HEAD |
500 git-diff-tree --stdin -v -p -S'if (frotz) {
501 nitfol();
502}'</tt></pre>
503</div></div>
504<p>We have already talked about the "--stdin" form of git-diff-tree
505command that reads the list of commits and compares each commit
506with its parents (otherwise you should go back and read the tutorial).
507The git-whatchanged command internally runs
508the equivalent of the above command, and can be used like this:</p>
509<div class="literalblock">
510<div class="content">
511<pre><tt>$ git-whatchanged -p -S'if (frotz) {
512 nitfol();
513}'</tt></pre>
514</div></div>
515<p>When the -S option is used, git-diff-tree command outputs
516differences between two commits only if one tree has the
517specified string in a file and the corresponding file in the
518other tree does not. The above example looks for a commit that
519has the "if" statement in it in a file, but its parent commit
520does not have it in the same shape in the corresponding file (or
521the other way around, where the parent has it and the commit
522does not), and the differences between them are shown, along
523with the commit message (thanks to the -v flag). It does not
524show anything for commits that do not touch this "if" statement.</p>
525<p>Also, in the original context, the same statement might have
526appeared at first in a different file and later the file was
527renamed to "a-file.c". CVS annotate would not help you to go
528back across such a rename, but git would still help you in such
529a situation. For that, you can give the -C flag to
530git-diff-tree, like this:</p>
531<div class="literalblock">
532<div class="content">
533<pre><tt>$ git-whatchanged -p -C -S'if (frotz) {
534 nitfol();
535}'</tt></pre>
536</div></div>
537<p>When the -C flag is used, file renames and copies are followed.
538So if the "if" statement in question happens to be in "a-file.c"
539in the current HEAD commit, even if the file was originally
540called "o-file.c" and then renamed in an earlier commit, or if
541the file was created by copying an existing "o-file.c" in an
542earlier commit, you will not lose track. If the "if" statement
543did not change across such a rename or copy, then the commit that
544does rename or copy would not show in the output, and if the
545"if" statement was modified while the file was still called
546"o-file.c", it would find the commit that changed the statement
547when it was in "o-file.c".</p>
548<div class="admonitionblock">
549<table><tr>
550<td class="icon">
551<div class="title">Note</div>
552</td>
553<td class="content">The current version of "git-diff-tree -C" is not eager
554 enough to find copies, and it will miss the fact that a-file.c
555 was created by copying o-file.c unless o-file.c was somehow
556 changed in the same commit.</td>
557</tr></table>
558</div>
559<p>You can use the &#8212;pickaxe-all flag in addition to the -S flag.
560This causes the differences from all the files contained in
561those two commits, not just the differences between the files
562that contain this changed "if" statement:</p>
563<div class="literalblock">
564<div class="content">
565<pre><tt>$ git-whatchanged -p -C -S'if (frotz) {
566 nitfol();
567}' --pickaxe-all</tt></pre>
568</div></div>
569<div class="admonitionblock">
570<table><tr>
571<td class="icon">
572<div class="title">Note</div>
573</td>
574<td class="content">This option is called "&#8212;pickaxe-all" because -S
575 option is internally called "pickaxe", a tool for software
576 archaeologists.</td>
577</tr></table>
578</div>
579</div>
580<div id="footer">
581<div id="footer-text">
Junio C Hamano33db4372006-06-07 19:51:45582Last updated 07-Jun-2006 19:51:36 UTC
Junio C Hamano1a4e8412005-12-27 08:17:23583</div>
584</div>
585</body>
586</html>