Как экспортировать историю ревизий из mercurial или git в cvs?

100

Я собираюсь работать с другими людьми над кодом из проекта, который использует cvs. Мы хотим использовать распределенный vcs для выполнения нашей работы, и когда мы закончим или, может быть, время от времени, мы хотим зафиксировать наш код и всю нашу историю изменений в cvs. У нас нет доступа на запись в репозиторий cvs проекта, поэтому мы не можем коммитить очень часто. Какой инструмент мы можем использовать для экспорта нашей истории изменений в cvs? В настоящее время мы думали об использовании git или mercurial, но мы могли бы использовать другой распределенный виртуальный компьютер, если это упростит экспорт.

Тацухиросату
источник
Когда вы говорите «распределенная CVS», я думаю, вы имеете в виду «распределенную VCS» или «DVCS», что означает «распределенная система контроля версий».
Патрик МакЭлхейни
Я имею в виду распределенную систему контроля версий.
tatsuhirosatou

Ответы:

237

К счастью для тех из нас, кто все еще вынужден использовать CVS, git предоставляет довольно хорошие инструменты, чтобы делать именно то, что вы хотите. Мои предложения (и что мы делаем здесь, в $ work):

Создание исходного клона

Используйте git cvsimportдля клонирования истории ревизий CVS в репозиторий git. Я использую следующий вызов:

% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \
  -A /path/to/authors/file cvs_module_to_checkout

Этот -Aпараметр не является обязательным, но он помогает сделать вашу историю изменений, импортированную из CVS, более похожей на git (см. man git-cvsimportДополнительную информацию о том, как это настроить).

В зависимости от размера и истории репозитория CVS, этот первый импорт займет ОЧЕНЬ много времени. Вы можете добавить -v к приведенной выше команде, если хотите быть уверенными в том, что что-то действительно происходит.

Когда этот процесс будет завершен, у вас будет masterветка, которая должна отражать HEAD CVS (за исключением того, что git cvsimportпо умолчанию игнорирует последние 10 минут коммитов, чтобы не поймать наполовину завершенный коммит). Затем вы можете использовать git logи друзей, чтобы изучить всю историю репозитория, как если бы он использовал git с самого начала.

Настройки конфигурации

Есть несколько настроек конфигурации, которые упростят инкрементный импорт из CVS (а также экспорт) в будущем. Они не задокументированы на git cvsimportстранице руководства, поэтому я предполагаю, что они могут быть изменены без предварительного уведомления, но FWIW:

% git config cvsimport.module cvs_module_to_checkout
% git config cvsimport.r cvs
% git config cvsimport.d $CVSROOT

Все эти параметры можно указать в командной строке, поэтому вы можете спокойно пропустить этот шаг.

Инкрементальный импорт

Последующий git cvsimportвызов должен быть намного быстрее, чем первый вызов. Однако он выполняет операцию для cvs rlogкаждого каталога (даже для тех, в которых есть только файлы Attic), поэтому это может занять несколько минут. Если вы указали предложенные выше конфигурации, все, что вам нужно сделать, это выполнить:

% git cvsimport

Если вы не настроили свои конфигурации, чтобы указать значения по умолчанию, вам нужно указать их в командной строке:

% git cvsimport -r cvs -d $CVSROOT cvs_module_to_checkout

В любом случае, нужно помнить о двух вещах:

  1. Убедитесь, что вы находитесь в корневом каталоге вашего репозитория git. Если вы находитесь в другом месте, он попытается сделать что-то новое, cvsimportчто снова займет вечность.
  2. Убедитесь, что вы находитесь в своей masterветке, чтобы изменения можно было объединить (или переназначить) в локальные / тематические ветки.

Внесение локальных изменений

На практике я рекомендую всегда вносить изменения в ветки и выполнять слияние только masterтогда, когда вы будете готовы экспортировать эти изменения обратно в репозиторий CVS. Вы можете использовать любой рабочий процесс, который вам нравится, в своих ветках (слияние, ребазирование, сжатие и т. Д.), Но, конечно, применяются стандартные правила переназначения: не переназначайте, если кто-то еще основывал свои изменения на вашей ветке.

Экспорт изменений в CVS

Команда git cvsexportcommitпозволяет вам экспортировать одиночный коммит на сервер CVS. Вы можете указать один идентификатор фиксации (или что-нибудь, что описывает конкретную фиксацию, как определено в man git-rev-parse). Затем создается diff, применяется к проверке CVS и затем (необязательно) передается в CVS с использованием реального cvsклиента. Вы можете экспортировать каждую микрокоммит в свои тематические ветки, но обычно мне нравится создавать коммит слияния в актуальном состоянии masterи экспортировать этот единственный коммит слияния в CVS. Когда вы экспортируете коммит слияния, вы должны указать git, какой родительский коммит использовать для генерации diff. Кроме того, это не сработает, если ваше слияние было перемоткой вперед (см. Раздел «КАК РАБОТАЕТ СЛИЯНИЕ» man git-mergeдля описания слияния с перемоткой вперед), поэтому вы должны использовать--no-ffвариант при выполнении слияния. Вот пример:

