Merge branch 'jc/diff' into next
[gitweb.git] / Documentation / cvs-migration.txt
index 4e2c4520344efecb4f4fa6ea6bbd10373e9a4573..fa94efde8dfd75a4eee7ddd62f110d5da39ef360 100644 (file)
-Git for CVS users
+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 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.
+So you're a CVS user. That's ok, it's a treatable condition.  The job of
+this document is to put you on the road to recovery, by helping you
+convert an existing cvs repository to git, and by showing you how to use a
+git repository in a cvs-like fashion.
 
+Some basic familiarity with git is required.  This
+link:tutorial.html[tutorial introduction to git] should be sufficient.
 
-Importing a CVS archive
------------------------
+First, note some ways that git differs from CVS:
 
-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.
+  * Commits are atomic and project-wide, not per-file as in CVS.
 
-Happily, that's very easy indeed. Git will do it for you, although git
-will need the help of a program called "cvsps":
+  * Offline work is supported: you can make multiple commits locally,
+    then submit them when you're ready.
 
-       http://www.cobite.com/cvsps/
+  * Branching is fast and easy.
 
-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.
+  * 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; see below
+    for details.
 
-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
+Importing a CVS archive
+-----------------------
 
-       git cvsimport <cvsroot> <module>
+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.  The magic command line is then
+
+-------------------------------------------
+$ git cvsimport -v -d <cvsroot> -C <destination> <module>
+-------------------------------------------
+
+This puts a git archive of the named CVS module in the directory
+<destination>, which will be created if necessary.  The -v option makes
+the conversion script very chatty.
+
+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.
+
+Development Models
+------------------
+
+CVS users are accustomed to giving a group of developers commit access to
+a common repository.  In the next section we'll explain how to do this
+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.
+
+Emulating the CVS Development Model
+-----------------------------------
+
+Start with an ordinary git working directory containing the project, and
+remove the checked-out files, keeping just the bare .git directory:
+
+------------------------------------------------
+$ mv project/.git /pub/repo.git
+$ rm -r project/
+------------------------------------------------
+
+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].
+
+Put all the committers should in the same group, and make the repository
+writable by that group:
+
+------------------------------------------------
+$ chgrp -R $group repo.git
+$ find repo.git -mindepth 1 -type d |xargs chmod ug+rwx,g+s
+$ GIT_DIR=repo.git git repo-config core.sharedrepository true
+------------------------------------------------
+
+Make sure committers have a umask of at most 027, so that the directories
+they create are writable and searchable by other group members.
+
+Suppose this repository is now set up in /pub/repo.git on the host
+foo.com.  Then as an individual commiter you can clone the shared
+repository:
+
+------------------------------------------------
+$ 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.
+
+[NOTE]
+================================
+The first `git clone` places the following in the
+`my-project/.git/remotes/origin` file, and that's why the previous step
+and the next step both work.
+------------
+URL: foo.com:/pub/project.git/ my-project
+Pull: master:origin
+------------
+================================
 
-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 a
-subdirectory named <module>.
+You can update the shared repository with your changes using:
 
-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 can be reasonably chatty, but on some not very
-scientific tests it averaged about eight 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.
+------------------------------------------------
+$ git push origin master
+------------------------------------------------
 
+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.
 
-Emulating CVS behaviour
------------------------
+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 repo.shared.xz:/pub/scm/project.git/
+------------
+
+as long as the shared repository does not have any branches
+other than `master`.
 
+[NOTE]
+============
+Because of this behaviour, if the shared repository and the developer's
+repository both have branches named `origin`, then a push like the above
+attempts to update the `origin` branch in the shared repository from the
+developer's `origin` branch.  The results may be unexpected, so it's
+usually best to remove any branch named `origin` from the shared
+repository.
+============
 
-FIXME! Talk about setting up several repositories, and pulling and
-pushing between them. Talk about merging, and branches. Some of this
-needs to be in the tutorial too.
+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.txt[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].
 
 CVS annotate
 ------------
@@ -100,10 +191,10 @@ 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
+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 software archaeologist"). 
 
 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
@@ -137,7 +228,7 @@ 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
-code that you are interested in in the HEAD version:
+of code that you are interested in in the HEAD version:
 
        if (frotz) {
                nitfol();
@@ -150,9 +241,10 @@ you would use git-rev-list and git-diff-tree like this:
                nitfol();
        }'
 
-We have already talked about the "--stdin" form of git-diff-tree
+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
+with its parents (otherwise you should go back and read the tutorial).
+The git-whatchanged command internally runs
 the equivalent of the above command, and can be used like this:
 
        $ git-whatchanged -p -S'if (frotz) {
@@ -173,7 +265,7 @@ 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
+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:
 
@@ -187,16 +279,16 @@ 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 rename or copy, then the commit that
+did not change across such 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".
 
-[ BTW, the current versions of "git-diff-tree -C" is not eager
+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.]
+  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
@@ -207,6 +299,6 @@ that contain this changed "if" statement:
                nitfol();
        }' --pickaxe-all
 
-[ Side note.  This option is called "--pickaxe-all" because -S
+NOTE: This option is called "--pickaxe-all" because -S
   option is internally called "pickaxe", a tool for software
-  archaeologists.]
+  archaeologists.