Skip to content

Wszystko o WordPressie, tworzeniu stron — i nie tylko

🐙 Błąd Git «fatal: refusing to merge unrelated histories»: przyczyny i rozwiązania

🐙 Błąd Git «fatal: refusing to merge unrelated histories»: przyczyny i rozwiązania

Wykonali Państwo git pull i zamiast oczekiwanych zmian terminal przywitał Państwa czerwonym komunikatem: fatal: refusing to merge unrelated histories. Projekt się nie zaktualizował, commity nie zostały pobrane, a Państwo zastanawiają się, czy nie uszkodzili Państwo repozytorium.

Nie, nie uszkodzili Państwo. Git po prostu odmawia zmieszania dwóch niezależnych historii i jest to przemyślane zachowanie, a nie błąd. W ciągu pięciu minut nie tylko zrozumieją Państwo, dlaczego ten błąd występuje, ale także nauczą się go naprawiać w każdej sytuacji: podczas pierwszego pusha, po utracie .git oraz przy łączeniu różnych projektów.

💡 Szybki przegląd:

  • Kiedy Git odmawia scalenia niepowiązanych gałęzi i dlaczego jest to słuszne
  • Flaga --allow-unrelated-histories, uniwersalne rozwiązanie dla pull, merge i pierwszego pusha
  • Scenariusze krok po kroku: klonowanie bez historii, nowe repozytorium, rebase i force-push
  • Co zrobić, jeśli flaga nie pomogła, i jak nie doprowadzać do tego błędu w przyszłości

Co oznacza błąd i dlaczego Git go zgłasza

Git śledzi historię poprzez łańcuch commitów. Każdy commit odwołuje się do rodzica, w ten sposób budowany jest graf, na podstawie którego Git rozumie, co skąd pochodzi. Kiedy wykonują Państwo git merge, Git szuka wspólnego przodka dwóch gałęzi i na jego podstawie oblicza różnicę.

Ale czasami wspólnego przodka po prostu nie ma. Dwa grafy commitów nie przecinają się, jak dwa osobne projekty, które nigdy o sobie nie wiedziały. W takiej sytuacji Git odmawia ślepego scalenia historii i wyrzuca:

1fatal: refusing to merge unrelated histories

To nie jest błąd w zwykłym sensie. To zabezpieczenie: Git mówi Państwu „nie rozumiem, jak te dwie historie są powiązane, więc nie będę zgadywać". Rozwiązanie istnieje i jest wbudowane w Gita, począwszy od wersji 2.9.0 (wydanej w czerwcu 2016 roku).

Dwa typowe scenariusze prowadzące do błędu

Pierwszy scenariusz, **uszkodzenie lub usunięcie katalogu **.git. Sklonowali Państwo projekt, pracowali z kodem, ale folder .git został usunięty (przypadkowo, przez antywirusa lub podczas kopiowania bez ukrytych plików). Git traci całą lokalną historię i podczas próby git push lub git pull postrzega Państwa katalog roboczy jako zupełnie nowy projekt, w żaden sposób niepowiązany ze zdalnym repozytorium.

Drugi scenariusz, nowe repozytorium spotyka się z istniejącym. Wykonali Państwo git init, dodali kilka commitów lokalnie, a następnie spróbowali podłączyć zdalne repozytorium, które ma już własną historię. Git widzi dwa niezależne grafy commitów i odmawia ich zmieszania. Często zdarza się to, gdy zaczynają Państwo projekt od zera, a potem decydują się załadować go na GitHub na istniejące repozytorium, lub gdy przenoszą kod z jednego projektu do drugiego.

Oba scenariusze rozwiązuje się tym samym mechanizmem, ale przed jego zastosowaniem warto zrozumieć, co dokładnie chcą Państwo uzyskać w rezultacie: scalenie dwóch historii w jedną czy całkowite zastąpienie jednej historii drugą.

Rozwiązanie: flaga --allow-unrelated-histories

Kluczem do naprawy jest flaga --allow-unrelated-histories. Mówi ona Gitowi wprost: „Wiem, że te gałęzie nie mają wspólnego przodka i świadomie chcę je scalić". Flaga działa z obiema głównymi komendami, git pull i git merge.

**Dla **git pull (najczęstszy przypadek):

1git pull origin main --allow-unrelated-histories

Proszę zastąpić main nazwą Państwa gałęzi, jeśli jest inna (master, develop itp.). Git utworzy merge-commit, który połączy dwie niezależne historie. Najprawdopodobniej otworzy się edytor komunikatu commita, proszę opisać, dlaczego łączą Państwo historie, zapisać i zamknąć edytor.

**Dla **git merge (gdy gałęzie są lokalne):

1git merge feature-branch --allow-unrelated-histories

Po udanym scaleniu Git zaproponuje wypchnięcie wyniku. Proszę nie zapomnieć tego zrobić:

1git push origin main

Ważny niuans: --allow-unrelated-histories nie eliminuje konfliktów scalania. Jeśli w obu gałęziach są pliki o takich samych nazwach, Git i tak poprosi Państwa o ręczne rozwiązanie konfliktów, flaga odpowiada tylko za połączenie historii, a nie za zawartość plików.

