Git
Mercurial
CVS
Version Control
Revision History

How to export revision history from mercurial or git to cvs?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Exporting revision history from Git or Mercurial to CVS is not a clean one-command migration because CVS cannot represent the full history model of modern distributed version control systems. The honest answer is that you can approximate a usable history by replaying commits, but you should not expect a lossless conversion of merges, branch structure, and metadata semantics.

Understand the model mismatch first

Git and Mercurial track changesets in a directed graph. CVS stores per-file revisions with a much older centralized model. That creates immediate gaps:

  • merge commits do not map cleanly to CVS history
  • distributed branch topology is far richer than CVS branches
  • changeset identity is lost
  • author and timestamp preservation is possible only approximately

So the real question is not "how do I perfectly export history," but "what subset of history do I need to preserve well enough for the legacy CVS target?"

A perfect history transfer is usually impossible

If the source repository has heavy branching and merging, a faithful CVS representation is effectively impossible. CVS simply does not have the same data model.

That means the practical options are usually:

  • export only the latest tree state
  • replay a linearized mainline history
  • preserve selected tags or milestones manually

This is why many migrations into CVS are business compromises rather than technical mirrors.

Linearize the history you intend to replay

The most realistic approach is to choose one branch, usually the main branch, and replay its commits in chronological order into a CVS working copy.

In Git, a simplified export list might come from a revision log:

bash
git log --reverse --pretty=format:'%H%x09%an%x09%ad%x09%s' main

In Mercurial, the equivalent idea is similar:

bash
hg log -r "reverse(ancestor(., 0):.)" --template '{node}\t{author}\t{date|isodate}\t{desc|firstline}\n'

These commands do not solve the migration on their own. They give you the ordered history you would need to replay.

Replay snapshots or patches into CVS

A practical migration strategy is:

  1. create a CVS module with the initial imported tree
  2. walk the chosen Git or Mercurial commits in order
  3. check out the source tree at each commit
  4. copy the resulting files into the CVS working directory
  5. commit into CVS with the original message and, where possible, preserved author and date metadata

For a simple Git snapshot export, the source-tree extraction step can look like this:

bash
git archive --format=tar COMMIT_SHA | tar -xf - -C /tmp/exported-tree

You then synchronize that tree into a CVS working copy and commit it. The same idea works from Mercurial with archive or checkout commands.

Expect metadata loss and manual cleanup

Even with careful replay, several things usually degrade:

  • merge commits become ordinary replayed content states
  • rename history may be flattened into delete plus add behavior
  • CVS tags and branches need separate handling
  • binary file handling may need extra attention

So after the automated replay portion, plan for manual cleanup and manual tagging of important release points.

Consider whether you really need CVS history at all

Before investing in a replay migration, challenge the requirement. In many organizations, the better answer is:

  • keep the old Git or Mercurial repository as the authoritative history archive
  • import only the current tree into CVS
  • document the mapping between CVS start point and legacy source history

That gives users a working CVS module without pretending the old history model survived intact.

Use the migration only as a compatibility bridge

Moving from Git or Mercurial into CVS is almost always a legacy-compatibility move. Treat it as such. The goal is usually to satisfy an old toolchain, vendor system, or policy constraint, not to improve version control quality.

That framing matters because it tells you how much fidelity is worth paying for. Often, "good enough mainline replay plus archived original repo" is the right answer.

Common Pitfalls

  • Expecting Git or Mercurial branch and merge history to survive intact in CVS.
  • Confusing git cvsimport with export to CVS; it imports CVS into Git, not the other way around.
  • Replaying every branch when only one maintained line actually matters.
  • Ignoring rename, binary, and tag behavior differences until late in the migration.
  • Throwing away the original Git or Mercurial repository after creating an approximate CVS replay.

Summary

  • There is no fully faithful export of modern DVCS history into CVS.
  • The practical solution is usually to linearize and replay a selected history, not to preserve everything.
  • Snapshot or patch replay into a CVS working copy is the standard approximation strategy.
  • Keep the original Git or Mercurial repository as the authoritative archive.
  • Treat the CVS result as a compatibility target, not as a perfect historical mirror.

Course illustration
Course illustration

All Rights Reserved.