How to Fix “Git Push Rejected: Non-Fast-Forward” Without Losing Changes

A non-fast-forward rejection is Git protecting history, not deleting your local work. It usually means the remote branch moved forward after your local branch last synchronized, so updating the remote with your current branch would discard commits that already exist there. GitHub’s current documentation describes the same situation: retrieve the upstream changes first, integrate them locally, then push again.

The safest general workflow is: protect any uncommitted work, fetch the remote branch without modifying your current branch, inspect how the histories diverged, choose either merge or rebase, resolve conflicts if necessary, and push again. Do not start with git push --force or git reset --hard just to make the error disappear.

Official references used for this guide include GitHub Docs: Dealing with non-fast-forward errors, Git: git-push documentation, Git: git-fetch documentation, and Git: git-rebase documentation.

What does “non-fast-forward” actually mean?

Suppose your local main branch contains commit L, while the remote origin/main has advanced to a different commit R. If neither commit is an ancestor of the other, the histories have diverged. A normal push cannot simply move the remote branch pointer to L without making R disappear from that branch’s visible history.

A fast-forward update is different: the new branch tip is a descendant of the old one, so moving the branch forward preserves everything already reachable from it. The official git push manual defines this ancestry rule and warns that --force disables the normal protection and can cause remote commits to be lost.

Terminalen som viser git push origin main ble avvist med en ikke-spolingsfeil fordi den eksterne inneholder arbeid som ikke finnes lokalt.
A non-fast-forward rejection means Git is refusing to replace remote history that your local branch does not yet contain.

Before doing anything: is your local work safely recorded?

Run:

git status

If the working tree is clean, your current changes are already represented by commits and you can create an extra safety reference before integrating the remote:

git branch backup-before-sync

That branch points to the current commit, so you have an easy name for the pre-integration state.

If you have modified or untracked files that are not committed, choose one of these approaches before pulling or rebasing:

  • Commit them if the work is logically ready for a commit.
  • Stash them if the work is incomplete: git stash push -u -m "before non-fast-forward fix".

The -u option includes untracked files. The official git-stash documentation explains that a stash records the working directory and index state and restores a clean working tree. Ignored files are not included by -u; -a would include ignored files too, but that is rarely necessary for this problem.

Important: if git status shows files you cannot afford to lose, do not run git reset --hard. That command can discard uncommitted working-tree changes.

Step 1: Should you use git pull immediately?

You can, but fetch first is easier to reason about. GitHub documents that git fetch downloads remote work and updates remote-tracking branches without merging those changes into your current branch. That makes it a useful diagnostic step because you can inspect the situation before altering local history.

git fetch origin
git status -sb
git log --oneline --graph --decorate --left-right HEAD...origin/main

After the fetch, the remote-tracking branch origin/main represents the remote state you just retrieved. The log command lets you see commits reachable only from your local side and only from the remote side.

If your local branch has no unique commits and is simply behind, you can often fast-forward it:

git merge --ff-only origin/main

Then there is nothing to reconcile; your branch simply moves forward.

Step 2: Merge or rebase—which should you choose?

Both can preserve your changes. The difference is the shape of the resulting history.

Situation Usually choose Why
Shared branch such as main where your local commits may already be known to others Merge Preserves existing commit identities and does not rewrite your local commits.
Your commits are local/private and you want a linear history Rebase Replays your local commits on top of the updated remote branch.
You are unsure and want the least history rewriting Merge It is easier to explain and safer for shared history.

Merge route

git fetch origin
git merge origin/main

If there are no conflicts, Git completes the integration. If the branches truly diverged, the result may include a merge commit.

Rebase route

git fetch origin
git rebase origin/main

Rebase takes the commits that are unique to your current branch and reapplies them on top of origin/main. Git’s rebase documentation describes it as transplanting a series of commits onto a different starting point. Because those commits receive new commit IDs, rebase is best used for local work that has not already been shared as public history.

If you prefer a shortcut, git pull --rebase origin main performs a fetch followed by a rebase, while git pull --no-rebase origin main explicitly chooses merge behavior. For a recovery situation, separate fetch and merge/rebase commands are often clearer because you can inspect the remote state first.

Terminal som viser git pull origin main som henter eksterne objekter og oppdaterer grenen med eksterne endringer.
After the remote changes are retrieved, integrate them deliberately—by merge or rebase—rather than overwriting them.

Step 3: What should you do if Git reports a conflict?

A conflict does not mean your changes are gone. It means Git cannot automatically decide how to combine changes to the same content.

Først må du sjekke staten:

git status

Åpne hver konfliktfylte fil, bestem hva det endelige innholdet skal være, fjern konfliktmarkørene, og plasser deretter den løste filen:

git add path/to/file

Hvis du valgte sammenslåing, fullfør sammenslåingen etter at alle konflikter er iscenesatt:

git commit

Hvis du valgte rebase, fortsett å spille av commitene dine på nytt:

git rebase --continue