Scenariusze krok po kroku dla różnych sytuacji

Sytuacja 1: pierwszy push do niepustego zdalnego repozytorium

Utworzyli Państwo projekt lokalnie (git init → commity), a na GitHubie jest już repozytorium z README.md i .gitignore. Bezpośredni git push nie przejdzie, ponieważ zdalna gałąź zawiera commity, których Państwo nie mają.

Prawidłowa kolejność:

Najpierw proszę pobrać zdalną historię i scalić ją z Państwa lokalną:

1git pull origin main --allow-unrelated-histories

Proszę rozwiązać konflikty, jeśli występują (zazwyczaj konfliktuje README.md), wykonać commit scalenia, następnie:

1git push origin main

Sytuacja 2: odzyskiwanie po utracie.git

Folder .git został usunięty, ale katalog roboczy jest nienaruszony. Można przywrócić połączenie ze zdalnym repozytorium bez utraty niezacommitowanych zmian:

1git init
2git remote add origin <url-репозитория>
3git fetch origin
4git reset --mixed origin/main

Komenda git reset --mixed synchronizuje indeks Gita ze zdalną gałęzią, ale zachowuje wszystkie Państwa pliki robocze nietknięte. Następnie proszę dodać zmiany i wykonać nowy commit:

1git add .
2git commit -m "Восстановление после потери .git"
3git push origin main

To podejście jest lepsze niż --allow-unrelated-histories, ponieważ nie tworzy sztucznego merge-commita i zachowuje historię czystą.

Sytuacja 3: rebase z niepowiązanymi historiami

Komenda git rebase również może zgłosić ten błąd, szczególnie często podczas używania flagi --preserve-merges (obecnie zastąpionej przez --rebase-merges). Rozwiązaniem jest dodanie --allow-unrelated-histories:

1git rebase --rebase-merges --allow-unrelated-histories main

Proszę jednak być ostrożnym: rebase przepisuje historię i jeśli ktoś jeszcze pracuje z tą gałęzią, stworzą mu Państwo problemy. Dla współdzielonych gałęzi zawsze proszę preferować merge.

Co zrobić, jeśli flaga nie pomogła

Czasami --allow-unrelated-histories wykonuje się bez błędów, ale rezultat nie jest tym, czego Państwo chcieli.

Problem: merge-commit zaśmieca historię. Jeśli połączyli Państwo dwa duże projekty, graf commitów staje się nieczytelny. W takim przypadku proszę rozważyć alternatywę, przeniesienie plików z zachowaniem historii poprzez git format-patch i git am:

