I'm going to be working with other people on code from a project that uses cvs. We want to use a distributed vcs to make our work and when we finish or maybe every once in a while we want to commit our code and all of our revision history to cvs. We don't have write access to the project's cvs repo so we can't commit very frequently. What tool can we use to export our revision history to cvs? Currently we were thinking of using git or mercurial but we could use another distributed vcs if it could make the export easier.
Are git submodules the only safe way to have working copies within working copies?
Howto extract a git subdirectory and make a submodule out of it?
How to back up private branches in git
My suggestions (and what we do here at $work):.
git alternatives to “svn info” that can be included in a build for traceability?
Creating the Initial CloneUse
git cvsimportto clone the CVS revision history into a git repository.
Can i know the revision number of a commit?
I use the following invocation:.
How to undo last commit(s) in Git?
% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout
-Aoption is optional but it helps to make your revision history that's imported from CVS look more git-like (see
man git-cvsimportfor more info on how this is set up)..
How do I tell git to always select my local version for conflicted merges on a specific file?
Depending on the size and history of the CVS repository, this first import will take a VERY long time.
git remove oldest revisions of a file
You can add a -v to the above command if you want the peace of mind that something is in fact happening.. Once this process is completed, you will have a
masterbranch that should reflect CVS's HEAD (with the exception that
git cvsimportby default ignores the last 10 minutes worth of commits to avoid catching a commit that is half-finished).
You can then use
git logand friends to examine the entire history of the repository just as if it had been using git from the beginning..
Configuration TweaksThere are a few configuration tweaks that will make incremental imports from CVS (as well as exports) easier in the future.
These are not documented on the
git cvsimportman page so I suppose they could change without notice but, FWIW:.
All of these options can be specified on the command line so you could safely skip this step..
% git config cvsimport.module cvs_module_to_checkout % git config cvsimport.r cvs % git config cvsimport.d $CVSROOT
git cvsimportshould be much faster than the first invocation.
It does, however, do an
cvs rlogon every directory (even those that have only files in
Attic) so it can still take a few minutes.
If you've specified the suggested configs above, all you need to do is execute:.
If you haven't set up your configs to specify the defaults, you'll need to specify them on the command line:.
% git cvsimport
Either way, two things to keep in mind:.
% git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout
- Make sure you're in the root directory of your git repository.
If you're anyplace else, it will try to do a fresh
cvsimportthat will again take forever.
- Make sure you're on your
masterbranch so that the changes can be merged (or rebased) into your local/topic branches.
Making Local ChangesIn practice, I recommend always making changes on branches and only merging to
masterwhen you're ready to export those changes back to the CVS repository.
You can use whatever workflow you like on your branches (merging, rebasing, squashing, etc) but of course the standard rebasing rules apply: don't rebase if anyone else has been basing their changes on your branch..
Exporting Changes to CVSThe
git cvsexportcommitcommand allows you to export a single commit out to the CVS server.
You can specify a single commit ID (or anything that describes a specific commit as defined in
A diff is then generated, applied to a CVS checkout and then (optionally) committed to CVS using the actual
You could export each micro commit on your topic branches but generally I like to create a merge commit on an up-to-date
masterand export that single merge commit to CVS.
When you export a merge commit, you have to tell git which commit parent to use to generate the diff.
Also, this won't work if your merge was a fast-forward (see the "HOW MERGE WORKS" section of
man git-mergefor a description of a fast-forward merge) so you have to use the
--no-ffoption when performing the merge.
Here's an example:.
You can see what each of those options mean on the man page for git-cvsexportcommit.
# on master % git merge --no-ff --log -m "Optional commit message here" topic/branch/name % git cvsexportcommit -w /path/to/cvs/checkout -u -p -c ORIG_HEAD HEAD
You do have the option of setting the
-woption in your git config:.
If the patch fails for whatever reason, my experience is that you'll (unfortunately) probably be better off copying the changed files over manually and committing using the cvs client.
% git config cvsexportcommit.cvsdir /path/to/cvs/checkout
This shouldn't happen, however, if you make sure
masteris up-to-date with CVS before merging your topic branch in.. If the commit fails for whatever reason (network/permissions issues, etc), you can take the command printed to your terminal at the end of the error output and execute it in your CVS working directory.
It usually looks something like this:.
The next time you do a
% cvs commit -F .msg file1 file2 file3 etc
git cvsimport(waiting at least 10 minutes) you should see the patch of your exported commit re-imported into your local repository.
They will have different commit IDs since the CVS commit will have a different timestamp and possibly a different committer name (depending on whether you set up an authors file in your initial
Cloning your CVS cloneIf you have more than one person needing to do the
cvsimport, it would be more efficient to have a single git repository that performs the cvsimport and have all the other repositories created as a clone.
This works perfectly and the cloned repository can perform cvsexportcommits just as described above.
There is one caveat, however.
Due to the way CVS commits come back through with different commit IDs (as described above), you don't want your cloned branch to track the central git repository.
By default, this is how
git cloneconfigures your repository but this is easily remedied:.
After you've removed these configs, you will have to explicitly say where and what to pull from when you want to pull in new commits from the central repository:.
% git clone [CENTRAL_REPO_HERE] % cd [NEW_GIT_REPO_DIR_HERE] % git config --unset branch.master.remote % git config --unset branch.master.merge
Overall, I've found this work-flow to be quite manageable and the "next best thing" when migrating completely to git isn't practical..
% git pull origin master
I've done this by sharing the new project using eclipse CVS' plug-in and found that there were inconsistencies..
. Two commits that were done in less than a minute with the same commit message (in order to revert a wrongfully deleted file) were grouped into one big commit, which resulted in a missing file from the tree... I was able to solve this problem by modifying the 'fuzz' parameter to less than a minute.. example:.
bottom line: check your tree after importing.
% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \ -A /path/to/authors/file cvs_module_to_checkout -z 15
but it has some limitations..