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

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

Ответ 1

К счастью для тех из нас, кто все еще вынужден использовать 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 -like (см. man git-cvsimport для получения дополнительной информации о том, как это настроено).

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

Как только этот процесс будет завершен, у вас будет ветвь master, которая должна отражать CVS HEAD (за исключением того, что 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

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

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

Создание локальных изменений

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

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

Команда git cvsexportcommit позволяет экспортировать одно сообщение на сервер CVS. Вы можете указать один идентификатор фиксации (или все, что описывает конкретную фиксацию, как определено в man git-rev-parse). Затем генерируется diff, применяемый к проверке CVS, а затем (необязательно) переданный CVS с использованием фактического клиента cvs. Вы можете экспортировать каждый микрообъявление в свои ветки тем, но обычно мне нравится создавать компиляцию слияния на обновленном master и экспортировать это единственное слияние в CVS. Когда вы экспортируете фиксацию слияния, вы должны сообщить git, который обязывает родителя использовать для генерации diff. Кроме того, это не сработает, если ваше слияние было быстрым (см. Раздел "HOW MERGE WORKS" 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 и имеет все остальные репозитории, созданные как клон. Это отлично работает, и клонированный репозиторий может выполнять команды cvsexport как описано выше. Однако есть одно предостережение. Из-за того, как транзакции 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 нецелесообразно.

Ответ 2

Нельзя доверять 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

нижняя строка: проверить свое дерево после импорта

Ответ 3

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