1git format-patch --root -o patches/ HEAD
2git am patches/*.patch

Problem: po scaleniu projekt się nie kompiluje. Scalanie niepowiązanych historii może prowadzić do duplikacji plików konfiguracyjnych, konfliktów zależności lub niekompatybilnych wersji pakietów. Po --allow-unrelated-histories zawsze proszę sprawdzać: zależności (npm install / composer install), pliki konfiguracyjne (.env, config/), ścieżki i importy w kodzie. Lepiej poświęcić pięć minut na sprawdzenie teraz, niż rozwiązywać problem z padającym buildem w CI później.

Problem: rozmyślili się Państwo. Wycofanie scalenia niepowiązanych historii można wykonać standardowo, git reset --hard HEAD~1 (jeśli jeszcze nie wypchnęli Państwo wyniku) lub git revert -m 1 HEAD (jeśli już wypchnęli).

Jak uniknąć błędu w przyszłości

Trzy proste zasady, które uchronią Państwa przed tym błędem w codziennej pracy.

Nie usuwać .git bez skrajnej potrzeby. Jeśli trzeba skopiować kod bez historii, proszę używać git archive lub kopiować pliki, świadomie wykluczając ukryty folder .git, a nie przypadkowo.

Nie tworzyć nowego repozytorium wewnątrz istniejącego. Jeśli trzeba wydzielić część bazy kodu do osobnego projektu, proszę używać git subtree split lub git filter-branch (obecnie zalecane jest git filter-repo). Te narzędzia zachowają historię potrzebnych plików i Git będzie wiedział, skąd pochodzą.

Przed git init w folderze z kodem zawsze proszę sprawdzać, czy nie ma tam już repozytorium: git status. Jeśli Git odpowiada fatal: not a git repository, można inicjalizować. Jeśli pokazuje status, są już Państwo wewnątrz istniejącego repozytorium i git init nie jest tu potrzebne.

Tym, którzy dopiero zaczynają pracę z Gitem, polecamy nasz poradnik „Git instrukcja dla początkujących", gdzie krok po kroku omówiono klucze SSH, tworzenie repozytorium i pełny cykl pracy z GitHubem. A jeśli Git nie jest jeszcze zainstalowany, proszę zacząć od instrukcji „Jak zainstalować Git w Windows".

⁉️🤔 Częste pytania

W jakich wersjach Gita działa --allow-unrelated-histories?

Flaga pojawiła się w Git 2.9.0 (czerwiec 2016) i jest obecna we wszystkich kolejnych wersjach. Jeśli Państwa wersja Gita jest starsza, proszę ją zaktualizować: komenda git --version pokaże bieżącą, a git update-git-for-windows (na Windows) lub menedżer pakietów Państwa systemu zaktualizuje do aktualnej. Najprościej sprawdzić wersję Gita komendą git --version w terminalu. Na połowę 2026 roku aktualna jest gałąź 2.48+. Jeśli są Państwo na Windows i Git był instalowany bardzo dawno, proszę pobrać świeży instalator z git-scm.com, autoaktualizacja w starych wersjach działała niestabilnie.

Czy można używać flagi bezpośrednio z git push?

Nie, git push nie przyjmuje --allow-unrelated-histories. Push nie tworzy scalenia, jedynie wysyła istniejące commity. Błąd „unrelated histories" podczas push oznacza, że Państwa lokalna gałąź i zdalna rozeszły się na poziomie historii. Rozwiązanie: najpierw git pull --allow-unrelated-histories, proszę rozwiązać konflikty i dopiero potem git push. Formalnie --allow-unrelated-histories działa z git fetch + git merge oraz z git pull (który wewnętrznie wykonuje fetch + merge). Push pozostaje osobną operacją, którą wykonują Państwo po udanym scaleniu. Proszę nie próbować obchodzić tego przez --force, stracą Państwo cudze commity na zdalnym repozytorium.

Co jest lepsze dla czystości historii: merge czy rebase?

Dla łączenia niepowiązanych historii zdecydowanie merge. Rebase w tym kontekście stwarza więcej problemów, niż rozwiązuje: próbuje odtworzyć commity jednej gałęzi na drugiej, ale bez wspólnego przodka prowadzi to do konfliktów przy każdym commicie. Merge z --allow-unrelated-histories robi dokładnie to, co potrzebne, tworzy jeden punkt połączenia dwóch grafów, po którym historia jest jednolita. Wyjątek stanowi sytuacja, gdy celowo chcą Państwo przepisać historię i dokładnie wiedzą, co robią. Na przykład podczas przenoszenia kodu z jednego repozytorium do drugiego z oczyszczeniem ze starych commitów. W tym przypadku git rebase --allow-unrelated-histories może mieć sens, ale do codziennej pracy proszę wybierać merge.

Utraciłem folder .git, ale mam niezacommitowane zmiany. Czy je stracę?

Nie, nie stracą ich Państwo. Sam folder .git zawiera tylko historię i metadane Gita, ale nie Państwa pliki robocze. Wszystkie zmienione, nowe, a nawet niezacommitowane pliki pozostaną w katalogu roboczym nietknięte. Procedura odzyskiwania została opisana w sekcji „Sytuacja 2" powyżej, git initgit remote addgit fetchgit reset --mixed. Kluczowy moment: proszę użyć właśnie --mixed, a nie --hard. Flaga --mixed resetuje indeks, ale zachowuje wszystkie zmiany w plikach. Jeśli nie są Państwo pewni, proszę zrobić kopię zapasową całego folderu projektu przed odzyskiwaniem, zajmie to dziesięć sekund i całkowicie wyeliminuje ryzyko utraty danych w każdej niestandardowej sytuacji.

Błąd występuje podczas klonowania przez IDE. Czy to ten sam problem?

Tak, ten sam. Niektóre IDE (na przykład PHPStorm, Visual Studio, stare wersje IntelliJ) podczas tworzenia projektu z szablonu inicjalizują nowe repozytorium Git, a następnie próbują podłączyć zdalne. Powstaje dokładnie drugi scenariusz z początku artykułu. Rozwiązanie jest takie samo: proszę otworzyć terminal w folderze projektu i wykonać git pull origin main --allow-unrelated-histories. Po ręcznym scaleniu IDE automatycznie wykryje nowy stan, wystarczy odświeżyć okno projektu lub kliknąć Refresh na panelu Git.

Czy należy bać się błędu „unrelated histories"?

Nie. To jeden z najbezpieczniejszych błędów Gita, nie uszkadza danych, nie usuwa plików i nie przeszkadza w kontynuowaniu pracy. Flaga --allow-unrelated-histories nie jest protezą ani obejściem, lecz udokumentowaną możliwością, specjalnie dodaną przez twórców Gita na wypadek, gdy świadomie chcą Państwo połączyć dwie niezależne historie.

Po opanowaniu tej komendy zyskują Państwo do dyspozycji potężne narzędzie: teraz mogą Państwo łączyć projekty o dowolnym stopniu izolacji, przenosić kod między repozytoriami i odzyskiwać pracę po utracie .git, a wszystko to bez paniki i tworzenia repozytorium od nowa. Jeśli Git czegoś dziś Państwa nauczył, to tego, że „fatal" w jego komunikatach nie oznacza „fatalny dla projektu", oznacza „nie będę zgadywać, powiedz mi wprost, co robić".