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