
🐙 Git-viga fatal refusing to merge unrelated histories: põhjused ja lahendus
Sa tegid git pull ja oodatud muudatuste asemel tervitas terminal sind punase reaga: fatal: refusing to merge unrelated histories. Projekt ei uuenenud, kommitid ei tõmmanud ja sa istud ning mõtled, kas lõhkusid repositooriumi.
Ei, sa ei lõhkunud seda. Git lihtsalt keeldub kahte sõltumatut ajalugu segamast ja see on tahtlik käitumine, mitte viga. Viie minuti pärast sa mitte ainult ei mõista, miks see viga tekib, vaid õpid ka seda igas olukorras parandama: esimesel tõukamisel, pärast .git kaotamist ja erinevate projektide ühendamisel.
💡 Kiire ülevaade:
- Millal Git keeldub mitteseotud harusid ühendamast ja miks see on õige
--allow-unrelated-historieslipp, universaalne lahenduspull,mergeja esimese push'i jaoks- Samm-sammult stsenaariumid: kloonimine ilma ajaloota, uus repositoorium, rebase ja force-push
- Mida teha, kui lipp ei aita, ja kuidas seda viga tulevikus vältida
Mida viga tähendab ja miks Git selle viskab
Git jälgib ajalugu läbi kommitide ahela. Iga kommit viitab oma eellasele, ehitades graafi, mida Git kasutab mõistmaks, mis kust tuli. Kui teed git merge, otsib Git kahe haru ühist eellast ja arvutab sellest lähtuvalt erinevuse.
Kuid mõnikord pole ühist eellast lihtsalt olemas. Kaks kommitigraafi ei lõiku, nagu kaks eraldi projekti, mis teineteisest kunagi ei teadnud. Sellises olukorras keeldub Git ajalugusid pimesi ühendamast ja viskab:
1 fatal: refusing to merge unrelated histories
See pole viga tavapärases mõttes. See on kaitse: Git ütleb sulle: „Ma ei mõista, kuidas need kaks ajalugu on seotud, seega ma ei hakka oletama." Lahendus on olemas ja see on Giti sisse ehitatud alates versioonist 2.9.0 (välja antud juunis 2016).
Kaks tüüpilist stsenaariumi, mis veani viivad
Esimene stsenaarium, .git kataloogi riknemine või kustutamine. Sa kloonisid projekti, töötasid koodiga, kuid .git kaust sai kustutatud (kogemata, viirusetõrje poolt või kopeerimisel ilma peidetud failideta). Git kaotab kogu kohaliku ajaloo ja git push või git pull katsel käsitleb sinu töökataloogi täiesti uue projektina, mis pole kaugrepositooriumiga seotud.
Teine stsenaarium, uus repositoorium kohtub olemasolevaga. Sa tegid git init, lisasid mitu kommiti kohapeal, seejärel proovisid ühendada kaugrepositooriumi, millel on juba oma ajalugu. Git näeb kahte sõltumatut kommitigraafi ja keeldub neid segamast. See juhtub sageli, kui alustad projekti nullist, seejärel otsustad selle GitHubi üles laadida olemasoleva repositooriumi peale või koodi ühest projektist teise üle kandes.
Mõlemad stsenaariumid lahendatakse sama mehhanismiga, kuid enne selle rakendamist peaksid mõistma, mida täpselt saavutada soovid: kahe ajaloo ühendamist üheks või ühe ajaloo täielikku asendamist teisega.
Lahendus: --allow-unrelated-histories lipp
Selle parandamise võti on --allow-unrelated-histories lipp. See ütleb Gitile selgesõnaliselt: „Ma tean, et neil harudel pole ühist eellast ja ma tahan neid teadlikult ühendada." Lipp töötab mõlema peamise käsuga, git pull ja git merge.
git pull jaoks (kõige tavalisem juhtum):
1 git pull origin main --allow-unrelated-histories
Asenda main oma haru nimega, kui see erineb (master, develop jne). Git loob ühendamiskommiti, mis seob kaks sõltumatut ajalugu. Tõenäoliselt avaneb redaktor kommiti sõnumi jaoks, kirjelda, miks sa ajalugusid ühendad, salvesta ja sulge redaktor.
git merge jaoks (kui harud on kohalikud):
1 git merge feature-branch --allow-unrelated-histories
Pärast edukat ühendamist palub Git sul tulemuse üles lükata. Ära unusta seda teha:
1 git push origin main
Oluline nüanss: --allow-unrelated-histories ei kõrvalda ühendamiskonflikte. Kui mõlemal harul on samanimelised failid, palub Git sul konfliktid ikkagi käsitsi lahendada, lipp tegeleb ainult ajalugude ühendamisega, mitte failide sisuga.
Samm-sammult stsenaariumid erinevateks olukordadeks
Olukord 1: esimene push mittetühja kaugrepositooriumisse
Sa lõid projekti kohapeal (git init → kommitid) ja GitHubis on juba repositoorium koos README.md ja .gitignore failidega. Otsene git push ei tööta, sest kaug-haru sisaldab kommitte, mida sul pole.
Õige järjekord:
Esmalt tõmba kauge ajalugu ja ühenda see oma kohalikuga:
1 git pull origin main --allow-unrelated-histories
Lahenda konfliktid, kui neid on (tavaliselt README.md konfliktid), tee ühendamiskommit, seejärel:
1 git push origin main
Olukord 2: taastamine pärast.git kaotamist
.git kaust on kustutatud, kuid töökataloog on puutumata. Saad taastada ühenduse kaugrepositooriumiga, kaotamata salvestamata muudatusi:
1 git init 2 git remote add origin <repository-url> 3 git fetch origin 4 git reset --mixed origin/main
Käsk git reset --mixed sünkroniseerib Giti indeksi kaug-haruga, kuid jätab kõik sinu tööfailid puutumata. Pärast seda lisa muudatused ja tee uus kommit:
1 git add . 2 git commit -m "Recovery after losing .git" 3 git push origin main
See lähenemine on eelistatavam kui --allow-unrelated-histories, sest see ei loo kunstlikku ühendamiskommiti ja hoiab ajaloo puhtana.
Olukord 3: rebase mitteseotud ajalugudega
Ka git rebase käsk võib selle vea visata, eriti kui kasutad --preserve-merges lippu (nüüd asendatud --rebase-merges lipuga). Lahendus, lisa --allow-unrelated-histories:
1 git rebase --rebase-merges --allow-unrelated-histories main
Kuid ole ettevaatlik: rebase kirjutab ajaloo ümber ja kui keegi teine selle haruga töötab, tekitate talle probleeme. Jagatud harude puhul eelista alati merge käsku.
Mida teha, kui lipp ei aita
Mõnikord töötab --allow-unrelated-histories vigadeta, kuid tulemus pole see, mida soovisid.
Probleem: ühendamiskommit risustab ajalugu. Kui ühendasid kaks suurt projekti, muutub kommitigraaf raskesti loetavaks. Sel juhul kaalu alternatiivi, failide ülekandmist ajaloo säilitamisega git format-patch ja git am abil:
1 git format-patch --root -o patches/ HEAD 2 git am patches/*.patch
Probleem: pärast ühendamist projekt ei kompileeru. Mitteseotud ajalugude ühendamine võib viia duplikaat konfiguratsioonifailide, sõltuvuste konfliktide või mitteühilduvate paketiversioonideni. Pärast --allow-unrelated-histories kontrolli alati: sõltuvused (npm install / composer install), konfiguratsioonifailid (.env, config/), teed ja impordid koodis. Parem kulutada viis minutit kontrollimisele nüüd kui tegeleda ebaõnnestunud ehitustega CI-s hiljem.
Probleem: sa muutsid meelt. Saad mitteseotud ajalugude ühendamise tagasi võtta standardsel viisil, git reset --hard HEAD~1 (kui sa pole tulemust veel üles lükanud) või git revert -m 1 HEAD (kui sa juba lükkasid üles).
Kuidas viga tulevikus vältida
Kolm lihtsat reeglit, mis säästavad sind sellest veast igapäevatöös.
Ära kustuta .git ilma absoluutse vajaduseta. Kui pead kopeerima koodi ilma ajaloota, kasuta git archive või kopeeri failid, jättes peidetud .git kausta teadlikult, mitte kogemata välja.
Ära loo uut repositooriumi olemasoleva sisse. Kui pead osa koodibaasist eraldi projekti eraldama, kasuta git subtree split või git filter-branch (nüüd soovitatakse git filter-repo). Need tööriistad säilitavad vajalike failide ajaloo ja Git teab, kust need tulid.
Enne git init kasutamist koodiga kaustas kontrolli alati, kas seal on juba repositoorium: git status. Kui Git vastab fatal: not a git repository, võid initsialiseerida. Kui see näitab staatust, oled juba olemasolevas repositooriumis ja git init pole siin vajalik.
Neile, kes alles alustavad Gitiga töötamist, soovitame meie juhendit "Git'i juhend algajatele", see käsitleb SSH võtmeid, repositooriumi loomist ja kogu GitHubi töövoogu samm-sammult. Ja kui Git pole veel installitud, alusta juhendist "Kuidas installida Git Windowsile".
⁉️🤔 Korduma kippuvad küsimused
Millised Giti versioonid toetavad --allow-unrelated-histories lippu?
Lipp ilmus Git 2.9.0-s (juuni 2016) ja on olemas kõigis järgnevates versioonides. Kui sinu Giti versioon on vanem, uuenda seda: käsk
git --versionnäitab praegust versiooni jagit update-git-for-windows(Windowsis) või sinu süsteemi paketihaldur uuendab praeguse väljalaskeni. Lihtsaim viis Giti versiooni kontrollimiseks ongit --versionkäsk terminalis. 2026. aasta keskpaiga seisuga on praegune haru 2.48+. Kui oled Windowsis ja Git paigaldati ammu, lae värske paigaldaja alla saidilt git-scm.com, automaatne uuendamine vanades versioonides töötas ebastabiilselt.
Kas ma saan lippu kasutada otse git push käsuga?
Ei,
git pushei aktsepteeri--allow-unrelated-historieslippu. Push ei loo ühendamist, see saadab ainult olemasolevaid kommitte. Viga „unrelated histories" push'i puhul tähendab, et sinu kohalik ja kauge haru on ajaloo tasemel lahknenud. Lahendus: esmaltgit pull --allow-unrelated-histories, lahenda konfliktid ja alles seejärelgit push. Formaalselt töötab--allow-unrelated-historieskäskudegagit fetch+git mergejagit pull(mis sisemiselt teeb fetch + merge). Push jääb eraldi operatsiooniks, mille sooritad pärast edukat ühendamist. Ära ürita sellest mööda hiilida--forcelipuga, sa kaotad teiste inimeste kommitid kaugrepositooriumis.
Mis on puhta ajaloo jaoks parem: merge või rebase?
Mitteseotud ajalugude ühendamiseks kindlasti
merge. Rebase selles kontekstis tekitab rohkem probleeme kui lahendab: see üritab ühe haru kommitte teise peale uuesti esitada, kuid ilma ühise eellaseta viib see konfliktideni iga kommiti juures. Merge koos--allow-unrelated-historieslipuga teeb täpselt seda, mida vaja, loob ühe ühenduspunkti kahe graafi vahel, mille järel on ajalugu ühtne. Erand: kui soovid tahtlikult ajalugu ümber kirjutada ja tead täpselt, mida teed. Näiteks koodi ühest repositooriumist teise ülekandmisel koos vanadest kommititest puhastamisega. Sel juhul võibgit rebase --allow-unrelated-historiesolla mõttekas, kuid igapäevatööks vali merge.
Kaotasin .git kausta, kuid mul on salvestamata muudatusi. Kas ma kaotan need?
Ei, sa ei kaota neid.
.gitkaust ise sisaldab ainult ajalugu ja Giti metaandmeid, kuid mitte sinu tööfaile. Kõik muudetud, uued ja isegi salvestamata failid jäävad töökataloogi puutumata. Taastamise protseduur on kirjeldatud ülalpool „Olukord 2" all,git init→git remote add→git fetch→git reset --mixed. Võtmepunkt: kasuta täpselt--mixed, mitte--hard.--mixedlipp lähtestab indeksi, kuid säilitab kõik muudatused failides. Kui pole kindel, tee enne taastamist kogu projektikaustast varukoopia, see võtab kümme sekundit ja välistab täielikult andmekao riski igas mittestandardses olukorras.
Viga ilmneb läbi IDE kloonimisel. Kas see on sama probleem?
Jah, sama. Mõned IDE-d (näiteks PHPStorm, Visual Studio, IntelliJ vanemad versioonid) initsialiseerivad projektist mallist loomisel uue Giti repositooriumi ja proovivad seejärel kaugrepositooriumiga ühenduda. See on täpselt teine stsenaarium artikli algusest. Lahendus on sama: ava terminal projektikaustas ja käivita
git pull origin main --allow-unrelated-histories. Pärast käsitsi ühendamist tuvastab IDE uue oleku automaatselt, lihtsalt värskenda projekti akent või klõpsa Git paneelil Refresh.
Kas peaksid kartma viga „unrelated histories"?
Ei. See on üks ohutumaid Giti vigu, see ei riku andmeid, ei kustuta faile ega takista töö jätkamist. --allow-unrelated-histories lipp pole kark ega möödahiilimine, vaid dokumenteeritud võimalus, mille Giti arendajad spetsiaalselt lisasid juhtudeks, kui soovid teadlikult ühendada kaks sõltumatut ajalugu.
Olles selle käsu selgeks õppinud, saad võimsa tööriista: nüüd saad ühendada mis tahes isolatsiooniastmega projekte, kanda koodi repositooriumide vahel ja taastada töö pärast .git kaotamist, ja seda kõike ilma paanikata ja repositooriumi nullist uuesti loomata. Kui Git sulle täna midagi õpetas, siis seda, et „fatal" tema sõnumites ei tähenda „projektile saatuslik", vaid „ma ei hakka oletama, ütle mulle selgesõnaliselt, mida teha."



