]>
Commit | Line | Data |
---|---|---|
fcbfd5a6 LT |
1 | Git for CVS users |
2 | ================= | |
3 | ||
4 | Ok, so you're a CVS user. That's ok, it's a treatable condition, and the | |
5 | first step to recovery is admitting you have a problem. The fact that | |
6 | you are reading this file means that you may be well on that path | |
7 | already. | |
8 | ||
9 | The thing about CVS is that it absolutely sucks as a source control | |
10 | manager, and you'll thus be happy with almost anything else. Git, | |
11 | however, may be a bit _too_ different (read: "good") for your taste, and | |
12 | does a lot of things differently. | |
13 | ||
14 | One particular suckage of CVS is very hard to work around: CVS is | |
15 | basically a tool for tracking _file_ history, while git is a tool for | |
16 | tracking _project_ history. This sometimes causes problems if you are | |
1cc92ff6 | 17 | used to doing very strange things in CVS, in particular if you're doing |
fcbfd5a6 LT |
18 | things like making branches of just a subset of the project. Git can't |
19 | track that, since git never tracks things on the level of an individual | |
20 | file, only on the whole project level. | |
21 | ||
22 | The good news is that most people don't do that, and in fact most sane | |
23 | people think it's a bug in CVS that makes it tag (and check in changes) | |
24 | one file at a time. So most projects you'll ever see will use CVS | |
25 | _as_if_ it was sane. In which case you'll find it very easy indeed to | |
26 | move over to Git. | |
27 | ||
28 | First off: this is not a git tutorial. See Documentation/tutorial.txt | |
29 | for how git actually works. This is more of a random collection of | |
30 | gotcha's and notes on converting from CVS to git. | |
31 | ||
32 | Second: CVS has the notion of a "repository" as opposed to the thing | |
33 | that you're actually working in (your working directory, or your | |
34 | "checked out tree"). Git does not have that notion at all, and all git | |
35 | working directories _are_ the repositories. However, you can easily | |
36 | emulate the CVS model by having one special "global repository", which | |
37 | people can synchronize with. See details later, but in the meantime | |
1cc92ff6 TM |
38 | just keep in mind that with git, every checked out working tree will |
39 | have a full revision control history of its own. | |
fcbfd5a6 LT |
40 | |
41 | ||
42 | Importing a CVS archive | |
43 | ----------------------- | |
44 | ||
45 | Ok, you have an old project, and you want to at least give git a chance | |
46 | to see how it performs. The first thing you want to do (after you've | |
47 | gone through the git tutorial, and generally familiarized yourself with | |
48 | how to commit stuff etc in git) is to create a git'ified version of your | |
49 | CVS archive. | |
50 | ||
51 | Happily, that's very easy indeed. Git will do it for you, although git | |
52 | will need the help of a program called "cvsps": | |
53 | ||
54 | http://www.cobite.com/cvsps/ | |
55 | ||
56 | which is not actually related to git at all, but which makes CVS usage | |
57 | look almost sane (ie you almost certainly want to have it even if you | |
58 | decide to stay with CVS). However, git will want at _least_ version 2.1 | |
59 | of cvsps (available at the address above), and in fact will currently | |
60 | refuse to work with anything else. | |
61 | ||
62 | Once you've gotten (and installed) cvsps, you may or may not want to get | |
63 | any more familiar with it, but make sure it is in your path. After that, | |
64 | the magic command line is | |
65 | ||
6c9a0dc2 | 66 | git cvsimport -v -d <cvsroot> <module> <destination> |
fcbfd5a6 LT |
67 | |
68 | which will do exactly what you'd think it does: it will create a git | |
e694dbab MU |
69 | archive of the named CVS module. The new archive will be created in the |
70 | subdirectory named <destination>; it'll be created if it doesn't exist. | |
71 | Default is the local directory. | |
fcbfd5a6 | 72 | |
1cc92ff6 TM |
73 | It can take some time to actually do the conversion for a large archive |
74 | since it involves checking out from CVS every revision of every file, | |
6c9a0dc2 MU |
75 | and the conversion script is reasonably chatty unless you omit the '-v' |
76 | option, but on some not very scientific tests it averaged about twenty | |
77 | revisions per second, so a medium-sized project should not take more | |
78 | than a couple of minutes. For larger projects or remote repositories, | |
79 | the process may take longer. | |
fcbfd5a6 | 80 | |
6c9a0dc2 MU |
81 | After the (initial) import is done, the CVS archive's current head |
82 | revision will be checked out -- thus, you can start adding your own | |
83 | changes right away. | |
e694dbab MU |
84 | |
85 | The import is incremental, i.e. if you call it again next month it'll | |
6c9a0dc2 MU |
86 | fetch any CVS updates that have been happening in the meantime. The |
87 | cut-off is date-based, so don't change the branches that were imported | |
88 | from CVS. | |
89 | ||
90 | You can merge those updates (or, in fact, a different CVS branch) into | |
91 | your main branch: | |
e694dbab MU |
92 | |
93 | cg-merge <branch> | |
94 | ||
6c9a0dc2 MU |
95 | The HEAD revision from CVS is named "origin", not "HEAD", because git |
96 | already uses "HEAD". (If you don't like 'origin', use cvsimport's | |
97 | '-o' option to change it.) | |
98 | ||
fcbfd5a6 LT |
99 | |
100 | Emulating CVS behaviour | |
101 | ----------------------- | |
102 | ||
103 | ||
104 | FIXME! Talk about setting up several repositories, and pulling and | |
105 | pushing between them. Talk about merging, and branches. Some of this | |
106 | needs to be in the tutorial too. | |
107 | ||
108 | ||
109 | ||
110 | CVS annotate | |
111 | ------------ | |
b0bf8f24 | 112 | |
3c65eb18 LT |
113 | So, something has gone wrong, and you don't know whom to blame, and |
114 | you're an ex-CVS user and used to do "cvs annotate" to see who caused | |
115 | the breakage. You're looking for the "git annotate", and it's just | |
116 | claiming not to find such a script. You're annoyed. | |
117 | ||
118 | Yes, that's right. Core git doesn't do "annotate", although it's | |
119 | technically possible, and there are at least two specialized scripts out | |
120 | there that can be used to get equivalent information (see the git | |
121 | mailing list archives for details). | |
122 | ||
123 | Git has a couple of alternatives, though, that you may find sufficient | |
124 | or even superior depending on your use. One is called "git-whatchanged" | |
125 | (for obvious reasons) and the other one is called "pickaxe" ("a tool for | |
126 | the software archeologist"). | |
127 | ||
128 | The "git-whatchanged" script is a truly trivial script that can give you | |
129 | a good overview of what has changed in a file or a directory (or an | |
130 | arbitrary list of files or directories). The "pickaxe" support is an | |
131 | additional layer that can be used to further specify exactly what you're | |
132 | looking for, if you already know the specific area that changed. | |
b0bf8f24 JH |
133 | |
134 | Let's step back a bit and think about the reason why you would | |
135 | want to do "cvs annotate a-file.c" to begin with. | |
136 | ||
137 | You would use "cvs annotate" on a file when you have trouble | |
138 | with a function (or even a single "if" statement in a function) | |
139 | that happens to be defined in the file, which does not do what | |
140 | you want it to do. And you would want to find out why it was | |
141 | written that way, because you are about to modify it to suit | |
142 | your needs, and at the same time you do not want to break its | |
143 | current callers. For that, you are trying to find out why the | |
144 | original author did things that way in the original context. | |
145 | ||
146 | Many times, it may be enough to see the commit log messages of | |
147 | commits that touch the file in question, possibly along with the | |
148 | patches themselves, like this: | |
149 | ||
150 | $ git-whatchanged -p a-file.c | |
151 | ||
152 | This will show log messages and patches for each commit that | |
153 | touches a-file. | |
154 | ||
155 | This, however, may not be very useful when this file has many | |
156 | modifications that are not related to the piece of code you are | |
157 | interested in. You would see many log messages and patches that | |
158 | do not have anything to do with the piece of code you are | |
159 | interested in. As an example, assuming that you have this piece | |
160 | code that you are interested in in the HEAD version: | |
161 | ||
162 | if (frotz) { | |
163 | nitfol(); | |
164 | } | |
165 | ||
166 | you would use git-rev-list and git-diff-tree like this: | |
167 | ||
168 | $ git-rev-list HEAD | | |
169 | git-diff-tree --stdin -v -p -S'if (frotz) { | |
170 | nitfol(); | |
171 | }' | |
172 | ||
173 | We have already talked about the "--stdin" form of git-diff-tree | |
174 | command that reads the list of commits and compares each commit | |
175 | with its parents. The git-whatchanged command internally runs | |
176 | the equivalent of the above command, and can be used like this: | |
177 | ||
178 | $ git-whatchanged -p -S'if (frotz) { | |
179 | nitfol(); | |
180 | }' | |
181 | ||
182 | When the -S option is used, git-diff-tree command outputs | |
183 | differences between two commits only if one tree has the | |
184 | specified string in a file and the corresponding file in the | |
185 | other tree does not. The above example looks for a commit that | |
186 | has the "if" statement in it in a file, but its parent commit | |
187 | does not have it in the same shape in the corresponding file (or | |
188 | the other way around, where the parent has it and the commit | |
189 | does not), and the differences between them are shown, along | |
190 | with the commit message (thanks to the -v flag). It does not | |
191 | show anything for commits that do not touch this "if" statement. | |
192 | ||
193 | Also, in the original context, the same statement might have | |
194 | appeared at first in a different file and later the file was | |
195 | renamed to "a-file.c". CVS annotate would not help you to go | |
196 | back across such a rename, but GIT would still help you in such | |
197 | a situation. For that, you can give the -C flag to | |
198 | git-diff-tree, like this: | |
199 | ||
200 | $ git-whatchanged -p -C -S'if (frotz) { | |
201 | nitfol(); | |
202 | }' | |
203 | ||
204 | When the -C flag is used, file renames and copies are followed. | |
205 | So if the "if" statement in question happens to be in "a-file.c" | |
206 | in the current HEAD commit, even if the file was originally | |
207 | called "o-file.c" and then renamed in an earlier commit, or if | |
208 | the file was created by copying an existing "o-file.c" in an | |
209 | earlier commit, you will not lose track. If the "if" statement | |
210 | did not change across such rename or copy, then the commit that | |
211 | does rename or copy would not show in the output, and if the | |
212 | "if" statement was modified while the file was still called | |
213 | "o-file.c", it would find the commit that changed the statement | |
214 | when it was in "o-file.c". | |
215 | ||
216 | [ BTW, the current versions of "git-diff-tree -C" is not eager | |
217 | enough to find copies, and it will miss the fact that a-file.c | |
218 | was created by copying o-file.c unless o-file.c was somehow | |
219 | changed in the same commit.] | |
220 | ||
221 | You can use the --pickaxe-all flag in addition to the -S flag. | |
222 | This causes the differences from all the files contained in | |
223 | those two commits, not just the differences between the files | |
224 | that contain this changed "if" statement: | |
225 | ||
226 | $ git-whatchanged -p -C -S'if (frotz) { | |
227 | nitfol(); | |
228 | }' --pickaxe-all | |
229 | ||
230 | [ Side note. This option is called "--pickaxe-all" because -S | |
231 | option is internally called "pickaxe", a tool for software | |
232 | archaeologists.] |