Hvis rebasen går dårlig og du vil returnere grenen til tilstanden før rebasen, bruk:

git rebase --abort

Den nåværende Git-rebase-manualen dokumenterer spesifikt --continueog --abortfor dette formålet. Ikke bruk git rebase --skipbare for å få en konflikt til å forsvinne med mindre du faktisk har til hensikt å utelate at commiten spilles av på nytt.

Terminal som viser en avvikende hovedgren, en app.js-flettingskonflikt og kommandoer som lagrer den løste filen og oppretter konfliktløsnings-commiten.
Løs innholdet først, plasser den korrigerte filen i en rekkefølge, og fullfør deretter sammenslåingen eller fortsett rebasen.

Trinn 4: Når er det trygt å presse igjen?

Før du legger inn data, kontroller arbeidstreet og den nylige historikken:

git status
git log --oneline --graph --decorate -n 12

Trykk deretter normalt:

git push origin main

Hvis du slo sammen den eksterne grenen, eller bare rebaserte commits som aldri hadde blitt pushet før, bør en vanlig push vanligvis være den riktige operasjonen fordi det nye eksterne tipset vil være en forgjenger til ditt lokale tips.

Terminalen viser at git push origin main fullføres etter at eksterne endringer er integrert.
Når grenen din inneholder både fjernarbeidet og de tiltenkte lokale endringene, kan et vanlig trykk trygt føre fjernarbeidet fremover.

Når bør du bruke --force-with-lease?

Bruk den bare når du med vilje omskrev historikk som allerede finnes på fjernkontrollen – for eksempel hvis du har rebasert en funksjonsgren som du tidligere hadde pushet og nå må erstatte den grenens gamle commit-sekvens.

git push --force-with-lease origin feature-branch

Den offisielle git pushdokumentasjonen forklarer hvorfor dette er tryggere enn vanlig --force: leasen sjekker at den eksterne referansen fortsatt har verdien du forventer. Hvis en annen person sendte nytt arbeid etter tilstanden du baserte omskrivingen din på, blir den tvungne oppdateringen avvist i stedet for å overskrive deres commits blindt.

Denne beskyttelsen er ikke en grunn til å bruke tvangspushing rutinemessig. Unngå tvangspushing av delte grener, med mainmindre teamet ditt eksplisitt tillater omskrevet historikk. Grenbeskyttelse på serversiden kan også avvise tvangspushing uavhengig av din lokale kommando.

Ikke erstatt dette:

git push --force origin main

Plain --forcedeaktiverer den vanlige sikkerhetskontrollen uten spoling fremover og kan overskrive eksterne commits. Gits egen dokumentasjon advarer om at det kan føre til at det eksterne depotet mister commits.

Hva om du allerede har kjørt feil kommando?

Git har ofte fortsatt nok lokal historikk til å gjenopprette en tidligere grenposisjon. Kjør:

git reflog

Reblogger registrerer nylige oppdateringer til lokale referanser, inkludert tidligere verdier for HEAD. Hvis du finner commiten som representerte grenen din før den feilaktige tilbakestillingen eller rebasen, opprett en redningsgren i stedet for å flytte den mainigjen umiddelbart:

git branch rescue-work <commit-id>

Inspiser rescue-workog gjenopprett nå commitene du trenger. Den offisielle git-reflog-dokumentasjonen beskriver reflogger som registreringer av hvor branch-tips og andre referanser tidligere pekte.

Hvorfor git pullopprettes det noen ganger en merge-commit?

git pullhenter først, og integrerer deretter den valgte oppstrømsgrenen. Avhengig av alternativene og depotkonfigurasjonen, kan denne integrasjonen være en sammenslåing eller en rebase. Hvis du ønsker forutsigbar oppførsel mens du fikser en avvisning som ikke spoler fremover, må du angi din intensjon eksplisitt:

# Preserve branch history with a merge
git pull --no-rebase origin main

# Replay private local commits on top
git pull --rebase origin main

For mest mulig synlighet, bruk git fetch originførst og løp git merge origin/maineller git rebase origin/mainseparat.

Hva om den eksterne commiten er uønsket?

Ikke anta at «uønsket» betyr at det er trygt å slette. Sjekk det først:

git fetch origin
git log --oneline --decorate HEAD..origin/main
git show origin/main

Hvis commit-en tilhører en annen utvikler, en bot, en avhengighetsoppdaterer eller en endring gjort i webgrensesnittet, integrer eller tilbakestill den gjennom normal historikk. Hvis teamet ditt bevisst har gått med på å erstatte den eksterne historikken, kan en bevoktet kraftoverføring være passende – men det er en avgjørelse knyttet til depothistorikk, ikke standardløsningen for en feil som ikke spoler fremover.

