Hem
» Grundläggande kunskap
»
Hur man åtgärdar "Git Push Rejected: Non-Spolar framåt" utan att förlora ändringar
Hur man åtgärdar "Git Push Rejected: Non-Spolar framåt" utan att förlora ändringar
En avvisning som inte spolas framåt skyddar Git-historiken, inte tar bort ditt lokala arbete. Det betyder vanligtvis att fjärrgrenen flyttades framåt efter att din lokala gren senast synkroniserades, så att uppdatera fjärrgrenen med din nuvarande gren skulle kassera commits som redan finns där. GitHubs nuvarande dokumentation beskriver samma situation: hämta först ändringarna uppströms, integrera dem lokalt och skicka sedan igen.
Det säkraste generella arbetsflödet är: skydda allt ocommitterat arbete, hämta fjärrgrenen utan att ändra din nuvarande gren, kontrollera hur historiken divergerade, välj antingen sammanslagning eller ombasering, lös konflikter om det behövs och tryck igen. Börja inte med git push --forceeller git reset --hardbara för att få felet att försvinna.
Vad betyder egentligen "icke-snabbspolning framåt"?
Anta att din lokala maingren innehåller commit L, medan fjärrgrenen origin/mainhar avancerat till en annan commit R. Om ingen av commit-funktionerna är en förfader till den andra har historiken divergerat. En normal push kan inte bara flytta fjärrgrenspekaren till Lutan att Rförsvinna från grenens synliga historik.
En snabbspolningsuppdatering är annorlunda: den nya grentipset är en ättling till den gamla, så om man flyttar grenen framåt bevaras allt som redan är åtkomligt från den. Den officiella git pushmanualen definierar denna regel för ättling och varnar för att --forcedet inaktiverar det normala skyddet och kan orsaka att fjärrcommits går förlorade.
Ett avslag utan snabbspolning framåt innebär att Git vägrar att ersätta fjärrhistorik som din lokala gren ännu inte innehåller.
Innan du gör något: är ditt lokala arbete säkert inspelat?
Sikt:
git status
Om arbetsträdet är rent representeras dina aktuella ändringar redan av commits och du kan skapa en extra säkerhetsreferens innan du integrerar fjärrkontrollen:
git branch backup-before-sync
Den grenen pekar på den aktuella commiten, så du har ett enkelt namn för tillståndet före integration.
Om du har modifierade eller ospårade filer som inte är committade, välj en av dessa metoder innan du hämtar eller ombaserar:
Commit dem om arbetet är logiskt klart för en commit.
Göm dem om arbetet är ofullständigt git stash push -u -m "before non-fast-forward fix":.
Alternativet -uinkluderar ospårade filer. Den officiella git-stash-dokumentationen förklarar att en stash registrerar arbetskatalogens och indexets tillstånd och återställer ett rent arbetsträd. Ignorerade filer inkluderas inte av -u; -a, vilket skulle inkludera ignorerade filer också, men det är sällan nödvändigt för det här problemet.
Viktigt: om git statusvisar filer som du inte har råd att förlora, kör inte git reset --hard. Det kommandot kan ignorera obekräftade ändringar i arbetsträdet.
Steg 1: Ska du använda git pullomedelbart?
Det kan du, men det är lättare att resonera kring att hämta `fetch first` . GitHub-dokument som git fetchladdar ner distansarbete och uppdaterar grenar för fjärrspårning utan att sammanfoga dessa ändringar med din nuvarande gren. Det gör det till ett användbart diagnostiskt steg eftersom du kan inspektera situationen innan du ändrar den lokala historiken.
Efter hämtningen origin/mainrepresenterar grenen remote-tracking det fjärrtillstånd du just hämtade. Med log-kommandot kan du se commits som bara är åtkomliga från din lokala sida och bara från fjärrsidan.
Om din lokala filial inte har några unika commits och helt enkelt ligger efter, kan du ofta spola framåt:
git merge --ff-only origin/main
Då finns det inget att förlika; din gren går helt enkelt framåt.
Steg 2: Sammanfoga eller ombasera – vilket ska du välja?
Båda kan bevara dina ändringar. Skillnaden är formen på den resulterande historiken.
Situation
Vanligtvis väljer
Varför
Delad gren, till exempel maindär dina lokala commits redan kan vara kända för andra.
Slå ihop
Bevarar befintliga commit-identiteter och skriver inte om dina lokala commits.
Dina commits är lokala/privata och du vill ha en linjär historik
Rebase
Spelar upp dina lokala commits ovanpå den uppdaterade fjärrgrenen.
Du är osäker och vill ha minsta möjliga omskrivning av historien
Slå ihop
Det är lättare att förklara och säkrare för gemensam historia.
Sammanfoga rutt
git fetch origin
git merge origin/main
Om det inte finns några konflikter slutför Git integrationen. Om grenarna verkligen divergerar kan resultatet inkludera en merge-commit.
Rebase-rutt
git fetch origin
git rebase origin/main
Rebase tar de commits som är unika för din nuvarande branch och återanvänder dem ovanpå . origin/mainGits rebase-dokumentation beskriver det som att transplantera en serie commits till en annan startpunkt. Eftersom dessa commits får nya commit-ID:n används rebase bäst för lokalt arbete som inte redan har delats som offentlig historik.
Om du föredrar en genväg, git pull --rebase origin mainutför en hämtning följt av en rebase, medan git pull --no-rebase origin mainden explicit väljer sammanslagningsbeteende. För en återställningssituation är separate- fetchoch merge/ rebase-kommandon ofta tydligare eftersom du kan inspektera fjärrtillståndet först.
När de fjärranslutna ändringarna har hämtats, integrera dem avsiktligt – genom sammanslagning eller ombasering – snarare än att skriva över dem.
Steg 3: Vad ska du göra om Git rapporterar en konflikt?
En konflikt betyder inte att dina ändringar är borta. Det betyder att Git inte automatiskt kan bestämma hur ändringar i samma innehåll ska kombineras.
Kontrollera först staten:
git status
Öppna varje konfliktfylld fil, bestäm vad det slutliga innehållet ska vara, ta bort konfliktmarkörerna och placera sedan den lösta filen i olika steg:
git add path/to/file
Om du valde sammanslagning, slutför sammanslagningen efter att alla konflikter har mellanlagrats:
git commit
Om du valde rebase, fortsätt spela upp dina commits:
git rebase --continue
Om rebasen går dåligt och du vill återställa grenen till dess tillstånd före rebasen, använd:
git rebase --abort
Den nuvarande Git-rebasemanualen dokumenterar specifikt --continueoch --abortför detta ändamål. Använd inte git rebase --skipbara för att få en konflikt att försvinna om du inte faktiskt avser att utelämna att commiten spelas upp igen.
Lös innehållet först, mellanlagra den korrigerade filen och slutför sedan sammanfogningen eller fortsätt med ombasen.
Steg 4: När är det säkert att trycka igen?
Innan du skickar, verifiera arbetsträdet och den senaste historiken:
git status
git log --oneline --graph --decorate -n 12
Tryck sedan normalt:
git push origin main
Om du sammanfogade den fjärrstyrda grenen, eller ombaserade endast commits som aldrig hade pushats tidigare, borde en normal push vanligtvis vara rätt operation eftersom det nya fjärrtipset kommer att vara en förfader till ditt lokala tips.
När din gren innehåller både fjärrarbetet och dina avsedda lokala ändringar, kan en vanlig knapptryckning föra fjärrarbetet framåt på ett säkert sätt.
När ska du använda --force-with-lease?
Använd den bara när du avsiktligt skriver om historik som redan finns på fjärrkontrollen — till exempel ombaserade du en funktionsgren som du tidigare hade pushat och nu behöver ersätta den grenens gamla commit-sekvens.
git push --force-with-lease origin feature-branch
Den officiella git pushdokumentationen förklarar varför detta är säkrare än plain --force: leasen kontrollerar att fjärrreferensen fortfarande har det värde du förväntar dig. Om en annan person skickade nytt arbete efter det tillstånd du baserade din omskrivning på, avvisas den påtvingade uppdateringen istället för att blint skriva över deras commits.
Det skyddet är inte en anledning att använda tvångspush rutinmässigt. Undvik tvångspush av delade grenar, till exempel mainom inte ditt team uttryckligen tillåter omskriven historik. Grenskydd på serversidan kan också avvisa tvångspush oavsett ditt lokala kommando.
Ersätt inte detta:
git push --force origin main
Plain --forceinaktiverar den vanliga säkerhetskontrollen utan snabbspolning framåt och kan skriva över fjärrcommits. Gits egen dokumentation varnar för att det kan orsaka att fjärrarkivet förlorar commits.
Tänk om du redan kört fel kommando?
Git har ofta fortfarande tillräckligt med lokal historik för att återställa en tidigare branchposition. Kör:
git reflog
Refloggar registrerar senaste uppdateringar av lokala referenser, inklusive tidigare värden för HEAD. Om du hittar commiten som representerade din gren före den felaktiga återställningen eller rebasen, skapa en räddningsgren istället för att omedelbart flytta den mainigen:
git branch rescue-work <commit-id>
Inspektera rescue-workoch återställ nu de commits du behöver. Den officiella git-reflog-dokumentationen beskriver reflogs som register över vart branchtips och andra referenser tidigare pekade.
Varför git pullskapades ibland en merge-commit?
git pullhämtar först och integrerar sedan den valda uppströmsgrenen. Beroende på alternativ och arkivkonfiguration kan integrationen vara en sammanslagning eller en ombas. Om du vill ha förutsägbart beteende när du åtgärdar ett avslag som inte snabbspolar framåt, ange din avsikt uttryckligen:
# Preserve branch history with a merge
git pull --no-rebase origin main
# Replay private local commits on top
git pull --rebase origin main
För bästa synlighet, använd git fetch originförst och kör git merge origin/maineller git rebase origin/mainseparat.
Vad händer om fjärrcommiten är oönskad?
Anta inte att "oönskad" betyder att det är säkert att radera. Kontrollera det först:
Om commiten tillhör en annan utvecklare, en bot, en beroendeuppdaterare eller en ändring som gjorts i webbgränssnittet, integrera eller återställ den via normal historik. Om ditt team medvetet har gått med på att ersätta fjärrhistoriken kan en guarded force push vara lämplig – men det är ett beslut om arkivhistorik, inte standardlösningen för ett fel som inte rör snabbspolning framåt.
En checklista för säkra beslut
Ocommitterade filer? Committa eller lagra dem före integration.
Behöver du en säkerhetspunkt? Skapa en backup-gren vid den aktuella commit-filen.
Fjärrkontrollen har ändrats? Kör git fetch origininnan du bestämmer dig för vad du ska göra.
Delad historik? Föredrar du merge om du vill undvika att skriva om commits.
Privata lokala commits? Rebase kan hålla historiken linjär.
Konflikt? Lös filen, mellanlagra den och slutför sedan sammanslagningen eller fortsätt med ombasen.
Är normal integration klar? Använd en normal git push.
Redan publicerad historia avsiktligt ombaserad? Tänk på det --force-with-lease, inte bara --force.
Slutsats
Meddelandet om att inte spola framåt är en säkerhetsbarriär som talar om för dig att fjärrgrenen innehåller historik som din föreslagna push inte bevarar. Lösningen är inte att övervinna den barriären. Skydda ditt lokala arbete, hämta fjärrgrenen, inspektera divergensen, integrera den med merge eller rebase, lös konflikter medvetet och push igen.
Om du kommer ihåg en regel, gör den så här: hämta och förstå innan du tvingar fram ändringar . Det bevarar både dina ändringar och det arbete som redan finns på fjärrkontrollen – och förvandlar ett skrämmande avvisande av push-kommandon till ett rutinmässigt Git-synkroniseringsproblem.