Как сказать Git, что две коммиты на самом деле одинаковы в непересекающейся истории?
У меня есть репозиторий Git, который клонируется из другого репозитория Git, который является клоном из гигантского репо SVN. Мы можем обновить другое репозиторий Git из SVN и передать его на SVN, но с другим пользователем.
Я хочу публиковать свои локальные коммиты в SVN-репо прямо со своим собственным пользователем.
Это то, что я пробовал: я вручную создал ветвь git-svn
, добавив ее в .git/config
[branch "master"]
[svn-remote "svn"]
url = https://url/to/svn/trunk/repo_name
fetch = :refs/remotes/git-svn
Затем git svn fetch
, загруженный 32k совершает.
Но я закончил с двумя непересекающимися историями:
- Один из Git:
- Начиная с commit
674c35a
, который представляет состояние репо SVN в точке исходного клона.
- Филиал
master
всегда синхронизируется с SVN (через другое Git repo).
- В ветке
dev
есть наши текущие разработки, которые должны быть объединены с master
(обычно раздавлены), а затем переданы обратно в репозиторий SVN.
- Один для репо SVN:
- Начинается с правильной начальной фиксации.
- Он имеет значение 30k +.
- Конец, который Git изначально был клонирован из SVN [
fb1b9c7
] (но только с отличием от предыдущих коммитов, а не с полным репо в качестве фиксации начала).
- Тогда то же самое фиксирует (100+), что должно быть общим для
git/origin/master
.
Как я могу сказать Git, что начальная фиксация (674c35a
) на самом деле совпадает с фиксацией SVN (fb1b9c7
)? Таким образом, Git может как-то понять, что коммиты в master
, после клонирования, на самом деле такие же, как git-svn
?
Я попытался переустановить --onto
, как описано здесь, но это было не совсем то, что я хотел (коммиты не находятся в верхней части ветки).
Ответы
Ответ 1
Я считаю, что у меня есть метод, который должен работать для этого в моем сообщении в блоге Присвоение истории с помощью Git, которое в целях соблюдения правила сайта. Я опишу здесь:
Текущее состояние:
- Два репозитория git с расходящимися историями, но одно происхождение
Целевое состояние:
- Один git репо с двумя ветвями, представляющими эти расходящиеся истории
- Преобразуйте обе истории в ветки git (я думаю, вы уже получили это)
- Найдите точку расхождения, сравнивая журналы и видя, когда изменяется хеш дерево.
- Получить список идентификаторов дерева и идентификаторов фиксации в каждой ветки с помощью
git log --reverse --format="%T %H"
и сохранить это в файле
- Сравните списки, чтобы увидеть, где хеш дерева расходится (я использую программу diff, которая может делать столбцы, вы можете просто использовать awk и diff, хотя)
- Отметьте точку расхождения на целевой ветке репо и создайте новую ветку
- Извлечь все объекты из источника в цель
- Для каждой ревизии исходного источника создайте новую ревизию для цели, которая
- Является ли оформление дерева внешней ревизии с помощью
git read-tree -um $TREEID
- Использует исходное сообщение фиксации с помощью
git commit --reuse-message $ORIGINAL_COMMIT
Или... cat ваш список идентификатора дерева id + commit-id в этот script.
#!/bin/bash
# graft script
while read TREE COMMIT
do
git read-tree -um $TREE
git commit --reuse-message $COMMIT
done
Ответ 2
Ваша история, вероятно, выглядит примерно так:
*--*--*--fb1b9c7--*--*--* [git-svn] (version of master from SVN)
674c35a--*--*--* [master] (version of master from Git)
\
*--*--*--* [dev]
Похоже, у вас есть две проблемы: ваша история Git не содержит 30k +, фиксирует полную историю SVN, а dev
основана на (неполной) истории Git вместо версии SVN.
Так как fb1b9c7
== 674c35a
, вы должны уметь:
git rebase --onto git-svn master dev
Мои эксперименты показывают, что git rebase
не заботится о том, чтобы целевая ветвь (git-svn
) не имела той же истории, что и базовая ветвь (master
). Также не должно иметь значения, что SVN сохраняет только diffs, потому что git -svn преобразует эти diff в real Git, комментирует во время выборки.
Поскольку истории содержат одно и то же содержимое, вы даже можете это сделать:
git checkout dev
git rebase git-svn
После этого вы можете удалить master
и позволить этому дереву собирать мусор позже. (Если вам все еще нужна отдельная ветвь master
, тогда git checkout -b master git-svn
после удаления оригинала master
.)
Когда вы сказали:
(коммиты не находятся в верхней части ветки)
Я предполагаю, что вы имеете в виду commits fb1b9c7
и 674c35a
. Тем не менее, не имеет значения, что эти коммиты зарыты в истории, потому что мы выберем один (fb1b9c7
) для использования, а другой собираем мусор, как упоминалось выше.
Ответ 3
Если вы хотите заменить одно коммит другим фиксатором, просто используйте git replace
, например git replace 674c35a fb1b9c7
.
Если вы хотите сделать это постоянным, используйте git rebase
.