Kezdőlap
» Alap tudás
»
Hogyan javítsuk ki a „Git Push elutasítva: nem gyorsított előretekerés” hibát a változtatások elvesztése nélkül
Hogyan javítsuk ki a „Git Push elutasítva: nem gyorsított előretekerés” hibát a változtatások elvesztése nélkül
A nem gyorsított átvitelű elutasítás a Git előzményeinek védelmét szolgálja, nem pedig a helyi munka törlését. Ez általában azt jelenti, hogy a távoli ág a helyi ág utolsó szinkronizálása után lépett előre, így a távoli ág frissítése az aktuális ággal elvetné az ott már létező commitokat. A GitHub jelenlegi dokumentációja ugyanezt a helyzetet írja le: először kérd le a upstream módosításokat, integráld őket lokálisan, majd küldd el újra.
A legbiztonságosabb általános munkafolyamat a következő: védjük a nem véglegesített munkákat, hívjuk le a távoli ágat az aktuális ág módosítása nélkül, vizsgáljuk meg, hogyan tértek el a történetek, válasszunk az egyesítés vagy az újraalapozás között, szükség esetén oldjuk fel az ütközéseket, majd küldjük újra. Ne agit push --force vagy a paranccsal kezdjük git reset --hardcsak azért, hogy a hiba eltűnjön.
Mit jelent valójában a „nem gyorsított előretekerés” kifejezés?
Tegyük fel, hogy a helyi mainág tartalmazza a commit `t L, míg a távoli origin/mainegy másik commitra lépett R. Ha egyik commit sem a másik őse, akkor a történetek eltértek. Egy normál push parancs nem tudja egyszerűen a távoli ág mutatóját a `t`-ra mozgatni Lanélkül, hogy Ra `t` eltűnne az adott ág látható előzményeiből.
Egy gyorsított frissítés más: az új ágtipp a régi leszármazottja, így az ág előre mozgatása megőrzi mindazt, ami már elérhető belőle. A hivatalos git pushkézikönyv definiálja ezt az eredet szabályt, és figyelmeztet, hogy --forceletiltja a normál védelmet, és távoli commitok elvesztését okozhatja.
A nem gyorsított visszautasítás azt jelenti, hogy a Git nem hajlandó lecserélni a távoli előzményeket, amelyeket a helyi ág még nem tartalmaz.
Mielőtt bármit is tennél: biztonságosan rögzítve van a helyi munkád?
Fut:
git status
Ha a munkafa tiszta, az aktuális módosításokat már commitok képviselik, és létrehozhatsz egy extra biztonsági referenciát a távoli integrálása előtt:
git branch backup-before-sync
Ez az ág az aktuális commitra mutat, így van egy egyszerű neved az integráció előtti állapotnak.
Ha módosított vagy nyomon követés nélküli, de még nem véglegesített fájlok vannak, a lehívás vagy az újraalapozás előtt válasszon az alábbi módszerek közül:
Véglegesítsd el a véglegesítést, ha a munka logikailag készen áll a véglegesítésre.
Rejtsd el őket, ha a munka befejezetlen git stash push -u -m "before non-fast-forward fix":.
Az -uopció a nem követett fájlokat is tartalmazza. A hivatalos git-stash dokumentáció elmagyarázza, hogy a stash rögzíti a munkakönyvtár és az index állapotát, és visszaállít egy tiszta működő fát. A figyelmen kívül hagyott fájlokat a -u; -aopció a figyelmen kívül hagyott fájlokat is tartalmazza, de erre ritkán van szükség ennél a problémánál.
Fontos: ha git statusolyan fájlokat mutat, amelyeket nem veszíthet el, ne futtassa a parancsot git reset --hard. Ez a parancs elveti a nem véglegesített munkafa-módosításokat.
1. lépés: Azonnal fel kell használni git pull?
Megteheted, de a „fetch first” (először letölt) módszerrel könnyebb érvelni . A GitHub dokumentumok git fetchletöltik a távoli munkát, és frissítik a távoli nyomkövetési ágakat anélkül, hogy ezeket a változtatásokat egyesítenék az aktuális ággal. Ez hasznos diagnosztikai lépéssé teszi, mivel a helyi előzmények módosítása előtt megvizsgálhatod a helyzetet.
A lehívás után a távoli nyomkövetési ág origin/mainaz imént lekért távoli állapotot jelöli. A log parancs lehetővé teszi, hogy csak a helyi és csak a távoli oldalról elérhető commitokat lásd.
Ha a helyi ágadnak nincsenek egyedi commitjai, és egyszerűen csak le van maradva, gyakran előre is tekerheted:
git merge --ff-only origin/main
Akkor nincs mit egyeztetni; az ágad egyszerűen továbblép.
2. lépés: Egyesítés vagy újraalapozás – melyiket válassza?
Mindkettő megőrzi a módosításokat. A különbség a kapott előzmények alakjában rejlik.
Helyzet
Általában választják
Miért
Megosztott ág, például mainahol a helyi commitjaid már mások számára ismertek lehetnek
Összeolvad
Megőrzi a meglévő commit-azonosítókat, és nem írja át a helyi commitokat.
A commitjaid lokálisak/privátok, és lineáris előzményeket szeretnél.
Újraalapozás
A frissített távoli ág felett újrajátssza a helyi commitokat.
Bizonytalan vagy, és a lehető legkevesebb történelem-átírást szeretnéd
Összeolvad
Könnyebb megmagyarázni és biztonságosabb a közös történelem szempontjából.
Útvonal egyesítése
git fetch origin
git merge origin/main
Ha nincsenek ütközések, a Git befejezi az integrációt. Ha az ágak valóban eltérnek egymástól, az eredmény egy összevonási commitot is tartalmazhat.
Útvonal újraalapozása
git fetch origin
git rebase origin/main
A Rebase az aktuális ágra jellemző egyedi commitokat veszi, és újraalkotja azokat a . ágra origin/main. A Git rebase dokumentációja ezt úgy írja le, mint egy sor commit átültetését egy másik kiindulópontra. Mivel ezek a commitok új commit azonosítókat kapnak, a rebase a leghatékonyabb olyan helyi munkákhoz, amelyeket még nem osztottak meg nyilvános előzményként.
Ha egy gyorsbillentyűt részesítesz előnyben, akkor git pull --rebase origin maina `fetch` egy lehívást, majd egy újraalapozást hajt végre, míg a `while` git pull --no-rebase origin mainexplicit módon az egyesítési viselkedést választja. Helyreállítási helyzetben a különálló ` fetchand` parancsok gyakran egyértelműbbek, mivel először a távoli állapotot vizsgálhatod meg.mergerebase
Miután a távoli módosításokat lekérte, integrálja azokat tudatosan – egyesítéssel vagy újraalapozással – a felülírás helyett.
3. lépés: Mit kell tenni, ha a Git ütközést jelez?
Az ütközés nem jelenti azt, hogy a módosítások elvesznek. Azt jelenti, hogy a Git nem tudja automatikusan eldönteni, hogyan kombinálja a módosításokat ugyanahhoz a tartalomhoz.
Először is vizsgáld meg az államot:
git status
Nyisson meg minden ütköző fájlt, döntse el, hogy mi legyen a végső tartalom, távolítsa el az ütközésjelzőket, majd készítse elő a feloldott fájlt:
git add path/to/file
Ha az egyesítést választotta, akkor az összes konfliktus előkészítése után fejezze be az egyesítést:
git commit
Ha az újrabázisolást választottad, folytasd a commitok újrajátszását:
git rebase --continue
Ha az újrabázisolás rosszul megy, és vissza szeretnéd állítani az ágat az újrabázisolás előtti állapotába, használd a következőt:
git rebase --abort
A jelenlegi Git újrabázisolási kézikönyv kifejezetten a --continueés a értéket dokumentálja --aborterre a célra. Ne használd git rebase --skipa értéket pusztán egy ütközés megszüntetésére, kivéve, ha ténylegesen ki akarod hagyni a commit újrajátszását.
Először oldd fel a tartalmat, készítsd elő a javított fájlt, majd fejezd be az egyesítést vagy folytasd az újrabázisolást.
4. lépés: Mikor biztonságos újra tolni?
A beküldés előtt ellenőrizd a működő fát és a legutóbbi előzményeket:
git status
git log --oneline --graph --decorate -n 12
Ezután nyomd meg a szokásos módon:
git push origin main
Ha egyesítetted a távoli ágat, vagy csak olyan commitokat állítottál újra, amelyeket korábban még soha nem küldtek el, akkor általában egy normál push műveletnek kell lennie a megfelelőnek, mivel az új távoli tip a helyi tip őse lesz.
Miután a fióktelep tartalmazza mind a távoli munkát, mind a tervezett helyi módosításokat, egy normál átvitellel biztonságosan előre lehet állítani a távoli munkát.
Mikor kell használni --force-with-lease?
Csak akkor használd, ha szándékosan írtál át olyan előzményeket, amelyek már léteznek a távoli gépen – például egy korábban már feltöltött funkcióágat újraalapoztál, és most le kell cserélned az ág régi véglegesítési szekvenciáját.
git push --force-with-lease origin feature-branch
A hivatalos git pushdokumentáció elmagyarázza, miért biztonságosabb ez, mint a sima --force: a bérlet ellenőrzi, hogy a távoli hivatkozás továbbra is rendelkezik-e a várt értékkel. Ha egy másik személy új munkát küldött az átírás alapjául szolgáló állapot után, a kényszerített frissítés elutasításra kerül ahelyett, hogy vakon felülírná a commitjait.
Ez a védelem nem ok a kényszerített küldések rutinszerű használatára. Kerüld a megosztott ágak kényszerített küldését, kivéve main, ha a csapatod kifejezetten engedélyezi az átírt előzményeket. A szerveroldali ágvédelem a helyi parancstól függetlenül elutasíthatja a kényszerített küldéseket.
Ne helyettesítsd be ezt:
git push --force origin main
A Plain (Plain) --forceletiltja a normál, nem gyorsított előretekeréses biztonsági ellenőrzést, és felülírhatja a távoli commitokat. A Git saját dokumentációja figyelmeztet, hogy ez a távoli adattár commitjainak elvesztését okozhatja.
Mi van, ha már lefuttattad a rossz parancsot?
A Git gyakran még mindig elegendő helyi előzményekkel rendelkezik egy korábbi ág pozíciójának visszaállításához. Futtassa a következőt:
git reflog
A relogok rögzítik a helyi referenciák legutóbbi frissítéseit, beleértve a korábbi értékeket is HEAD. Ha megtalálod azt a commitot, amely a hibás visszaállítás vagy újraalapozás előtti ágadat képviselte, hozz létre egy rescue ágat ahelyett, hogy azonnal mainújra áthelyeznéd:
git branch rescue-work <commit-id>
Most vizsgáld meg rescue-workés állítsd helyre a szükséges commitokat. A hivatalos git-reflog dokumentáció a reflogokat olyan feljegyzésekként írja le, amelyek azt mutatják, hogy hová mutattak a korábbi ágtippek és egyéb hivatkozások.
Miért jött git pulllétre néha egyesítési commit?
git pullelőször lekéri, majd integrálja a kiválasztott upstream ágat. A beállításoktól és a tárház konfigurációjától függően ez az integráció lehet egyesítés vagy újrabázisolás. Ha kiszámítható viselkedést szeretne a nem gyorsított visszautasítás javítása során, akkor kifejezetten jelezze szándékát:
# Preserve branch history with a merge
git pull --no-rebase origin main
# Replay private local commits on top
git pull --rebase origin main
A legjobb láthatóság érdekében git fetch originelőször használd, majd futtasd git merge origin/main, vagy git rebase origin/mainkülön-külön.
Mi van, ha a távoli commit nemkívánatos?
Ne feltételezd, hogy a „nem kívánt” azt jelenti, hogy biztonságosan törölhető. Először is vizsgáld meg:
Ha a commit egy másik fejlesztőhöz, egy bothoz, egy függőségfrissítőhöz vagy a webes felületen végrehajtott módosításhoz tartozik, integráld vagy állítsd vissza a normál előzményeken keresztül. Ha a csapatod szándékosan beleegyezett a távoli előzmények cseréjébe, akkor egy védett kényszerített áthelyezés (guarded force push) megfelelő lehet – de ez egy repository-előzményekkel kapcsolatos döntés, nem a nem gyorsított előretekeréssel járó hibák standard javítása.
Biztonságos döntési ellenőrzőlista
Nincsenek véglegesített fájlok? Integráció előtt véglegesítse vagy mentse el őket.
Biztonsági pontra van szükséged? Hozz létre egy biztonsági mentési ágat az aktuális commitnál.
Távirányító cserélve? Fuss el, git fetch originmielőtt eldöntenéd, mit tegyél.
Megosztott előzmények? Inkább az egyesítést válaszd, ha el akarod kerülni a commitok újraírását.
Privát helyi commitok? A Rebase lineárisan tudja tartani a történetét.
Ütközés? Oldja fel a fájlt, hozzon létre egyesítést, majd fejezze be az egyesítést, vagy folytassa az újrabázisolást.
Már publikált történelmi tételek szándékosan átdolgozva? Gondoljunk csak a --force-with-lease, nem pedig a sima , szóra --force.
A lényeg
A nem gyorsított üzenet egy biztonsági korlát, amely azt jelzi, hogy a távoli ág olyan előzményeket tartalmaz, amelyeket a javasolt push nem őriz meg. A megoldás nem az, hogy túllépjük ezt a korlátot. Védjük meg a helyi munkánkat, hívjuk le a távoli ágat, vizsgáljuk meg a divergenciát, integráljuk egyesítéssel vagy újrabázisolással, oldjuk meg szándékosan a konfliktusokat, és küldjük újra.
Ha emlékszel egy szabályra, tedd azzá: először a kényszerítést kell elvégezni, majd a módosításokat meg kell érteni . Ez megőrzi mind a módosításaidat, mind a távoli gépen már meglévő munkát – és egy ijesztő push elutasítást rutinszerű Git szinkronizációs problémává változtat.