Другие ответы на данный момент предполагают перебазирование.Эта может работать, в некоторых случаях, в зависимости от графика фиксации в хранилище, преобразованном в Git.Новый фанатский ребаз с --rebase-merges
определенно может это сделать.Но это немного неуклюжий способ сделать это.Идеальный способ сделать это - конвертировать коммиты , начиная с первого, который вы хотите сохранить. То есть экспорт вашего Mercurial экспортируется в Git, как первый коммит Git, ревизияВы хотите притвориться, это корень.Попросите экспортера Mercurial экспортировать потомков этого коммита, по одному в импортер, точно так же, как экспортер всегда собирался выполнять эту работу (каким бы образом это ни было).
Будь икак вы сможете сделать это, зависит от того, какие инструменты вы используете для конвертации.(На самом деле я не делал ни одного из этих преобразований, но большинство людей, похоже, используют hg-fast-export
и git fast-import
. Я не особо рассматривал внутренние детали hg-fast-export
, но нет очевидной причины, по которой не смог сделать это.)
По сути (внутренне), хранилища Mercurial фиксируются как наборы изменений.Это не случай для Git: Git хранит снимки вместо этого.Однако Mercurial извлекает (т.е. извлекает) снимки, суммируя вместе наборы изменений, как требуется, поэтому, если ваш инструмент работает, выполняя hg checkout
(или его внутренний эквивалент), здесь нет проблемпервое место: вы просто избегаете проверять ревизии перед первым желаемым снимком и импортируете их в Git, и итоговая история Git начинается в нужной точке.
Если инструменты, которые вы сделалиэто неудобно, однако, обратите внимание, что после преобразования всей истории репозитория, включая все ветви и слияния, в снимки Git, ваш репозиторий Git делает это относительно простым, как второй проход.Например, ваша история Git может выглядеть следующим образом:
o-..-o o--o <-- br1
/ \ /
...--o--o--....--o--*--o--o--o--o <-- br2
\ / \
o--...--o o <-- master
, где commit *
- это первый коммит, который вы хотели увидеть в своем хранилище Git.(Обратите внимание, что если есть несколько историй, возвращающихся до *
, у вас есть другая проблема, и вы не можете выполнить этот вид преобразования в первую очередь без дополнительной модификации истории. Но пока *
находится в некотором роде Choke Point , как и на этой диаграмме, здесь легко обрезать график.)
Чтобы удалить все до *
, просто используйте git replace
, чтобы сделать альтернативный коммит, который оченьочень , как commit *
, но не имеет родителя:
git replace --graft <hash-of-*>
Теперь у вас есть замена, которую будет использовать большая часть Git вместо *
, у которой нет родительского коммита.Затем запустите git filter-branch
для всех веток и тегов с фильтром no-op:
git filter-branch --tag-name-filter cat -- --all
Это скопирует каждый достижимый коммит, включая замену *
, но исключая *
и его собственную историю, до новых коммитов, затем обновите ваши ветки и имена тегов.Удалите пространство имен refs/originals/
(подробности см. в документации git filter-branch
), принудительно заберите первоначальные объекты, если хотите (дополнительные коммиты со временем исчезнут сами по себе), и выготово.