Что означает ошибка "refusing to merge unrelated histories"
Введение
TL;DR: Решение проблемы "Refusing to Merge Unrelated Histories" в Git
Ошибка Git "refusing to merge unrelated histories" возникает, когда Git пытается объединить ветки или репозитории без общей истории коммитов. Это может быть случай, когда кто-то пытается объединить два независимых репозитория, объединить два проекта или даже синхронизировать локальный проект с новым удалённым репозиторием.
Если у вас нет времени читать полную статью, вот краткие решения для устранения ошибки:
Основные решения:
--allow-unrelated-histories
: Добавьте этот флаг к командеmerge
, если хотите объединить несвязанные истории:git merge branch-name --allow-unrelated-histories
- Начните с чистого листа: Клонируйте удалённый репозиторий, скопируйте свои файлы и закоммитите их для чистой интеграции:
git clone repo-url
cp -r local-project/* repo-folder/
git add .
git commit -m "Integrate project"
git push origin branch-name - Перепишите историю: Используйте продвинутые техники, например, создайте ветку
сироту
, чтобы начать всё с чистого листа:git checkout --orphan new-branch
git add .
git commit -m "Initial commit"
git push -f origin branch-name
Давайте рассмотрим подробности, поскольку я вкратце затронул эту тему выше: Работая с Git'ом на протяжении многих лет, я могу подтвердить наличие ряда интересных проблем; одна из них, которая регулярно застаёт разработчиков врасплох, — это печально известная ошибка "refusing to merge unrelated histories".
Обычно это происходит, когда команды пытаются объединить репозитории или ветки, которые, по мнению Git, не имеют общего происхождения.
Я расскажу, почему это происходит и как правильно с этим справиться.
Понимание ошибки
Обычно ошибка выглядит следующим образом:
git merge origin/main
fatal: refusing to merge unrelated histories
Это не просто придирки Git'а, он на самом деле пытается помочь. Ошибка возникает, когда Git обнаруживает, что у двух веток или репозиториев, которые вы пытаетесь объединить, нет общей истории коммитов. Это может произойти при нескольких распространённых обстоятельствах:
- Когда вы пытаетесь объединить два независимо созданных репозитория
- Создание нового репозитория с
README
на GitHub и попытка запушить существующий локальный проект
Распространённые сценарии возникновения ошибки
Хочу поделиться наиболее частыми сценариями возникновения этой ошибки:
Новый удалённый репозиторий с существующим локальным проектом
Когда вы пытаетесь подтянуть из только что созданного удалённого репозитория в существующий локальный проект, Git будет жаловаться на несвязанные истории:
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
fatal: Need to specify how to reconcile divergent branches.
Это происходит потому, что вы инициализировали локальный репозиторий, а затем удалённый по отдельности. У них обоих есть свои собственные деревья истории.
Комбинирование двух независимых проектов
Когда вы пытаетесь объединить два проекта, начатые по отдельности, Git предотвратит слияние, чтобы вы случайно не объединили несвязанные кодовые базы:
# В основной директории проекта
git remote add other-project./path/to/other-project
git fetch other-project
git merge other-project/main # Ошибки с несвязанными историями
Как решить эту ошибку
Справиться с этим можно разными способами, в зависимости от ваших требований:
Использование --allow-unrelated-histories
Самый простое решение — использовать флаг --allow-unrelated-histories
. Вот что происходит при его использовании:
$ git merge origin/main --allow-unrelated-histories
Auto-merging README.md
CONFLICT (add/add): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Как видите, Git пытается объединить обе истории вместе и автоматически разрешает некоторые конфликты. После разрешения всех конфликтов видно, что слияние прошло успешно:
$ git commit -m "Merge remote repository with local, resolving conflicts"
[main 62c10f7] Merge remote repository with local, resolving conflicts
$ git status
On branch main
nothing to commit, working tree clean
Однако хочу сказать, что это решение не для всех случаев. Важно понимать, что именно вы объединяете и почему истории вообще не связаны.
Начните с чистого листа (чистый подход)
Иногда лучше начать с чистого листа:
# Резервное копирование текущей работы
cp -r project project_backup
# Начинаем с чистого листа
git clone git@github.com:username/repo.git
cd repo
# Копируем файлы (кроме каталога .git)
cp -r ../project_backup/* .
git add .
git commit -m "Integrate existing project"
git push origin main
Переписывание истории (продвинутый уровень)
В более сложных случаях может понадобиться переписать историю:
# Создание ветки сироты
git checkout --orphan temp_branch
# Добавление всех файлов
git add .
# Создание начального коммита
git commit -m "Initial commit"
# Удаление ветки main
git branch -D main
# Переименование текущей ветки в main
git branch -m main
# Принудительный push в remote
git push -f origin main
Рекомендации/лучшие практики обработки несвязанных историй
Ниже приведены несколько рекомендаций/лучших практик, выработанных мною в процессе работы с несвязанными историями.
- Всегда создавайте резервную копию: Прежде чем применить какое-либо решение, убедитесь, что вы сделали резервную копию своей работы.
- Знайте источник: Потратьте время на то, чтобы понять, почему истории не связаны друг с другом. Это поможет выбрать правильное решение.
- Документируйте своё решение: Если используете
--allow-unrelated-histories
, задокументируйте причины такого решения в сообщении коммита. - Проверьте наличие конфликтов: После создания слияния несвязанных историй проверьте результат на наличие конфликтов или несоответствий.
Когда использовать каждый из подходов
Мои рекомендации по выбору правильного подхода:
Используйте --allow-unrelated-histories
, когда:
- Хотите объединить истории
- Хотите сохранить оба дерева историй
- Понимаете последствия
Начните с чистого листа, когда:
- Проект относительно новый.
- Не нужно сохранять всю историю.
- Вам нужна чистая линейная история.
Переписывайте историю, когда:
- Нужна определённая структура истории
- Работаете в команде, хорошо знающей Git
- Можете координировать изменения со всеми разработчиками
Заключение
Хотя ошибка "refusing to merge unrelated histories" раздражает, на самом деле это Git пытается уберечь вас от потенциально проблемных слияний. Понимание причин возникновения этой ошибки и знание подходящих решений позволит уверенно справляться с подобными ситуациями и выбирать лучший подход для конкретного случая.
Помните, что цель — не просто заставить ошибку исчезнуть, а сохранить чистую, читаемую историю Git, служащую интересам вашего проекта. Потратьте время на понимание того, что подразумевает каждое решение, и выберите подходящее для вашей ситуации.