git push –force and how to deal with it

Har du någonsin befunnit dig i en situation där ett felaktigt git-kommando orsakat kaos i ditt projekts repo? Människor gör misstag, och ibland kan dessa misstag kosta timmar av ditt teams tid. I den här handledningen visar vi dig hur du snabbt kan återhämta dig från ett olyckligt git push --force.

Låt oss inte bli alltför självsäkra. Förr eller senare kommer detta att hända. När du arbetar med flera fjärrkontroller i samma git-arkiv kommer du så småningom att git push --force till master (eller en annan viktig gren som du aldrig ska röra dig med).

Det kan till exempel hända när du distribuerar med Deis eller Heroku som använder separata git-fjärrkontroller för att bygga och distribuera en applikation. Efter en lång arbetsdag är det otroligt lätt att exekvera git push --force istället för vanliga git push --force deis master.

Oj! På ett ögonblick har dina lagkamrater förlorat allt sitt senaste arbete. Dags att möta deras raseri.

Men som en utmärkt guide säger till oss: ”DON’T PANIC! Det som är bra är att du använder git, och det betyder att allt kan fixas.

Bästa scenariot: någon annan som arbetar med samma kod tog fram en nyare version av master precis innan du förstörde den. Då är allt du behöver göra att gå in i ditt teams chatt och be den personen att tvinga fram sina senaste ändringar.

Om du har tur kommer deras lokala arkiv att ha hela historiken av commits, ditt misstag kommer att skrivas över med ny kod och ingenting kommer att gå förlorat. Men vad händer om du inte har sådan tur? Läs vidare!

Fall 1: Du var den sista personen som pushade till master före misstaget

Goda nyheter! Du har allt du behöver för att ångra ditt misstag framför dina ögon. Stäng eller rensa bara inte terminalen. Gå först in i ditt teams chatt och bekänn dina synder. Be folk att inte pilla med repo:n under de närmaste minuterna medan du fixar saker och ting.

I utmatningen av kommandot git push --force i ditt skal letar du efter en rad som liknar den här:

 + deadbeef...f00f00ba master -> master (forced update)

Den första gruppen av symboler (som ser ut som ett SHA-prefix för en commit) är nyckeln till räddningen. deadbeef är din sista bra commit till master strax innan du orsakade skada.

Så allt du behöver är att… forcera push (bekämpa eld med eld!) denna commit tillbaka till master-grenen, ovanpå en dålig.

$ git push --force origin deadbeef:master

Grattis! Du har räddat dagen. Nu är det dags att lära sig av dina misstag.

Fall 2: master ändrades av någon annan innan du klantade dig

Så, precis innan du gjorde git push --force hade någon stängt ett gäng pull requests, och master ser nu inte alls ut som din lokala kopia. Du kan inte längre göra git push --force sha1:master eftersom du inte har några nyligen gjorda commits lokalt (och du kan inte få dem med git fetch eftersom de inte tillhör någon gren längre). Håll dig ändå lugn och be dina lagkamrater att hålla sig borta från fjärrkontrollen ett tag.

Vi kommer att dra nytta av att GitHub inte tar bort oåtkomliga commits omedelbart. Naturligtvis kan du inte heller hämta dem, men det finns en lösning.

Notera att det bara fungerar om du ”bevakar” repositoriet, så att allt som händer i det visas i ett flöde som visas på din GitHubs förstasida. Öppna detta flöde och leta efter något som liknar detta:

an hour agoUsername pushed to master at org/repo - deadbeef Implement foo - deadf00d Fix bar

Nu kan du:

  • Skapa en URL https://github.com/org/repo/tree/deadbeef, där deadbeef är en hash av den senaste bra överföringen till den skadade grenen;
  • Öppna växlaren för grenar/taggar i GitHubs webbgränssnitt;

GitHub branch/tag switcher

GitHub branch/tag switcher

  • Skapa ett namn för en ny tillfällig gren (e.g., master-before-force-push);
  • Klicka på ”Skapa gren”.

Nu kan du hämta alla saknade commits:

$ git fetchFrom github.com:org/repo * master-before-force-push -> origin/master-before-force-push

Ditt problem är nu reducerat till det som beskrivs i ett tidigare exempel:

$ git push --force origin origin/master-before-force-push:master

Om du fortfarande behöver ditt arbete i master, gör du bara en ny bas ovanpå den:

$ git rebase origin/master

Hur man undviker en sådan katastrof i framtiden

  1. GitHub och GitLab har en funktion som kallas ”protected branches”.” Markera master, develop, stable eller andra viktiga grenar som skyddade och ingen kommer att tillåtas forcera push till dem. Det är alltid möjligt att tillfälligt ”avskydda” en gren om du verkligen behöver skriva över historiken.

    Läs GitHub-dokumentationen för detaljer.

  2. Istället för alternativet --force, använd --force-with-lease. Det stoppar push-operationen om någon har pushat till samma gren medan du arbetade med den (och inte har dragit några ändringar).

    Se den här artikeln från Atlassian.

  3. Skapa alias för kommandon som använder git push --force för att förhindra destruktiva åtgärder av misstag:

    # ~/.gitconfig deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\""

    Läs ProGit-kapitlet om alias.

  4. Gör aldrig dina experiment i huvudgrenen av ett arkiv! git checkout -b experiments är din bästa vän.

Pro tips: git push har många alternativ. --force och --all fungerar särskilt bra tillsammans. Du kan använda den här kombinationen när du återvänder till projektet efter flera månaders inaktivitet. Ge det ett försök om du känner dig extra äventyrlig!

Leave a Reply