1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
\r
2 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
\r
3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
\r
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
\r
6 <meta name="generator" content="AsciiDoc 7.0.1" />
\r
7 <style type="text/css">
\r
9 p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
\r
11 border: 1px solid red;
\r
16 margin: 1em 5% 1em 5%;
\r
20 a:visited { color: fuchsia; }
\r
34 h1, h2, h3, h4, h5, h6 {
\r
36 font-family: sans-serif;
\r
38 margin-bottom: 0.5em;
\r
43 border-bottom: 2px solid silver;
\r
46 border-bottom: 2px solid silver;
\r
56 border: 1px solid silver;
\r
61 margin-bottom: 0.5em;
\r
71 font-family: sans-serif;
\r
78 font-family: sans-serif;
\r
82 font-family: sans-serif;
\r
84 border-top: 2px solid silver;
\r
90 padding-bottom: 0.5em;
\r
94 padding-bottom: 0.5em;
\r
98 div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
\r
99 div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
\r
100 div.admonitionblock {
\r
103 margin-bottom: 1.5em;
\r
105 div.admonitionblock {
\r
107 margin-bottom: 2.5em;
\r
110 div.content { /* Block element content. */
\r
114 /* Block element titles. */
\r
115 div.title, caption.title {
\r
116 font-family: sans-serif;
\r
120 margin-bottom: 0.5em;
\r
126 td div.title:first-child {
\r
129 div.content div.title:first-child {
\r
132 div.content + div.title {
\r
136 div.sidebarblock > div.content {
\r
137 background: #ffffee;
\r
138 border: 1px solid silver;
\r
142 div.listingblock > div.content {
\r
143 border: 1px solid silver;
\r
144 background: #f4f4f4;
\r
148 div.quoteblock > div.content {
\r
149 padding-left: 2.0em;
\r
151 div.quoteblock .attribution {
\r
155 div.admonitionblock .icon {
\r
156 vertical-align: top;
\r
159 text-decoration: underline;
\r
161 padding-right: 0.5em;
\r
163 div.admonitionblock td.content {
\r
164 padding-left: 0.5em;
\r
165 border-left: 2px solid silver;
\r
168 div.exampleblock > div.content {
\r
169 border-left: 2px solid silver;
\r
173 div.verseblock div.content {
\r
177 div.imageblock div.content { padding-left: 0; }
\r
178 div.imageblock img { border: 1px solid silver; }
\r
179 span.image img { border-style: none; }
\r
183 margin-bottom: 0.8em;
\r
188 font-style: italic;
\r
190 dd > *:first-child {
\r
195 list-style-position: outside;
\r
198 list-style-type: lower-alpha;
\r
201 div.tableblock > table {
\r
202 border-color: #527bbd;
\r
206 font-family: sans-serif;
\r
215 margin-bottom: 0.8em;
\r
218 vertical-align: top;
\r
219 font-style: italic;
\r
220 padding-right: 0.8em;
\r
223 vertical-align: top;
\r
227 div#footer-badges { display: none; }
\r
229 /* Workarounds for IE6's broken and incomplete CSS2. */
\r
231 div.sidebar-content {
\r
232 background: #ffffee;
\r
233 border: 1px solid silver;
\r
236 div.sidebar-title, div.image-title {
\r
237 font-family: sans-serif;
\r
240 margin-bottom: 0.5em;
\r
243 div.listingblock div.content {
\r
244 border: 1px solid silver;
\r
245 background: #f4f4f4;
\r
249 div.quoteblock-content {
\r
250 padding-left: 2.0em;
\r
253 div.exampleblock-content {
\r
254 border-left: 2px solid silver;
\r
255 padding-left: 0.5em;
\r
258 <title>git for CVS users</title>
\r
262 <h1>git for CVS users</h1>
\r
264 <div id="preamble">
\r
265 <div class="sectionbody">
\r
266 <p>So you're a CVS user. That's ok, it's a treatable condition. The job of
\r
267 this document is to put you on the road to recovery, by helping you
\r
268 convert an existing cvs repository to git, and by showing you how to use a
\r
269 git repository in a cvs-like fashion.</p>
\r
270 <p>Some basic familiarity with git is required. This
\r
271 <a href="tutorial.html">tutorial introduction to git</a> should be sufficient.</p>
\r
272 <p>First, note some ways that git differs from CVS:</p>
\r
276 Commits are atomic and project-wide, not per-file as in CVS.
\r
281 Offline work is supported: you can make multiple commits locally,
\r
282 then submit them when you're ready.
\r
287 Branching is fast and easy.
\r
292 Every working tree contains a repository with a full copy of the
\r
293 project history, and no repository is inherently more important than
\r
294 any other. However, you can emulate the CVS model by designating a
\r
295 single shared repository which people can synchronize with; see below
\r
302 <h2>Importing a CVS archive</h2>
\r
303 <div class="sectionbody">
\r
304 <p>First, install version 2.1 or higher of cvsps from
\r
305 <a href="http://www.cobite.com/cvsps/">http://www.cobite.com/cvsps/</a> and make
\r
306 sure it is in your path. The magic command line is then</p>
\r
307 <div class="listingblock">
\r
308 <div class="content">
\r
309 <pre><tt>$ git cvsimport -v -d <cvsroot> -C <destination> <module></tt></pre>
\r
311 <p>This puts a git archive of the named CVS module in the directory
\r
312 <destination>, which will be created if necessary. The -v option makes
\r
313 the conversion script very chatty.</p>
\r
314 <p>The import checks out from CVS every revision of every file. Reportedly
\r
315 cvsimport can average some twenty revisions per second, so for a
\r
316 medium-sized project this should not take more than a couple of minutes.
\r
317 Larger projects or remote repositories may take longer.</p>
\r
318 <p>The main trunk is stored in the git branch named <tt>origin</tt>, and additional
\r
319 CVS branches are stored in git branches with the same names. The most
\r
320 recent version of the main trunk is also left checked out on the <tt>master</tt>
\r
321 branch, so you can start adding your own changes right away.</p>
\r
322 <p>The import is incremental, so if you call it again next month it will
\r
323 fetch any CVS updates that have been made in the meantime. For this to
\r
324 work, you must not modify the imported branches; instead, create new
\r
325 branches for your own changes, and merge in the imported branches as
\r
328 <h2>Development Models</h2>
\r
329 <div class="sectionbody">
\r
330 <p>CVS users are accustomed to giving a group of developers commit access to
\r
331 a common repository. In the next section we'll explain how to do this
\r
332 with git. However, the distributed nature of git allows other development
\r
333 models, and you may want to first consider whether one of them might be a
\r
334 better fit for your project.</p>
\r
335 <p>For example, you can choose a single person to maintain the project's
\r
336 primary public repository. Other developers then clone this repository
\r
337 and each work in their own clone. When they have a series of changes that
\r
338 they're happy with, they ask the maintainer to pull from the branch
\r
339 containing the changes. The maintainer reviews their changes and pulls
\r
340 them into the primary repository, which other developers pull from as
\r
341 necessary to stay coordinated. The Linux kernel and other projects use
\r
342 variants of this model.</p>
\r
343 <p>With a small group, developers may just pull changes from each other's
\r
344 repositories without the need for a central maintainer.</p>
\r
346 <h2>Emulating the CVS Development Model</h2>
\r
347 <div class="sectionbody">
\r
348 <p>Start with an ordinary git working directory containing the project, and
\r
349 remove the checked-out files, keeping just the bare .git directory:</p>
\r
350 <div class="listingblock">
\r
351 <div class="content">
\r
352 <pre><tt>$ mv project/.git /pub/repo.git
\r
353 $ rm -r project/</tt></pre>
\r
355 <p>Next, give every team member read/write access to this repository. One
\r
356 easy way to do this is to give all the team members ssh access to the
\r
357 machine where the repository is hosted. If you don't want to give them a
\r
358 full shell on the machine, there is a restricted shell which only allows
\r
359 users to do git pushes and pulls; see <a href="git-shell.html">git-shell(1)</a>.</p>
\r
360 <p>Put all the committers should in the same group, and make the repository
\r
361 writable by that group:</p>
\r
362 <div class="listingblock">
\r
363 <div class="content">
\r
364 <pre><tt>$ chgrp -R $group repo.git
\r
365 $ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
\r
366 $ GIT_DIR=repo.git git repo-config core.sharedrepository true</tt></pre>
\r
368 <p>Make sure committers have a umask of at most 027, so that the directories
\r
369 they create are writable and searchable by other group members.</p>
\r
370 <p>Suppose this repository is now set up in /pub/repo.git on the host
\r
371 foo.com. Then as an individual commiter you can clone the shared
\r
373 <div class="listingblock">
\r
374 <div class="content">
\r
375 <pre><tt>$ git clone foo.com:/pub/repo.git/ my-project
\r
376 $ cd my-project</tt></pre>
\r
378 <p>and hack away. The equivalent of <tt>cvs update</tt> is</p>
\r
379 <div class="listingblock">
\r
380 <div class="content">
\r
381 <pre><tt>$ git pull origin</tt></pre>
\r
383 <p>which merges in any work that others might have done since the clone
\r
385 <div class="admonitionblock">
\r
388 <div class="title">Note</div>
\r
390 <td class="content">
\r
391 <p>The first <tt>git clone</tt> places the following in the
\r
392 <tt>my-project/.git/remotes/origin</tt> file, and that's why the previous step
\r
393 and the next step both work.</p>
\r
394 <div class="listingblock">
\r
395 <div class="content">
\r
396 <pre><tt>URL: foo.com:/pub/project.git/ my-project
\r
397 Pull: master:origin</tt></pre>
\r
402 <p>You can update the shared repository with your changes using:</p>
\r
403 <div class="listingblock">
\r
404 <div class="content">
\r
405 <pre><tt>$ git push origin master</tt></pre>
\r
407 <p>If someone else has updated the repository more recently, <tt>git push</tt>, like
\r
408 <tt>cvs commit</tt>, will complain, in which case you must pull any changes
\r
409 before attempting the push again.</p>
\r
410 <p>In the <tt>git push</tt> command above we specify the name of the remote branch
\r
411 to update (<tt>master</tt>). If we leave that out, <tt>git push</tt> tries to update
\r
412 any branches in the remote repository that have the same name as a branch
\r
413 in the local repository. So the last <tt>push</tt> can be done with either of:</p>
\r
414 <div class="listingblock">
\r
415 <div class="content">
\r
416 <pre><tt>$ git push origin
\r
417 $ git push repo.shared.xz:/pub/scm/project.git/</tt></pre>
\r
419 <p>as long as the shared repository does not have any branches
\r
420 other than <tt>master</tt>.</p>
\r
421 <div class="admonitionblock">
\r
424 <div class="title">Note</div>
\r
426 <td class="content">
\r
427 <p>Because of this behaviour, if the shared repository and the developer's
\r
428 repository both have branches named <tt>origin</tt>, then a push like the above
\r
429 attempts to update the <tt>origin</tt> branch in the shared repository from the
\r
430 developer's <tt>origin</tt> branch. The results may be unexpected, so it's
\r
431 usually best to remove any branch named <tt>origin</tt> from the shared
\r
437 <h2>Advanced Shared Repository Management</h2>
\r
438 <div class="sectionbody">
\r
439 <p>Git allows you to specify scripts called "hooks" to be run at certain
\r
440 points. You can use these, for example, to send all commits to the shared
\r
441 repository to a mailing list. See <a href="hooks.txt">Hooks used by git</a>.</p>
\r
442 <p>You can enforce finer grained permissions using update hooks. See
\r
443 <a href="howto/update-hook-example.txt">Controlling access to branches using
\r
444 update hooks</a>.</p>
\r
446 <h2>CVS annotate</h2>
\r
447 <div class="sectionbody">
\r
448 <p>So, something has gone wrong, and you don't know whom to blame, and
\r
449 you're an ex-CVS user and used to do "cvs annotate" to see who caused
\r
450 the breakage. You're looking for the "git annotate", and it's just
\r
451 claiming not to find such a script. You're annoyed.</p>
\r
452 <p>Yes, that's right. Core git doesn't do "annotate", although it's
\r
453 technically possible, and there are at least two specialized scripts out
\r
454 there that can be used to get equivalent information (see the git
\r
455 mailing list archives for details).</p>
\r
456 <p>git has a couple of alternatives, though, that you may find sufficient
\r
457 or even superior depending on your use. One is called "git-whatchanged"
\r
458 (for obvious reasons) and the other one is called "pickaxe" ("a tool for
\r
459 the software archaeologist").</p>
\r
460 <p>The "git-whatchanged" script is a truly trivial script that can give you
\r
461 a good overview of what has changed in a file or a directory (or an
\r
462 arbitrary list of files or directories). The "pickaxe" support is an
\r
463 additional layer that can be used to further specify exactly what you're
\r
464 looking for, if you already know the specific area that changed.</p>
\r
465 <p>Let's step back a bit and think about the reason why you would
\r
466 want to do "cvs annotate a-file.c" to begin with.</p>
\r
467 <p>You would use "cvs annotate" on a file when you have trouble
\r
468 with a function (or even a single "if" statement in a function)
\r
469 that happens to be defined in the file, which does not do what
\r
470 you want it to do. And you would want to find out why it was
\r
471 written that way, because you are about to modify it to suit
\r
472 your needs, and at the same time you do not want to break its
\r
473 current callers. For that, you are trying to find out why the
\r
474 original author did things that way in the original context.</p>
\r
475 <p>Many times, it may be enough to see the commit log messages of
\r
476 commits that touch the file in question, possibly along with the
\r
477 patches themselves, like this:</p>
\r
478 <div class="literalblock">
\r
479 <div class="content">
\r
480 <pre><tt>$ git-whatchanged -p a-file.c</tt></pre>
\r
482 <p>This will show log messages and patches for each commit that
\r
483 touches a-file.</p>
\r
484 <p>This, however, may not be very useful when this file has many
\r
485 modifications that are not related to the piece of code you are
\r
486 interested in. You would see many log messages and patches that
\r
487 do not have anything to do with the piece of code you are
\r
488 interested in. As an example, assuming that you have this piece
\r
489 of code that you are interested in in the HEAD version:</p>
\r
490 <div class="literalblock">
\r
491 <div class="content">
\r
492 <pre><tt>if (frotz) {
\r
496 <p>you would use git-rev-list and git-diff-tree like this:</p>
\r
497 <div class="literalblock">
\r
498 <div class="content">
\r
499 <pre><tt>$ git-rev-list HEAD |
\r
500 git-diff-tree --stdin -v -p -S'if (frotz) {
\r
504 <p>We have already talked about the "--stdin" form of git-diff-tree
\r
505 command that reads the list of commits and compares each commit
\r
506 with its parents (otherwise you should go back and read the tutorial).
\r
507 The git-whatchanged command internally runs
\r
508 the equivalent of the above command, and can be used like this:</p>
\r
509 <div class="literalblock">
\r
510 <div class="content">
\r
511 <pre><tt>$ git-whatchanged -p -S'if (frotz) {
\r
515 <p>When the -S option is used, git-diff-tree command outputs
\r
516 differences between two commits only if one tree has the
\r
517 specified string in a file and the corresponding file in the
\r
518 other tree does not. The above example looks for a commit that
\r
519 has the "if" statement in it in a file, but its parent commit
\r
520 does not have it in the same shape in the corresponding file (or
\r
521 the other way around, where the parent has it and the commit
\r
522 does not), and the differences between them are shown, along
\r
523 with the commit message (thanks to the -v flag). It does not
\r
524 show anything for commits that do not touch this "if" statement.</p>
\r
525 <p>Also, in the original context, the same statement might have
\r
526 appeared at first in a different file and later the file was
\r
527 renamed to "a-file.c". CVS annotate would not help you to go
\r
528 back across such a rename, but git would still help you in such
\r
529 a situation. For that, you can give the -C flag to
\r
530 git-diff-tree, like this:</p>
\r
531 <div class="literalblock">
\r
532 <div class="content">
\r
533 <pre><tt>$ git-whatchanged -p -C -S'if (frotz) {
\r
537 <p>When the -C flag is used, file renames and copies are followed.
\r
538 So if the "if" statement in question happens to be in "a-file.c"
\r
539 in the current HEAD commit, even if the file was originally
\r
540 called "o-file.c" and then renamed in an earlier commit, or if
\r
541 the file was created by copying an existing "o-file.c" in an
\r
542 earlier commit, you will not lose track. If the "if" statement
\r
543 did not change across such a rename or copy, then the commit that
\r
544 does rename or copy would not show in the output, and if the
\r
545 "if" statement was modified while the file was still called
\r
546 "o-file.c", it would find the commit that changed the statement
\r
547 when it was in "o-file.c".</p>
\r
548 <div class="admonitionblock">
\r
551 <div class="title">Note</div>
\r
553 <td class="content">The current version of "git-diff-tree -C" is not eager
\r
554 enough to find copies, and it will miss the fact that a-file.c
\r
555 was created by copying o-file.c unless o-file.c was somehow
\r
556 changed in the same commit.</td>
\r
559 <p>You can use the —pickaxe-all flag in addition to the -S flag.
\r
560 This causes the differences from all the files contained in
\r
561 those two commits, not just the differences between the files
\r
562 that contain this changed "if" statement:</p>
\r
563 <div class="literalblock">
\r
564 <div class="content">
\r
565 <pre><tt>$ git-whatchanged -p -C -S'if (frotz) {
\r
567 }' --pickaxe-all</tt></pre>
\r
569 <div class="admonitionblock">
\r
572 <div class="title">Note</div>
\r
574 <td class="content">This option is called "—pickaxe-all" because -S
\r
575 option is internally called "pickaxe", a tool for software
\r
576 archaeologists.</td>
\r
581 <div id="footer-text">
\r
582 Last updated 30-Jan-2006 23:10:24 PDT
\r