Клон hg-git из Github выдает "abort: хранилище не связано"
У меня есть проект, основной репозиторий которого (Mercurial) находится на SourceForge, но есть клоны на Bitbucket (Mercurial) и Github (Git).
Теперь я использую hg-git, чтобы перенести репозиторий Mercurial на Github, и из того, что я понимаю в этой процедуре, некоторые метаданные в процессе хранятся в репозитории Mercurial.
Теперь, при повторном клонировании репозитория Bitbucket и клонировании репозитория Github, а также, если я выпущу hg pull ../github-repo
Я получил:
pulling from ../github-repo
searching for changes
abort: repository is unrelated
Почему это так и как я могу убедить Mercurial в том, что они действительно связаны? Или я должен полагаться на исходный репозиторий, из которого я изначально отправил Github? У меня все еще есть это, но предположим, что я потерял его, какие у меня будут варианты, кроме ручной трансплантации?
Примечание: репозиторий Github был изменен (новый набор изменений) из-за запроса на получение. Но репозитории SourceForge и Bitbucket по-прежнему распознают друг друга как связанные. Миссия теперь состоит в том, чтобы вытащить набор изменений из репозитория Github Git в локальный и вернуть их обратно в SourceForge и Bitbucket соответственно.
2 ответа
Связанный или не связанный бит в основном происходит от того, имеют ли два репозитория общий корень, то есть начальный набор изменений.
Чтобы заставить тянуть, вы могли бы сделать что-то злое с трансплантатом или удлинителями трансплантата, но это может иметь волновые эффекты, и вы, похоже, против такого решения - я бы тоже!
Чтобы понять, почему у вас проблемы, вам нужно немного понять, как работает Hg-Git.
Как работает Hg-Git
ТЛ; др
Настоящая проблема заключается в том, что Hg-Git создает динамически новый репо. Таким образом, два хранилища не связаны по той же причине, что продукт hg convert some-existing-hg-repo
не связано с исходным хранилищем. До сих пор вы этого не замечали, потому что Hg-Git делает это и в другом направлении - когда вы запускаете из репозитория Mercurial, он создает необходимый репозиторий Git. Когда вы впервые начали клонировать в GitHub, вы создали на своих серверах пустой Git-репозиторий, который по своим намерениям и целям связан с каждым репозиторием. Таким образом, ваш толчок в новом Git-репо, созданном Hg-Git, связан, и все работает, никаких проблем. После этого вы выходили из того же репо, поэтому опять никаких проблем - Hg-Git отслеживает отношения между локальными репозиториями Git и Hg и, таким образом, ваши отношения сохраняются. Но когда вы начинаете заново, вы создаете новое Git и / или Hg репо (в зависимости от того, в каком направлении вы движетесь), и корреспонденция нарушается.
Чуть менее упрощенно
Hg-Git создает скрытый Git-репозиторий и устанавливает соответствие между коммитами Git и Hg-репозиториями. Hg-Git - это двусторонний мост, то есть он способен принимать коммиты Git и генерировать коммиты Hg, и наоборот. Hg-Git достигает своего двуязычия, используя библиотеку git, написанную на Python ( dulwich), и в качестве расширения ссылается на Mercurial. Это означает, что Hg-Git читает и пишет Git-репозитории без необходимости git
двоичная / установленная эталонная реализация Git. Однако Hg-Git является расширением Mercurial и поэтому зависит от системы Mercurial для завершения транзакции Mercurial, а также от пользовательского интерфейса. Вот почему предпринимаются попытки создать обратный интерфейс (Git-Hg и т. П.), Чтобы пользователи Git могли использовать Git для взаимодействия с Mercurial.
Теперь, будет ли создан репозиторий Git или Hg, зависит от того, как гибридный репозиторий был создан в первую очередь. Поскольку вы пришли с канонической стороны Mercurial, мы начнем там.
Когда вы создаете хранилище в Github или Bitbucket, оно изначально пустое и не содержит коммитов и, таким образом, связано с каждым хранилищем - это является частью мотивации по умолчанию отсутствия первоначальной фиксации при создании хранилища. (Это верно как для Git, так и для Mercurial.) Связанность репозитория основана на корневом узле. Таким образом, любой репозиторий может быть перенесен в этот новый репозиторий. Когда ты бежишь hg push ssh+git://git@github.com/user/some-git-repo
впервые Hg-Git создает новый скрытый Git-репозиторий в вашей локальной папке, а затем использует протоколы Git для связи и передачи изменений на удаленный компьютер. С этого момента у вас не должно возникать проблем при обмене данными между двумя репозиториями - начиная с первоначального преобразования корневого узла и отношений родитель-потомок, можно добиться взаимно-однозначного сопоставления между наборами изменений двух репозиториев. (Это не совсем на 100% верно, особенно если вы используете более продвинутые идиоматические функции Git или Mercurial, но пока этого будет достаточно.) Hg-Git отслеживает чуть больше информации, чем эта, я уверен Если только по какой-то другой причине, кроме как ускорить процесс с последовательными толчками. Итак, когда вы начинаете с клона Mercurial, ваш "прото-корень" - это корень Mercurial, а хранилище Git создается и поддерживается по мере необходимости.
Теперь, если вы не начинаете с локального клона Mercurial, а скорее с удаленного клона Git, то вы фактически создаете клон Mercurial из Git - "прото-корень" - это корень Git. Точнее, когда вы бежите hg clone ssh+git://git@github.com/user/some-git-repo
Mercurial запускается, проверяет, может ли он взаимодействовать с удаленным (что он может с помощью Hg-Git), затем создает каталог и вызывает необходимое расширение (я), то есть Hg-Git. Hg-Git затем создает скрытый .git
папка в вашем .hg
Папка, выполняет клон git, а затем конвертирует репозиторий Git в Mercurial; когда этот клон завершен, он вызывает hg update
, который работает непосредственно на репозитории Mercurial, не зная о репозитории Git.
Это, я подозреваю, то, что пошло не так в вашем случае. Когда вы сделали новый клон из GitHub, вы фактически создали новый репозиторий Mercurial, который, конечно, не связан с вашим исходным репозиторием - во многом так же, как продукт hg convert
не относится к оригиналу, даже если мутированные коммиты не включают начальный. (Это похоже на то, как когда вы переводите что-то на другой язык и обратно, вы не всегда получаете исходную форму обратно.) Я подозреваю, что Hg-Git выполняет свои преобразования независимо от времени и детерминированно. (почти наверняка последний, но он может добавить дополнительные метаданные о самом преобразовании, что будет означать не первое). Если это так, тогда вы сможете начать с канонического клона Hg и воссоздать соединение с репозиторием Git. (Да, несколько проблематично, что направленность первоначального преобразования имеет значение, но плюсы и минусы проектных решений, которые привели к этому, лучше обсудить с самими разработчиками.)
Вернуться к структуре гибридного хранилища Hg-Git. Здесь есть две интересные вещи:
- Mercurial более или менее полностью забывает о дополнительном переводе, происходящем при взаимодействии с пультами Git и
- Существует полноценное хранилище Git, скрытое от глаз и иногда синхронизируемое с хранилищем Mercurial.
Важно то, что вы можете работать непосредственно со скрытым Git-репозиторием через систему Git. Если вы используете Hg-Git, то репозиторий Git синхронизируется только при подталкивании и извлечении из удаленных клонов Git, что означает, что эти локальные прямые изменения Git будут не синхронизированы с репозиторием Mercurial - в худшем случае вы делаете коммит несколько раз в Git, затем фиксируйте в Mercurial без синхронизации и эффективно создавайте две отдельные ветви, потому что коммиты Hg и коммиты Git имеют общего предка, но не опираются друг на друга. Тем не менее, Hg-Git предоставляет механизм для ручного запуска синхронизации между репозиториями через hg gimport [git-repo-to-import-from-if-not-local-hidden]
а также hg gexport
(экспортирует по умолчанию в локальную скрытую копию, создавая ее при необходимости). Принудительная синхронизация также должна помочь вам решить проблемы, которые вы заметили. Вы можете использовать Git для извлечения (или в терминологии Git, fetch
- git pull
эквивалентно hg pull --update
; git fetch
является hg pull
, что делает имя расширения Mercurial fetch действительно неудачным) новые наборы изменений в репозиторий Git, затем используйте hg gimport
импортировать эти наборы изменений в репозиторий Mercurial.
Теперь, если вы сделали что-то вроде редактирования истории или чего-то подобного, тогда все ставки сняты. Я не уверен, как Hg-Git справится с этим - я подозреваю, что это приведет к созданию двойников. Новые коммиты в клоне Mercurial будут добавлены в Git, но удаленные ревизии все еще находятся в репозитории Git и, вероятно, будут импортированы обратно в репозиторий Mercurial. (Это прямой результат метода автономной синхронизации наборов изменений Hg-Git.) В этом случае я предлагаю выбрать канонический репозиторий, стереть все клоны и сделать новый толчок с извинениями всем, чьи клоны были аннулированы этим беспорядком. (Это, кстати, часть того, почему сообщество Mercurial так настороженно относится к редактированию истории.)
Потенциальные решения
@EmilSit предложил вам запустить
hg pull git+ssh://github.com/you/githubrepo.git
непосредственно из канонического (не клон GitHub) хранилища Mercurial. Это имеет неплохие шансы на работу, если предположить, что метод Hg-Git по созданию исходного клона Git полностью независим от времени и детерминирован. (Последнее почти наверняка верно, но я не уверен в первом, см. Текст выше для более подробной информации.)Вы можете сделать локальный вариант этого: использовать
git clone ssh://github.com/you/githubrepo.git
чтобы получить местный чистый клон Git, а затем сделатьhg pull ../githubrepo
, (Для этого необходимо, чтобы у вас был установлен Git.) Hg-Git должен автоматически подключиться и выполнить преобразование. Преобразование также зависит от того, как Hg-Git выполняет преобразование детерминистическим, независимым от времени способом.Вы можете работать непосредственно со скрытым Git-репозиторием в исходном гибридном репозитории. использование
git fetch
(потенциально вы можете сначалаcd
в.git
папка скрыта в.hg
папка первая). Тогда бегиhg gimport && hg update
импортировать изменения из репозитория git и обновить. (Вы можете указать путь кgimport
-- или.
или путь к скрытому git-репо. Я подозреваю, что вы также можете указать путь к GitHub.)Вы можете использовать различные методы тупой трансплантации - экспорт серии патчей и т. Д. - и их фиксация вручную. Если вы хотите отдать должное другому разработчику при выполнении коммитов вручную, вы можете использовать
-u
возможность установить пользователя на основе принятия.Вы можете сделать "умную" пересадку с помощью трансплантата или удлинителя трансплантата. Сначала используйте Hg-Git, чтобы создать новый клон Mercurial из репозитория GitHub. Затем используйте одно из этих расширений, чтобы объединить два репозитория Mercurial.
По крайней мере, один из методов не трансплантации должен работать, потому что, если Hg-Git не выполняет свою магию в зависимости от времени, тогда должен быть возможность найти общий корень. Даже если общий корень найден, вы можете получить две в основном дублирующие (неназванные) ветви, которые затем необходимо объединить.
Я бы добавил, что вы даже можете получить сообщение об ошибке, связанной с репозиторием, когда вы помещаете репозиторий hg в git, затем клонируете репозиторий git из hg и затем пытаетесь получить изменения из исходного репозитория hg. Поскольку теперь у нас есть репозиторий hg, локально созданный из репозитория git, созданного из исходного репозитория hg, я полагаю, что локальное и исходное репозитории hg должны быть связаны, но иногда это не так.
Из-за различий в том, как hg и git обрабатывают имена авторов и электронные письма, если в вашем исходном репозитории hg было что-то другое для авторов, чем Name <mail@example.com>
в стиле вы увидите эту проблему. Причина в том, что hg-git пытается преобразовать авторов в строгий стиль git (который использует упомянутые пары имя-адрес электронной почты) и заполнит пробелы, если это не так (см. Объяснение в Readme: https: hg-git https://bitbucket.org/durin42/hg-git).
Таким образом, может случиться так, что автор набора изменений в исходном репозитории hg не совсем такой же, как в репозитории git; и в результате авторы репозитория hg, созданные из репозитория git, не будут совпадать с авторами исходного репозитория hg, например:
- Для набора изменений A в оригинальном репозитории hg автор установлен как
mail@example.com
, - Так как это не соответствует стандартному git, gg-git преобразует это в
mail@example.com <mail@example.com>
в git репо. - Теперь, когда вы клонируете репозиторий git в hg, у ревизии будет автор
mail@example.com <mail@example.com>
,
Поскольку для связывания двух репозиториев исходный коммит должен совпадать точно, вы получите ошибку "репозиторий не связан", даже если хеш, сообщение коммита, дата и время совпадают, но автор отличается. Довольно больно переживать (ага, теперь я наказан, потому что я забыл правильно установить автора три года назад!), Но вполне разумно.