Git Pull Force - Hvordan overskrive lokale endringer med Git

Når du lærer å kode, vil du før eller senere også lære om versjonskontrollsystemer. Og mens det er mange konkurrerende verktøy i dette rommet, er en av dem de facto-standarden som brukes av nesten alle i bransjen. Det er så populært at det er selskaper som bruker navnet sitt i merkevaren. Vi snakker selvfølgelig om Git.

Mens Git er et kraftig verktøy, er kraften godt skjult. Det er noen viktige konsepter du må forstå for å bli virkelig dyktig med Git. Den gode nyheten er at når du først har lært dem, vil du nesten aldri komme i problemer du ikke kan unnslippe.

Den typiske arbeidsflyten

I en typisk Git-arbeidsflyt bruker du et lokalt depot, et eksternt arkiv og en eller flere grener. Repositories lagrer all informasjon om prosjektet, inkludert hele historien og alle grenene. En gren er i utgangspunktet en samling endringer som fører fra et tomt prosjekt til dagens tilstand.

Etter å ha klonet et depot, jobber du med din lokale kopi og introduserer nye endringer. Inntil du presser lokale endringer i det eksterne depotet, er alt arbeidet ditt bare tilgjengelig på maskinen din.

Når du er ferdig med en oppgave, er det på tide å synkronisere med det eksterne depotet. Du vil trekke fjernendringene for å holde tritt med prosjektets fremgang, og du vil presse de lokale endringene for å dele arbeidet ditt med andre.

Lokale endringer

Alt er bra når du og resten av teamet ditt jobber med helt separate filer. Uansett hva som skjer, vil du ikke tråkke på hverandres føtter.

Imidlertid er det tider når du og lagkameratene dine samtidig innfører endringer på samme sted. Og det er vanligvis der problemene begynner.

Har du noen gang henrettet git pullbare for å se de fryktede error: Your local changes to the following files would be overwritten by merge:? Før eller siden støter alle på det problemet.

Det som er mer forvirrende her er at du ikke vil slå sammen noe, bare dra, ikke sant? Egentlig er pull litt mer komplisert enn du kanskje hadde trodd.

Hvor nøyaktig fungerer Git Pull?

Trekk er ikke en eneste operasjon. Den består av å hente data fra den eksterne serveren og deretter slå sammen endringene med det lokale depotet. Disse to operasjonene kan utføres manuelt hvis du vil:

git fetch git merge origin/$CURRENT_BRANCH

Den origin/$CURRENT_BRANCHdelen betyr at:

  • Git vil slå sammen endringene fra navnet på det eksterne lagringsstedet origin(det du klonet fra)
  • som er lagt til $CURRENT_BRANCH
  • som ikke allerede er til stede i din lokale utsjekkede filial

Siden Git bare utfører sammenslåinger når det ikke er noen uforpliktede endringer, kan hver gang du løper git pullmed uforpliktede endringer få deg i trøbbel. Heldigvis er det måter å komme ut av trøbbel i ett stykke!

Vi er familie

Ulike tilnærminger

Når du ikke har forpliktet lokale endringer og fremdeles vil hente en ny versjon fra den eksterne serveren, faller bruken din vanligvis inn i et av følgende scenarier. Enten:

  • du bryr deg ikke om lokale endringer og vil overskrive dem,
  • du bryr deg veldig om endringene og vil bruke dem etter endringene på fjernkontrollen,
  • du vil laste ned fjernendringene, men ikke bruke dem ennå

Hver av tilnærmingene krever en annen løsning.

Du bryr deg ikke om lokale endringer

I dette tilfellet vil du bare slette alle uforpliktede lokale endringer. Kanskje du endret en fil for å eksperimentere, men du trenger ikke lenger endringen. Alt du bryr deg om er å være oppdatert med oppstrøms.

Dette betyr at du legger til ett trinn til mellom å hente fjernendringene og slå dem sammen. Dette trinnet vil tilbakestille grenen til sin umodifiserte tilstand, slik at den git mergekan fungere.

git fetch git reset --hard HEAD git merge origin/$CURRENT_BRANCH

