X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=Documentation%2Fcvs-migration.txt;h=8e09beaa799dbff462b258e5593fd5c79c91312a;hb=0d313b2b7bb219542473a25ad042f4b990e69a45;hp=57436f00783a7f6682431b24a5719effd04faf32;hpb=5e80092f7e6db09a40a62e837ca3f74f0bc5ad73;p=git.git diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index 57436f007..8e09beaa7 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -1,247 +1,171 @@ git for CVS users ================= -Ok, so you're a CVS user. That's ok, it's a treatable condition, and the -first step to recovery is admitting you have a problem. The fact that -you are reading this file means that you may be well on that path -already. - -The thing about CVS is that it absolutely sucks as a source control -manager, and you'll thus be happy with almost anything else. git, -however, may be a bit 'too' different (read: "good") for your taste, and -does a lot of things differently. - -One particular suckage of CVS is very hard to work around: CVS is -basically a tool for tracking 'file' history, while git is a tool for -tracking 'project' history. This sometimes causes problems if you are -used to doing very strange things in CVS, in particular if you're doing -things like making branches of just a subset of the project. git can't -track that, since git never tracks things on the level of an individual -file, only on the whole project level. - -The good news is that most people don't do that, and in fact most sane -people think it's a bug in CVS that makes it tag (and check in changes) -one file at a time. So most projects you'll ever see will use CVS -'as if' it was sane. In which case you'll find it very easy indeed to -move over to git. - -First off: this is not a git tutorial. See -link:tutorial.html[Documentation/tutorial.txt] for how git -actually works. This is more of a random collection of gotcha's -and notes on converting from CVS to git. - -Second: CVS has the notion of a "repository" as opposed to the thing -that you're actually working in (your working directory, or your -"checked out tree"). git does not have that notion at all, and all git -working directories 'are' the repositories. However, you can easily -emulate the CVS model by having one special "global repository", which -people can synchronize with. See details later, but in the meantime -just keep in mind that with git, every checked out working tree will -have a full revision control history of its own. +Git differs from CVS in that every working tree contains a repository with +a full copy of the project history, and no repository is inherently more +important than any other. However, you can emulate the CVS model by +designating a single shared repository which people can synchronize with; +this document explains how to do that. + +Some basic familiarity with git is required. This +link:tutorial.html[tutorial introduction to git] should be sufficient. + +Developing against a shared repository +-------------------------------------- + +Suppose a shared repository is set up in /pub/repo.git on the host +foo.com. Then as an individual committer you can clone the shared +repository over ssh with: + +------------------------------------------------ +$ git clone foo.com:/pub/repo.git/ my-project +$ cd my-project +------------------------------------------------ + +and hack away. The equivalent of `cvs update` is + +------------------------------------------------ +$ git pull origin +------------------------------------------------ + +which merges in any work that others might have done since the clone +operation. If there are uncommitted changes in your working tree, commit +them first before running git pull. + +[NOTE] +================================ +The `pull` command knows where to get updates from because of certain +configuration variables that were set by the first `git clone` +command; see `git repo-config -l` and the gitlink:git-repo-config[1] man +page for details. +================================ + +You can update the shared repository with your changes by first committing +your changes, and then using the gitlink:git-push[1] command: + +------------------------------------------------ +$ git push origin master +------------------------------------------------ + +to "push" those commits to the shared repository. If someone else has +updated the repository more recently, `git push`, like `cvs commit`, will +complain, in which case you must pull any changes before attempting the +push again. + +In the `git push` command above we specify the name of the remote branch +to update (`master`). If we leave that out, `git push` tries to update +any branches in the remote repository that have the same name as a branch +in the local repository. So the last `push` can be done with either of: +------------ +$ git push origin +$ git push foo.com:/pub/project.git/ +------------ -Importing a CVS archive ------------------------ - -Ok, you have an old project, and you want to at least give git a chance -to see how it performs. The first thing you want to do (after you've -gone through the git tutorial, and generally familiarized yourself with -how to commit stuff etc in git) is to create a git'ified version of your -CVS archive. - -Happily, that's very easy indeed. git will do it for you, although git -will need the help of a program called "cvsps": - - http://www.cobite.com/cvsps/ - -which is not actually related to git at all, but which makes CVS usage -look almost sane (ie you almost certainly want to have it even if you -decide to stay with CVS). However, git will want 'at least' version 2.1 -of cvsps (available at the address above), and in fact will currently -refuse to work with anything else. - -Once you've gotten (and installed) cvsps, you may or may not want to get -any more familiar with it, but make sure it is in your path. After that, -the magic command line is - - git cvsimport -v -d -C +as long as the shared repository does not have any branches +other than `master`. -which will do exactly what you'd think it does: it will create a git -archive of the named CVS module. The new archive will be created in the -subdirectory named ; it'll be created if it doesn't exist. -Default is the local directory. +Setting Up a Shared Repository +------------------------------ -It can take some time to actually do the conversion for a large archive -since it involves checking out from CVS every revision of every file, -and the conversion script is reasonably chatty unless you omit the '-v' -option, but on some not very scientific tests it averaged about twenty -revisions per second, so a medium-sized project should not take more -than a couple of minutes. For larger projects or remote repositories, -the process may take longer. +We assume you have already created a git repository for your project, +possibly created from scratch or from a tarball (see the +link:tutorial.html[tutorial]), or imported from an already existing CVS +repository (see the next section). -After the (initial) import is done, the CVS archive's current head -revision will be checked out -- thus, you can start adding your own -changes right away. +Assume your existing repo is at /home/alice/myproject. Create a new "bare" +repository (a repository without a working tree) and fetch your project into +it: -The import is incremental, i.e. if you call it again next month it'll -fetch any CVS updates that have been happening in the meantime. The -cut-off is date-based, so don't change the branches that were imported -from CVS. +------------------------------------------------ +$ mkdir /pub/my-repo.git +$ cd /pub/my-repo.git +$ git --bare init-db --shared +$ git --bare fetch /home/alice/myproject master:master +------------------------------------------------ -You can merge those updates (or, in fact, a different CVS branch) into -your main branch: +Next, give every team member read/write access to this repository. One +easy way to do this is to give all the team members ssh access to the +machine where the repository is hosted. If you don't want to give them a +full shell on the machine, there is a restricted shell which only allows +users to do git pushes and pulls; see gitlink:git-shell[1]. - git resolve HEAD origin "merge with current CVS HEAD" +Put all the committers in the same group, and make the repository +writable by that group: -The HEAD revision from CVS is named "origin", not "HEAD", because git -already uses "HEAD". (If you don't like 'origin', use cvsimport's -'-o' option to change it.) +------------------------------------------------ +$ chgrp -R $group /pub/my-repo.git +------------------------------------------------ +Make sure committers have a umask of at most 027, so that the directories +they create are writable and searchable by other group members. -Emulating CVS behaviour +Importing a CVS archive ----------------------- - -So, by now you are convinced you absolutely want to work with git, but -at the same time you absolutely have to have a central repository. -Step back and think again. Okay, you still need a single central -repository? There are several ways to go about that: - -1. Designate a person responsible to pull all branches. Make the -repository of this person public, and make every team member -pull regularly from it. - -2. Set up a public repository with read/write access for every team -member. Use "git pull/push" as you used "cvs update/commit". Be -sure that your repository is up to date before pushing, just -like you used to do with "cvs commit"; your push will fail if -what you are pushing is not up to date. - -3. Make the repository of every team member public. It is the -responsibility of each single member to pull from every other -team member. - - -CVS annotate ------------- - -So, something has gone wrong, and you don't know whom to blame, and -you're an ex-CVS user and used to do "cvs annotate" to see who caused -the breakage. You're looking for the "git annotate", and it's just -claiming not to find such a script. You're annoyed. - -Yes, that's right. Core git doesn't do "annotate", although it's -technically possible, and there are at least two specialized scripts out -there that can be used to get equivalent information (see the git -mailing list archives for details). - -git has a couple of alternatives, though, that you may find sufficient -or even superior depending on your use. One is called "git-whatchanged" -(for obvious reasons) and the other one is called "pickaxe" ("a tool for -the software archeologist"). - -The "git-whatchanged" script is a truly trivial script that can give you -a good overview of what has changed in a file or a directory (or an -arbitrary list of files or directories). The "pickaxe" support is an -additional layer that can be used to further specify exactly what you're -looking for, if you already know the specific area that changed. - -Let's step back a bit and think about the reason why you would -want to do "cvs annotate a-file.c" to begin with. - -You would use "cvs annotate" on a file when you have trouble -with a function (or even a single "if" statement in a function) -that happens to be defined in the file, which does not do what -you want it to do. And you would want to find out why it was -written that way, because you are about to modify it to suit -your needs, and at the same time you do not want to break its -current callers. For that, you are trying to find out why the -original author did things that way in the original context. - -Many times, it may be enough to see the commit log messages of -commits that touch the file in question, possibly along with the -patches themselves, like this: - - $ git-whatchanged -p a-file.c - -This will show log messages and patches for each commit that -touches a-file. - -This, however, may not be very useful when this file has many -modifications that are not related to the piece of code you are -interested in. You would see many log messages and patches that -do not have anything to do with the piece of code you are -interested in. As an example, assuming that you have this piece -of code that you are interested in in the HEAD version: - - if (frotz) { - nitfol(); - } - -you would use git-rev-list and git-diff-tree like this: - - $ git-rev-list HEAD | - git-diff-tree --stdin -v -p -S'if (frotz) { - nitfol(); - }' - -We have already talked about the "\--stdin" form of git-diff-tree -command that reads the list of commits and compares each commit -with its parents. The git-whatchanged command internally runs -the equivalent of the above command, and can be used like this: - - $ git-whatchanged -p -S'if (frotz) { - nitfol(); - }' - -When the -S option is used, git-diff-tree command outputs -differences between two commits only if one tree has the -specified string in a file and the corresponding file in the -other tree does not. The above example looks for a commit that -has the "if" statement in it in a file, but its parent commit -does not have it in the same shape in the corresponding file (or -the other way around, where the parent has it and the commit -does not), and the differences between them are shown, along -with the commit message (thanks to the -v flag). It does not -show anything for commits that do not touch this "if" statement. - -Also, in the original context, the same statement might have -appeared at first in a different file and later the file was -renamed to "a-file.c". CVS annotate would not help you to go -back across such a rename, but git would still help you in such -a situation. For that, you can give the -C flag to -git-diff-tree, like this: - - $ git-whatchanged -p -C -S'if (frotz) { - nitfol(); - }' - -When the -C flag is used, file renames and copies are followed. -So if the "if" statement in question happens to be in "a-file.c" -in the current HEAD commit, even if the file was originally -called "o-file.c" and then renamed in an earlier commit, or if -the file was created by copying an existing "o-file.c" in an -earlier commit, you will not lose track. If the "if" statement -did not change across such a rename or copy, then the commit that -does rename or copy would not show in the output, and if the -"if" statement was modified while the file was still called -"o-file.c", it would find the commit that changed the statement -when it was in "o-file.c". - -NOTE: The current version of "git-diff-tree -C" is not eager - enough to find copies, and it will miss the fact that a-file.c - was created by copying o-file.c unless o-file.c was somehow - changed in the same commit. - -You can use the --pickaxe-all flag in addition to the -S flag. -This causes the differences from all the files contained in -those two commits, not just the differences between the files -that contain this changed "if" statement: - - $ git-whatchanged -p -C -S'if (frotz) { - nitfol(); - }' --pickaxe-all - -NOTE: This option is called "--pickaxe-all" because -S - option is internally called "pickaxe", a tool for software - archaeologists. +First, install version 2.1 or higher of cvsps from +link:http://www.cobite.com/cvsps/[http://www.cobite.com/cvsps/] and make +sure it is in your path. Then cd to a checked out CVS working directory +of the project you are interested in and run gitlink:git-cvsimport[1]: + +------------------------------------------- +$ git cvsimport -C +------------------------------------------- + +This puts a git archive of the named CVS module in the directory +, which will be created if necessary. + +The import checks out from CVS every revision of every file. Reportedly +cvsimport can average some twenty revisions per second, so for a +medium-sized project this should not take more than a couple of minutes. +Larger projects or remote repositories may take longer. + +The main trunk is stored in the git branch named `origin`, and additional +CVS branches are stored in git branches with the same names. The most +recent version of the main trunk is also left checked out on the `master` +branch, so you can start adding your own changes right away. + +The import is incremental, so if you call it again next month it will +fetch any CVS updates that have been made in the meantime. For this to +work, you must not modify the imported branches; instead, create new +branches for your own changes, and merge in the imported branches as +necessary. + +Advanced Shared Repository Management +------------------------------------- + +Git allows you to specify scripts called "hooks" to be run at certain +points. You can use these, for example, to send all commits to the shared +repository to a mailing list. See link:hooks.html[Hooks used by git]. + +You can enforce finer grained permissions using update hooks. See +link:howto/update-hook-example.txt[Controlling access to branches using +update hooks]. + +Providing CVS Access to a git Repository +---------------------------------------- + +It is also possible to provide true CVS access to a git repository, so +that developers can still use CVS; see gitlink:git-cvsserver[1] for +details. + +Alternative Development Models +------------------------------ + +CVS users are accustomed to giving a group of developers commit access to +a common repository. As we've seen, this is also possible with git. +However, the distributed nature of git allows other development models, +and you may want to first consider whether one of them might be a better +fit for your project. + +For example, you can choose a single person to maintain the project's +primary public repository. Other developers then clone this repository +and each work in their own clone. When they have a series of changes that +they're happy with, they ask the maintainer to pull from the branch +containing the changes. The maintainer reviews their changes and pulls +them into the primary repository, which other developers pull from as +necessary to stay coordinated. The Linux kernel and other projects use +variants of this model. + +With a small group, developers may just pull changes from each other's +repositories without the need for a central maintainer.