4 So you're a CVS user. That's OK, it's a treatable condition. The job of
5 this document is to put you on the road to recovery, by helping you
6 convert an existing cvs repository to git, and by showing you how to use a
7 git repository in a cvs-like fashion.
9 Some basic familiarity with git is required. This
10 link:tutorial.html[tutorial introduction to git] should be sufficient.
12 First, note some ways that git differs from CVS:
14 * Commits are atomic and project-wide, not per-file as in CVS.
16 * Offline work is supported: you can make multiple commits locally,
17 then submit them when you're ready.
19 * Branching is fast and easy.
21 * Every working tree contains a repository with a full copy of the
22 project history, and no repository is inherently more important than
23 any other. However, you can emulate the CVS model by designating a
24 single shared repository which people can synchronize with; see below
27 Importing a CVS archive
28 -----------------------
30 First, install version 2.1 or higher of cvsps from
31 link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make
32 sure it is in your path. The magic command line is then
34 -------------------------------------------
35 $ git cvsimport -v -d <cvsroot> -C <destination> <module>
36 -------------------------------------------
38 This puts a git archive of the named CVS module in the directory
39 <destination>, which will be created if necessary. The -v option makes
40 the conversion script very chatty.
42 The import checks out from CVS every revision of every file. Reportedly
43 cvsimport can average some twenty revisions per second, so for a
44 medium-sized project this should not take more than a couple of minutes.
45 Larger projects or remote repositories may take longer.
47 The main trunk is stored in the git branch named `origin`, and additional
48 CVS branches are stored in git branches with the same names. The most
49 recent version of the main trunk is also left checked out on the `master`
50 branch, so you can start adding your own changes right away.
52 The import is incremental, so if you call it again next month it will
53 fetch any CVS updates that have been made in the meantime. For this to
54 work, you must not modify the imported branches; instead, create new
55 branches for your own changes, and merge in the imported branches as
61 CVS users are accustomed to giving a group of developers commit access to
62 a common repository. In the next section we'll explain how to do this
63 with git. However, the distributed nature of git allows other development
64 models, and you may want to first consider whether one of them might be a
65 better fit for your project.
67 For example, you can choose a single person to maintain the project's
68 primary public repository. Other developers then clone this repository
69 and each work in their own clone. When they have a series of changes that
70 they're happy with, they ask the maintainer to pull from the branch
71 containing the changes. The maintainer reviews their changes and pulls
72 them into the primary repository, which other developers pull from as
73 necessary to stay coordinated. The Linux kernel and other projects use
74 variants of this model.
76 With a small group, developers may just pull changes from each other's
77 repositories without the need for a central maintainer.
79 Emulating the CVS Development Model
80 -----------------------------------
82 Start with an ordinary git working directory containing the project, and
83 remove the checked-out files, keeping just the bare .git directory:
85 ------------------------------------------------
86 $ mv project/.git /pub/repo.git
88 ------------------------------------------------
90 Next, give every team member read/write access to this repository. One
91 easy way to do this is to give all the team members ssh access to the
92 machine where the repository is hosted. If you don't want to give them a
93 full shell on the machine, there is a restricted shell which only allows
94 users to do git pushes and pulls; see gitlink:git-shell[1].
96 Put all the committers in the same group, and make the repository
97 writable by that group:
99 ------------------------------------------------
100 $ chgrp -R $group repo.git
101 $ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
102 $ GIT_DIR=repo.git git repo-config core.sharedrepository true
103 ------------------------------------------------
105 Make sure committers have a umask of at most 027, so that the directories
106 they create are writable and searchable by other group members.
108 Suppose this repository is now set up in /pub/repo.git on the host
109 foo.com. Then as an individual committer you can clone the shared
112 ------------------------------------------------
113 $ git clone foo.com:/pub/repo.git/ my-project
115 ------------------------------------------------
117 and hack away. The equivalent of `cvs update` is
119 ------------------------------------------------
121 ------------------------------------------------
123 which merges in any work that others might have done since the clone
127 ================================
128 The first `git clone` places the following in the
129 `my-project/.git/remotes/origin` file, and that's why the previous step
130 and the next step both work.
132 URL: foo.com:/pub/project.git/ my-project
135 ================================
137 You can update the shared repository with your changes using:
139 ------------------------------------------------
140 $ git push origin master
141 ------------------------------------------------
143 If someone else has updated the repository more recently, `git push`, like
144 `cvs commit`, will complain, in which case you must pull any changes
145 before attempting the push again.
147 In the `git push` command above we specify the name of the remote branch
148 to update (`master`). If we leave that out, `git push` tries to update
149 any branches in the remote repository that have the same name as a branch
150 in the local repository. So the last `push` can be done with either of:
154 $ git push repo.shared.xz:/pub/scm/project.git/
157 as long as the shared repository does not have any branches
162 Because of this behavior, if the shared repository and the developer's
163 repository both have branches named `origin`, then a push like the above
164 attempts to update the `origin` branch in the shared repository from the
165 developer's `origin` branch. The results may be unexpected, so it's
166 usually best to remove any branch named `origin` from the shared
170 Advanced Shared Repository Management
171 -------------------------------------
173 Git allows you to specify scripts called "hooks" to be run at certain
174 points. You can use these, for example, to send all commits to the shared
175 repository to a mailing list. See link:hooks.txt[Hooks used by git].
177 You can enforce finer grained permissions using update hooks. See
178 link:howto/update-hook-example.txt[Controlling access to branches using
184 So, something has gone wrong, and you don't know whom to blame, and
185 you're an ex-CVS user and used to do "cvs annotate" to see who caused
186 the breakage. You're looking for the "git annotate", and it's just
187 claiming not to find such a script. You're annoyed.
189 Yes, that's right. Core git doesn't do "annotate", although it's
190 technically possible, and there are at least two specialized scripts out
191 there that can be used to get equivalent information (see the git
192 mailing list archives for details).
194 git has a couple of alternatives, though, that you may find sufficient
195 or even superior depending on your use. One is called "git-whatchanged"
196 (for obvious reasons) and the other one is called "pickaxe" ("a tool for
197 the software archaeologist").
199 The "git-whatchanged" script is a truly trivial script that can give you
200 a good overview of what has changed in a file or a directory (or an
201 arbitrary list of files or directories). The "pickaxe" support is an
202 additional layer that can be used to further specify exactly what you're
203 looking for, if you already know the specific area that changed.
205 Let's step back a bit and think about the reason why you would
206 want to do "cvs annotate a-file.c" to begin with.
208 You would use "cvs annotate" on a file when you have trouble
209 with a function (or even a single "if" statement in a function)
210 that happens to be defined in the file, which does not do what
211 you want it to do. And you would want to find out why it was
212 written that way, because you are about to modify it to suit
213 your needs, and at the same time you do not want to break its
214 current callers. For that, you are trying to find out why the
215 original author did things that way in the original context.
217 Many times, it may be enough to see the commit log messages of
218 commits that touch the file in question, possibly along with the
219 patches themselves, like this:
221 $ git-whatchanged -p a-file.c
223 This will show log messages and patches for each commit that
226 This, however, may not be very useful when this file has many
227 modifications that are not related to the piece of code you are
228 interested in. You would see many log messages and patches that
229 do not have anything to do with the piece of code you are
230 interested in. As an example, assuming that you have this piece
231 of code that you are interested in in the HEAD version:
237 you would use git-rev-list and git-diff-tree like this:
239 $ git-rev-list HEAD |
240 git-diff-tree --stdin -v -p -S'if (frotz) {
244 We have already talked about the "\--stdin" form of git-diff-tree
245 command that reads the list of commits and compares each commit
246 with its parents (otherwise you should go back and read the tutorial).
247 The git-whatchanged command internally runs
248 the equivalent of the above command, and can be used like this:
250 $ git-whatchanged -p -S'if (frotz) {
254 When the -S option is used, git-diff-tree command outputs
255 differences between two commits only if one tree has the
256 specified string in a file and the corresponding file in the
257 other tree does not. The above example looks for a commit that
258 has the "if" statement in it in a file, but its parent commit
259 does not have it in the same shape in the corresponding file (or
260 the other way around, where the parent has it and the commit
261 does not), and the differences between them are shown, along
262 with the commit message (thanks to the -v flag). It does not
263 show anything for commits that do not touch this "if" statement.
265 Also, in the original context, the same statement might have
266 appeared at first in a different file and later the file was
267 renamed to "a-file.c". CVS annotate would not help you to go
268 back across such a rename, but git would still help you in such
269 a situation. For that, you can give the -C flag to
270 git-diff-tree, like this:
272 $ git-whatchanged -p -C -S'if (frotz) {
276 When the -C flag is used, file renames and copies are followed.
277 So if the "if" statement in question happens to be in "a-file.c"
278 in the current HEAD commit, even if the file was originally
279 called "o-file.c" and then renamed in an earlier commit, or if
280 the file was created by copying an existing "o-file.c" in an
281 earlier commit, you will not lose track. If the "if" statement
282 did not change across such a rename or copy, then the commit that
283 does rename or copy would not show in the output, and if the
284 "if" statement was modified while the file was still called
285 "o-file.c", it would find the commit that changed the statement
286 when it was in "o-file.c".
288 NOTE: The current version of "git-diff-tree -C" is not eager
289 enough to find copies, and it will miss the fact that a-file.c
290 was created by copying o-file.c unless o-file.c was somehow
291 changed in the same commit.
293 You can use the --pickaxe-all flag in addition to the -S flag.
294 This causes the differences from all the files contained in
295 those two commits, not just the differences between the files
296 that contain this changed "if" statement:
298 $ git-whatchanged -p -C -S'if (frotz) {
302 NOTE: This option is called "--pickaxe-all" because -S
303 option is internally called "pickaxe", a tool for software