Hvis du ikke ønsker å skrive grenen navn hver gang du kjører denne kommandoen, har Git en hyggelig snarvei som peker til oppstrøms gren: @{u}. En oppstrøms gren er grenen i det eksterne arkivet som du skyver til og henter fra.

Slik ser kommandoer ovenfor ut med snarveien:

git fetch git reset --hard HEAD git merge '@{u}'

Vi siterer snarveien i eksemplet for å forhindre at skallet tolker det.

Du bryr deg veldig om lokale endringer

Når dine uforpliktede endringer er viktige for deg, er det to alternativer. Du kan begå dem og deretter utføre git pull, eller du kan stash dem.

Stashing betyr å legge endringene bort et øyeblikk for å bringe dem tilbake senere. For å være mer presis, git stashoppretter en forpliktelse som ikke er synlig på din nåværende gren, men som fremdeles er tilgjengelig for Git.

For å få tilbake endringene som er lagret i siste stash, bruker du git stash popkommandoen. Etter å ha brukt de stashede endringene, fjerner denne kommandoen også stash-forpliktelsen ettersom den ikke lenger er nødvendig.

Arbeidsflyten kan da se slik ut:

git fetch git stash git merge '@{u}' git stash pop

Som standard blir endringene fra stash iscenesatt. Hvis du vil fjerne scenen, bruk kommandoen git restore --staged(hvis du bruker Git nyere enn 2.25.0).

Du vil bare laste ned de eksterne endringene

Det siste scenariet er litt annerledes enn de forrige. La oss si at du er midt i en veldig rotete refactoring. Verken å miste endringene eller stash dem er et alternativ. Likevel vil du fortsatt ha fjernendringene tilgjengelige for å kjøre git diffmot dem.

Som du sikkert har funnet ut, krever ikke nedlasting av fjernendringene git pulli det hele tatt! git fetcher akkurat nok.

One thing to note is that by default, git fetch will only bring you changes from the current branch. To get all the changes from all the branches, use git fetch --all. And if you'd like to clean up some of the branches that no longer exist in the remote repository, git fetch --all --prune will do the cleaning up!

Some Automation

Have you heard of Git Config? It's a file where Git stores all of the user-configured settings. It resides in your home directory: either as ~/.gitconfig or ~/.config/git/config. You can edit it to add some custom aliases that will be understood as Git commands.

For example, to have a shortcut equivalent to git diff --cached (that shows the difference between the current branch and the staged files), you'd add the following section:

[alias] dc = diff --cached

After that, you can run git dc whenever you wish to review the changes. Going this way, we can set up a few aliases related to the previous use cases.

[alias] pull_force = !"git fetch --all; git reset --hard HEAD; git merge @{u}" pf = pull_force pull_stash = !"git fetch --all; git stash; git merge @{u}; git stash pop"

This way, running git pull_force will overwrite the local changes, while git pull_stash will preserve them.

The Other Git Pull Force

Curious minds may have already discovered that there is such a thing as git pull --force. However, this is a very different beast to what's presented in this article.

It may sound like something that would help us overwrite local changes. Instead, it lets us fetch the changes from one remote branch to a different local branch. git pull --force only modifies the behavior of the fetching part. It is therefore equivalent to git fetch --force.

Like git push, git fetch allows us to specify which local and remote branch do we want to operate on. git fetch origin/feature-1:my-feature will mean that the changes in the feature-1 branch from the remote repository will end up visible on the local branch my-feature. When such an operation modifies the existing history, it is not permitted by Git without an explicit --force parameter.

Just like git push --force allows overwriting remote branches, git fetch --force (or git pull --force) allows overwriting local branches. It is always used with source and destination branches mentioned as parameters. An alternative approach to overwriting local changes using git --pull force could be git pull --force "@{u}:HEAD".

Conclusion

Verden til Git er enorm. Denne artikkelen dekket bare en av fasettene ved vedlikehold av depoter: å integrere eksterne endringer i et lokalt depot. Selv dette hverdagsscenariet krevde at vi skulle se litt nærmere på dette versjonskontrollverktøyets interne mekanismer.

Å lære faktiske brukstilfeller hjelper deg med å forstå hvordan Git fungerer under panseret. Dette vil igjen få deg til å føle deg bemyndiget når du får problemer. Det gjør vi alle innimellom.