# 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

Вы можете увидеть, что означает каждый из этих параметров, на странице руководства для git-cvsexportcommit . У вас есть возможность установить этот -wпараметр в конфигурации git:

% git config cvsexportcommit.cvsdir /path/to/cvs/checkout

Если патч не работает по какой-либо причине, мой опыт показывает, что вам (к сожалению), вероятно, будет лучше скопировать измененные файлы вручную и зафиксировать с помощью клиента cvs. Однако этого не должно происходить, если вы убедитесь, что у вас установлена masterпоследняя версия CVS, прежде чем объединять тематическую ветку в.

Если фиксация не удалась по какой-либо причине (проблемы с сетью / разрешениями и т. Д.), Вы можете взять команду, напечатанную на вашем терминале в конце сообщения об ошибке, и выполнить ее в своем рабочем каталоге CVS. Обычно это выглядит примерно так:

% cvs commit -F .msg file1 file2 file3 etc

В следующий раз, когда вы сделаете git cvsimport(ожидая не менее 10 минут), вы увидите, что патч экспортированного коммита повторно импортирован в ваш локальный репозиторий. У них будут разные идентификаторы фиксации, так как фиксация CVS будет иметь другую метку времени и, возможно, другое имя коммиттера (в зависимости от того, настроили ли вы файл авторов в исходном cvsimportвыше).

Клонирование вашего клона CVS

Если у вас есть несколько человек, которые должны сделать это cvsimport, было бы более эффективно иметь один репозиторий git, который выполняет cvsimport, а все остальные репозитории созданы как клоны. Это работает отлично, и клонированный репозиторий может выполнять cvsexportcommit, как описано выше. Однако есть один нюанс. Из-за того, что коммиты CVS возвращаются с разными идентификаторами коммитов (как описано выше), вы не хотите, чтобы ваша клонированная ветка отслеживала центральный репозиторий git. По умолчанию git cloneваш репозиторий настраивается так, но это легко исправить:

% git clone [CENTRAL_REPO_HERE]
% cd [NEW_GIT_REPO_DIR_HERE]
% git config --unset branch.master.remote
% git config --unset branch.master.merge

После того, как вы удалили эти конфигурации, вам нужно будет явно указать, где и что извлекать, когда вы хотите получить новые коммиты из центрального репозитория:

% git pull origin master

В целом, я обнаружил, что этот рабочий процесс вполне управляем, и «следующая лучшая вещь» при полном переходе на git непрактична.

Брайан Филлипс
источник
3
Спасибо. Это очень помогло мне, особенно совет об использовании не-fastforward слияния для объединения изменений для CVS в один коммит.
skiphoppy
8
Для записи вариант -A, который вы предлагаете использовать для git-cvsimport, упоминается на странице руководства как «не рекомендуется ... если вы собираетесь позже снова экспортировать изменения обратно в CVS с помощью git-cvsexportcommit (1)». В моем случае мне действительно нравится, как авторы выступают как есть.
skiphoppy
2
Спасибо за советы. Одна полезная вещь, которую я сделал, - это добавить "cvs =! Git cvsimport -k -a" под [псевдонимом] моего .gitconfig. Это делает так, что "git cvs" будет выполнять DTRT (с вершины дерева).
bstpierre 06
1
Если вам не хватает git cvsimportDebian, попробуйтеapt-get install git-cvs
Тино
5
В Mac OSX mavricks полностью отсутствуют cvs, и кажется, что git cvsimport зависит от cvs Initialized empty Git repository in /Users/gus/projects/foo/foobar/.git/ Can't exec "cvsps": No such file or directory at /Applications/Xcode.app/Contents/Developer/usr/libexec/git-core/git-cvsimport line 777. Could not start cvsps: No such file or directory git cvsimport: fatal: cvsps reported errorТак что, к сожалению, это не поможет вам обойтись без CVS :(
Гас
22

Вы не должны слепо доверять cvsimport и проверять, совпадает ли импортированное дерево с тем, что находится в репозитории CVS. Я сделал это, поделившись новым проектом с помощью подключаемого модуля eclipse CVS, и обнаружил несоответствия ..

Две фиксации, которые были выполнены менее чем за минуту с одним и тем же сообщением фиксации (для восстановления ошибочно удаленного файла), были сгруппированы в одну большую фиксацию, что привело к отсутствию файла в дереве ..

Мне удалось решить эту проблему, изменив параметр «fuzz» до менее чем минуты.

пример:

% git cvsimport -d $CVSROOT -C dir_to_create -r cvs -k \
  -A /path/to/authors/file cvs_module_to_checkout -z 15

Итог: проверьте свое дерево после импорта

shil88
источник
3

В дополнение к ответу Брайана Филлипса: есть также git-cvsserver, который работает как сервер CVS, но фактически обращается к репозиторию git ... но имеет некоторые ограничения.

Якуб Наребски
источник