✦ Oplossingen · Server- en developerfouten

! [rejected] main -> main (non-fast-forward): push geweigerd

Git weigert je push met ‘! [rejected] (non-fast-forward)’ of ‘(fetch first)’? Lees waarom, hoe je bijwerkt met pull --rebase en waarom force-push riskant is.

Zo ziet de foutmelding eruit

  • ! [rejected] main -> main (non-fast-forward)
  • ! [rejected] main -> main (fetch first)
  • error: failed to push some refs to
  • Updates were rejected because the tip of your current branch is behind
  • Updates were rejected because the remote contains work that you do not have locally.
  • ! [remote rejected] main -> main (protected branch hook declined)

Waarom gebeurt dit?

Git pusht alleen als jouw versie een rechtstreekse voortzetting is van wat er al op de server staat. Dat heet een fast-forward: de server kan zijn branch simpelweg doorschuiven naar jouw nieuwste commit. Heeft iemand anders (of jij vanaf een andere computer) intussen commits gepusht die jij lokaal niet hebt, dan zou jouw push die commits overschrijven. Git weigert dat en meldt ! [rejected].

Er zijn twee varianten van dezelfde situatie. Bij (fetch first) heeft de server commits die jouw computer nog helemaal niet kent; je hebt dus nog niet opgehaald. Bij (non-fast-forward) heb je die commits al wel opgehaald, maar staat jouw branch erachter of is hij ervan afgeweken. De hint ‘the tip of your current branch is behind its remote counterpart’ zegt precies dat.

Het gebeurt ook na een eigen git commit --amend of git rebase van commits die je al eerder had gepusht. Die commits hebben dan een nieuwe identiteit, en voor Git is je branch dan afgeweken van de server. Een derde vorm is [remote rejected]: dan weigert de server zelf, bijvoorbeeld omdat de branch beschermd is en alleen via een pull request of merge request mag veranderen.

Zo herken je dit probleem

  • De push begint wel, maar eindigt met ! [rejected] en error: failed to push some refs; inloggen lukte dus.
  • Krijg je ‘Permission denied (publickey)’, dan komt je push niet eens zover en gaat het om de SSH-sleutel: zie Permission denied (publickey).
  • Staat er [remote rejected] met ‘protected branch’ of ‘pre-receive hook declined’, dan weigert de serverregel en helpt bijwerken niet; dan moet je via een andere branch en een pull request werken.
  • Geeft het bijwerken daarna een conflict, ga dan verder bij merge conflict.

Zo los je het op, stap voor stap

Menunamen kunnen per versie of toestel iets anders heten. Loop de stappen op volgorde af en stop zodra het werkt.

  1. Kijk wat er op de server staat

    Haal eerst op wat er nieuw is, zonder iets samen te voegen. Daarna zie je welke commits de server heeft die jij niet hebt, en omgekeerd. Zo weet je of het om je eigen werk vanaf een andere computer gaat of om werk van een collega.

    git fetch origin
    git status
    git log --oneline main..origin/main
    git log --oneline origin/main..main
  2. Werk bij met pull --rebase

    De nette oplossing is je eigen commits bovenop de nieuwste versie van de server zetten. Met git pull --rebase haalt Git de commits van de server op en speelt het jouw commits daarna opnieuw af. De geschiedenis blijft dan een rechte lijn, zonder extra merge-commit. Een gewone git pull (met merge) mag ook; dan krijg je een merge-commit.

    git pull --rebase origin main
  3. Los eventuele conflicten op en push opnieuw

    Raken jouw wijzigingen en die van de server dezelfde regels, dan stopt de rebase met een conflict. Los dat op, markeer het bestand met git add en ga verder met git rebase --continue. Daarna lukt de push gewoon, zonder force.

    git add bestand.php
    git rebase --continue
    git push origin main
  4. Stel desgewenst rebase in als standaard

    Wil je dat git pull voortaan altijd rebaset in plaats van merget, dan zet je dat eenmalig in je instellingen. In recente Git-versies vraagt Git je ook om een keuze als je dit niet hebt ingesteld en de branches uiteenlopen.

    git config --global pull.rebase true
  5. Na amend of rebase: gebruik --force-with-lease, niet --force

    Heb je bewust je eigen, al gepushte commits herschreven (bijvoorbeeld op je eigen feature-branch), dan moet je de server overschrijven. Gebruik dan --force-with-lease. Die controleert eerst of de server nog staat waar jij hem voor het laatst zag; heeft iemand intussen iets gepusht, dan weigert hij alsnog. Een kale --force gooit het werk van anderen zonder waarschuwing weg.

    git push --force-with-lease origin feature/mijn-branch
  6. Beschermde branch? Werk via een eigen branch

    Weigert de server met ‘protected branch’, dan mag main alleen via een pull request of merge request veranderen. Zet je commits op een nieuwe branch, push die en open daar een pull request. Het is verstandig om de hoofdbranch zo te beschermen: dan kan niemand per ongeluk de geschiedenis overschrijven.

    git switch -c fix/mijn-wijziging
    git push -u origin fix/mijn-wijziging
  7. Werk je overschreven? Haal het terug via reflog

    Is er toch geforceerd en mis je commits, kijk dan in de reflog van de computer die ze het laatst had. Daar staan ook commits die niet meer aan een branch hangen. Zet er een nieuwe branch op en push die.

    git reflog
    git branch herstel 1a2b3c4
    git push origin herstel

Let op: Gebruik git push --force nooit op een gedeelde branch zoals main. Het overschrijft de commits van je collega’s op de server. Moet je echt forceren, doe het met --force-with-lease en alleen op je eigen branch.

Wanneer schakel je hulp in?

  • Er is geforceerd gepusht op een gedeelde branch en er ontbreekt werk.
  • Je website wordt automatisch uitgerold vanuit Git en je wilt de geschiedenis niet beschadigen.
  • Je moet beschermde branches, pull requests of rechten op GitHub of GitLab inrichten voor een team.
  • Na het bijwerken lopen de conflicten zo op dat je niet meer weet welke versie de juiste is.

Lukt het niet? Wij helpen

Kom je er met deze stappen niet uit, of wil je het liever niet zelf doen? We kijken online mee of komen langs. Hulp op afstand kost €20 per uur; komen we langs, dan is de prijs op aanvraag. Je weet vooraf waar je aan toe bent.

Aanvraag

Hulp aanvragen

Schrijf kort wat er misgaat en wat je al hebt geprobeerd. Kies of we bellen, online meekijken of langskomen.

Veelgestelde vragen

Vragen over dit probleem

Wat betekent ‘non-fast-forward’?

Dat jouw branch geen rechtstreekse voortzetting is van de branch op de server. Er staan daar commits die jij niet hebt, dus eerst bijwerken.

Wat is het verschil tussen ‘fetch first’ en ‘non-fast-forward’?

Bij ‘fetch first’ heeft je computer de nieuwe commits van de server nog niet opgehaald. Bij ‘non-fast-forward’ heb je ze wel, maar loopt je branch erachter of is hij afgeweken. In beide gevallen helpt git pull --rebase.

Mag ik git push --force gebruiken?

Alleen op een branch waar alleen jij aan werkt, en dan liever met --force-with-lease. Op een gedeelde branch overschrijf je anders het werk van anderen.

Ik heb per ongeluk geforceerd. Is het werk weg?

Meestal niet. Op de computer van degene die de commits had, staan ze nog in git reflog; daar kun je een branch van maken en die opnieuw pushen.