Giti tõmbejõud - kuidas kohalikke muudatusi Gitiga üle kirjutada

Kui õpite kodeerima, saate varem või hiljem teada ka versioonihaldussüsteemidest. Ja kuigi selles ruumis on palju konkureerivaid tööriistu, on üks neist de facto standard, mida kasutavad peaaegu kõik selles valdkonnas. See on nii populaarne, et on ettevõtteid, kes kasutavad selle nime oma brändingus. Me räägime muidugi Gitist.

Kuigi Git on võimas tööriist, on selle jõud hästi varjatud. Seal on mõned olulised mõisted, mida peate mõistma, et Gitiga tõeliselt osata. Hea uudis on see, et kui olete need ära õppinud, satub vaevalt kunagi hätta, kust ei pääse.

Tüüpiline töövoog

Tüüpilises Giti töövoos kasutate kohalikku hoidlat, kaughoidlat ja ühte või mitut haru. Hoidlad salvestavad kogu projekti kohta käiva teabe, sealhulgas kogu selle ajaloo ja kõik harud. Filiaal on põhimõtteliselt tühjade projektide hetkeseisundisse viivate muudatuste kogu.

Pärast hoidla kloonimist töötate kohaliku koopia kallal ja tutvustate uusi muudatusi. Kuni kaughoidlas pole kohalikke muudatusi, on kogu teie töö saadaval ainult teie arvutis.

Kui olete ülesande lõpetanud, on aeg sünkroonida kaughoidlaga. Saate tõmmata kaugemuudatused, et olla kursis projekti edenemisega, ja soovite lükata kohalikke muudatusi, et jagada oma tööd teistega.

Kohalikud muutused

Kõik on hästi, kui teie ja teie ülejäänud meeskond töötavad täiesti eraldi failide kallal. Mis ka ei juhtuks, te ei astu üksteise jalgadele.

Siiski on olukordi, kus teie ja teie meeskonnakaaslased tutvustavad muudatusi samaaegselt. Ja tavaliselt saavadki probleemid alguse.

Kas olete kunagi hukanud git pullainult selleks, et näha kardetavat error: Your local changes to the following files would be overwritten by merge:? Varem või hiljem satuvad kõik selle probleemiga kokku.

Segasem on siin see, et te ei soovi midagi ühendada, lihtsalt tõmmake, eks? Tegelikult on tõmbamine natuke keerulisem, kui arvata võis.

Kui täpselt Git Pull töötab?

Tõmbamine pole üks operatsioon. See koosneb andmete hankimisest kaugserverist ja seejärel muudatuste ühendamisest kohaliku hoidlaga. Neid kahte toimingut saab soovi korral teha käsitsi:

git fetch git merge origin/$CURRENT_BRANCH

See origin/$CURRENT_BRANCHosa tähendab, et:

  • Git ühendab muudatused nimega kaughoidlast origin(sellest, kust kloonisite)
  • mis on lisatud $CURRENT_BRANCH
  • mida teie kohalikus registreeritud filiaalis juba pole

Kuna Git teostab liitumisi ainult siis, kui tegemata muudatusi pole, võib iga kord, kui käivitate git pullsidumata muudatustega, teid hätta sattuda. Õnneks on viise, kuidas hätta saada ühes tükis!

Me oleme perekond

Erinevad lähenemisviisid

Kui teil on kohalikud muudatused tegemata ja soovite siiski kaugserverist uue versiooni tõmmata, langeb teie kasutusjuht tavaliselt ühte järgmistest stsenaariumitest. Mõlemad:

  • sa ei hooli kohalikest muudatustest ja tahad need üle kirjutada,
  • sa hoolid muudatustest väga ja sooviksid neid pärast kaugemuudatusi rakendada,
  • soovite kaugmodifikatsioonid alla laadida, kuid neid veel ei rakendata

Iga lähenemine nõuab erinevat lahendust.

Sa ei hooli kohalikest muudatustest

Sellisel juhul soovite lihtsalt loobuda kõikidest kohalikest muudatustest. Võib-olla muutsite katsetamiseks faili, kuid te ei vaja enam muudatusi. Kõik, mis teid huvitab, on ülesvooluga kursis olemine.

See tähendab, et lisate veel ühe sammu kaugmuudatuste toomise ja nende ühendamise vahele. See samm lähtestab haru muutmata olekusse, võimaldades git mergenii töötada.

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

Kui te ei soovi kirjutage harunime iga kord, kui käivitada käsk, Git on kena otsetee osutades ülesvoolu filiaal: @{u}. Ülesvoolu haru on kaughoidla haru, kuhu tõukate ja kust teete.

This is how the above commands would look like with the shortcut:

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

We are quoting the shortcut in the example to prevent the shell from interpreting it.

You Very Much Care About the Local Changes

When your uncommitted changes are significant to you, there are two options. You can commit them and then perform git pull, or you can stash them.

Stashing means putting the changes away for a moment to bring them back later. To be more precise, git stash creates a commit that is not visible on your current branch, but is still accessible by Git.

To bring back the changes saved in the last stash, you use the git stash pop command. After successfully applying the stashed changes, this command also removes the stash commit as it is no longer needed.

The workflow could then look like this:

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

By default, the changes from the stash will become staged. If you want to unstage them, use the command git restore --staged (if using Git newer than 2.25.0).

You Just Want to Download the Remote Changes

The last scenario is a little different from the previous ones. Let's say that you are in the middle of a very messy refactoring. Neither losing the changes nor stashing them is an option. Yet, you still want to have the remote changes available to run git diff against them.

As you have probably figured out, downloading the remote changes does not require git pull at all! git fetch is just enough.

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

Giti maailm on tohutu. See artikkel käsitles ainult ühte hoidla hoolduse tahke: kaugmuudatuste kaasamine kohalikku hoidlasse. Isegi see igapäevane stsenaarium nõudis, et vaataksime selle versioonihalduse tööriista sisemisi mehhanisme veidi põhjalikumalt.

Tegelike kasutusjuhtumite õppimine aitab teil paremini mõista, kuidas Git kapoti all töötab. See omakorda annab teile võimaluse tunda end alati, kui satute hätta. Me kõik teeme seda aeg-ajalt.