En sjekkliste for trygge beslutninger

  • Ikke-registrerte filer? Registrer eller lagr dem før integrering.
  • Trenger du et sikkerhetspunkt? Opprett en backup-gren ved gjeldende commit.
  • Fjernkontroll endret? Kjør git fetch originfør du bestemmer deg for hva du skal gjøre.
  • Delt historikk? Foretrekker du merge hvis du vil unngå å skrive om commits.
  • Private lokale commits? Rebase kan holde historikken lineær.
  • Konflikt? Løs filen, lag den, og fullfør deretter sammenslåingen eller fortsett rebasen.
  • Normal integrasjon fullført? Bruk en normal git push.
  • Allerede publisert historie med vilje rebasert? Tenk på det --force-with-lease, ikke bare --force.

Konklusjon

Meldingen om ikke å spole fremover er en sikkerhetsbarriere som forteller deg at den eksterne grenen inneholder historikk som den foreslåtte pushen din ikke bevarer. Løsningen er ikke å overvinne denne barrieren. Beskytt ditt lokale arbeid, hent den eksterne grenen, inspiser divergensen, integrer den med merge eller rebase, løs konflikter med vilje, og push på nytt.

Hvis du husker én regel, gjør den slik: hent og forstå før du tvinger frem noe . Det bevarer både endringene dine og arbeidet som allerede er på fjernkontrollen – og gjør en skremmende avvisning av push til et rutinemessig Git-synkroniseringsproblem.

Legg igjen en kommentar

How to Fix "Tailwind CSS Styles Not Updating" in a Vite React App

How to Fix "Tailwind CSS Styles Not Updating" in a Vite React App

Fix Tailwind CSS styles not updating in Vite React by checking Tailwind v4 setup, CSS imports, source detection, dynamic classes, HMR, and stale caches.

Slik fikser du ModuleNotFoundError: Ingen modul kalt 'pip' i Python 3

Slik fikser du ModuleNotFoundError: Ingen modul kalt 'pip' i Python 3

Fiks Python 3s ModuleNotFoundError for pip på Windows, macOS og Linux med ensurepip, OS-pakker, virtuelle miljøer og tolkekontroller.

Slik fikser du «Ingen tillatelse (offentlig nøkkel)» i GitHub SSH

Slik fikser du «Ingen tillatelse (offentlig nøkkel)» i GitHub SSH

Fiks GitHub SSH-tillatelse nektet (offentlig nøkkel) ved å sjekke verten, aktiv SSH-nøkkel, GitHub-konto, SSO-autorisasjon, ekstern URL og port 22-tilgang.

How to Fix “Git Push Rejected: Non-Fast-Forward” Without Losing Changes

How to Fix “Git Push Rejected: Non-Fast-Forward” Without Losing Changes

Fix a Git non-fast-forward push safely. Protect local work, fetch remote commits, choose merge or rebase, resolve conflicts, and push without losing changes.

Slik fikser du "Nginx 502 Bad Gateway" når du bruker proxy til Node.js

Slik fikser du "Nginx 502 Bad Gateway" når du bruker proxy til Node.js

Rett Nginx 502 Bad Gateway-feil med en Node.js-oppstrøm ved å sjekke appporten, NGINX-logger, proxy_pass-adresse, containernettverk, tidsavbrudd og omlasting.

Slik fikser du «Typen 'null' kan ikke tilordnes til type» i TypeScript

Slik fikser du «Typen 'null' kan ikke tilordnes til type» i TypeScript

Rett TypeScripts feilmelding «Typen 'null' kan ikke tilordnes til type» med unionstyper, innsnevring, standardverdier og sikre påstander under strictNullChecks.

Slik fikser du feilen «Prisma Client has not been generated yet»

Slik fikser du feilen «Prisma Client has not been generated yet»

Fiks feilen med at Prisma Client ikke er generert ved å sjekke generatoren, skjemaet, utdatastien, importene, versjonene, monorepo-oppsettet og byggetrinnene ved distribusjon.

Slik fikser du «ERR_MODULE_NOT_FOUND» i Node.js ESM-importer

Slik fikser du «ERR_MODULE_NOT_FOUND» i Node.js ESM-importer

Fiks Node.js ERR_MODULE_NOT_FOUND i ESM ved å sjekke importstier, filtyper, pakkeinstallasjon, eksport, ESM-modus og rene installasjoner.

Slik løser du SSL-sertifikatproblemet: Unable to Get Local Issuer Certificate i Git

Slik løser du SSL-sertifikatproblemet: Unable to Get Local Issuer Certificate i Git

Løs Git-feilmeldingen 'unable to get local issuer certificate' ved å identifisere tillitsbakgrunnen, installere riktig CA-kjede og beholde SSL-verifisering aktivert.

Slik løser du MongoDB nettverksavbrudd i Mongoose-tilkoblingen

Slik løser du MongoDB nettverksavbrudd i Mongoose-tilkoblingen

Løs MongoDB nettverksavbrudd i Mongoose ved å identifisere avbruddstypen, teste Atlas- eller TCP-tilgjengelighet, korrigere URI-en, og justere tidsavbrudd kun når det er berettiget.