Angre i filene: git restore
Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.
Etter leksjonen kan du
- forkaste en ustaget endring med
git restore, og forklare hvorfor Git ikke kan gi tilbake en redigering den aldri lagret anvende - ta en fil ut av staging med
git restore --stageduten å miste endringen i filen anvende - gjenopprette en eldre versjon av en fil med
git restore --source, uten å endre historikken anvende - velge restore-variant ut fra hvor versjonen du vil ha ligger, og gjenkjenne når jobben gjelder en commit og krever reset eller revert analysere
Forstå: Tre steder, tre retninger
Husk de tre stedene en fil kan ligge: arbeidsmappen, staging-området og siste commit. Til nå har du flyttet versjoner mot høyre med add og commit. I dag flytter vi dem tilbake mot venstre.
Se for deg dette. Du la til en linje om søndager og staget den. Etterpå skrev du noe rot i den samme filen. Nå finnes det tre ulike versjoner, én på hvert sted.
git restore README.md kopierer versjonen fra staging-området inn i arbeidsmappen. Kortet flyr ett steg mot venstre, og rotet er borte. Merk: rotet var aldri lagret i Git, så denne handlingen kan ikke angres.
git restore --staged README.md virker ett steg lenger til høyre. Den kopierer versjonen fra siste commit inn i staging-området. Arbeidsfilen blir ikke rørt, så søndagslinjen er fortsatt der, bare ikke staget lenger.
Du kan også gjenopprette en fil fra en eldre commit. git restore --source=HEAD~1 README.md kopierer versjonen fra commiten før den siste. Uten flere valg havner den bare i arbeidsmappen.
I alle tre tilfellene står main på samme commit som før. Restore endrer filer og staging, aldri historikken. Skal en commit angres, trenger du reset eller revert.
Se demo: Rydd opp i README.md
Vi starter med to commits. Først legger vi til en nyttig linje om søndager og stager den. Se at kortet flytter seg til staging.
$ echo "Closed Sundays" >> README.md && git add README.md
Så kommer et uhell: noe rot havner i den samme filen. Nå er arbeidsfilen, staging og siste commit tre forskjellige versjoner.
$ echo "asdf qwerty" >> README.md
Før du forkaster noe, ser du på hva du kaster. git diff viser bare det som ikke er staget. Her er det kun rotet.
$ git diff
Nå kjører vi git restore README.md. Se arbeidskortet: rotet forsvinner, og søndagslinjen blir.
$ git restore README.md
Du ombestemmer deg: søndagslinjen skal ikke med i neste commit ennå. git restore --staged kopierer siste commit inn i staging. Kortet i staging bytter innhold, men arbeidsfilen beholder linjen.
$ git restore --staged README.md
Nå vil sjefen ha README uten åpningstider til de er bestemt. Vi gjenoppretter filen slik den var én commit tilbake. Merk at dette også overskriver søndagslinjen i arbeidsfilen, fordi restore uten --staged alltid skriver over arbeidsfilen.
$ git restore --source=HEAD~1 README.md
Til slutt sjekker vi status. Ingen commit ble laget eller fjernet, og main står der den sto. Men hva sier status om README.md?
$ git status --short
Oppgaver
- Se nøyaktig hvilke ustagede endringer du er i ferd med å forkaste.
- Bli kvitt rotet, men behold den stagede søndagslinjen.
- Ta README.md ut av staging, men behold søndagslinjen i filen.
- Gjør README.md i arbeidsmappen lik versjonen fra én commit tilbake.
Øv: Overfør: tre filer, tre problemer
Et repository der litt av hvert har gått galt. Bruk git status og git diff for å se tilstanden før du angrer noe.
Oppgaver
- Både README.md og todo.txt er staget. Bare README.md skal med i neste commit. Behold endringen i todo.txt i filen.
- contact.txt ble slettet ved et uhell. Få den tilbake nøyaktig slik den var.
- Den nyeste commiten la en dårlig idé inn i notes.txt. Uten å endre historikken: gjør notes.txt i arbeidsmappen lik versjonen fra før den commiten.
Sjekk deg selv: Hent det fram igjen
Du kjører git restore --staged app.txt. Hva skjer med endringen i arbeidsfilen?
- Den slettes
- Den blir liggende i filen, men er ikke lenger staget
- Den blir committet
Du har en redigering i notes.txt som aldri ble staget eller committet, og kjører git restore notes.txt. Kan Git gi deg redigeringen tilbake?
- Ja, med
git reflog - Nei, Git lagret aldri den versjonen
- Ja, Git tar vare på hver versjon av en sporet fil
git status --short viser M config.txt: en staget endring, og ingenting ustaget. Du vil ha config.txt tilbake slik den er i siste commit, både i staging og i filen. Hva gjør du?
git restore config.txtgit restore --staged config.txt, og sågit restore config.txtgit revert HEAD
Repetisjon fra «Tre områder»: git status --short viser MM README.md. Hva betyr de to M-ene?
- README.md er endret i to commits
- Filen har en staget endring, og i tillegg en ustaget endring i arbeidsmappen
- Filen har en konflikt som må løses
Vanlige misforståelser
- «
git restore --stagedsletter endringen min.» Den setter bare staging-området tilbake til siste commit. Endringen ligger fortsatt i arbeidsfilen. - «Git kan alltid finne igjen det jeg forkaster.» Git kan bare gi tilbake versjoner den har lagret, altså staget eller committet. En redigering som aldri ble lagret, er borte etter
git restore. - «Restore kan angre en commit.» Restore flytter aldri en branch. Commits blir liggende akkurat der de er.
Les mer
Hva restore leser, og hva den skriver
git restore kopierer en versjon av én eller flere filer fra en kilde til et mål. Den flytter aldri HEAD eller en branch, så historikken blir nøyaktig som før. Valgene bestemmer bare kilde og mål:
| Kommando | Leser fra | Skriver til |
|---|---|---|
git restore app.txt |
staging-området | arbeidsmappen |
git restore --staged app.txt |
HEAD |
staging-området |
git restore --staged --worktree app.txt |
HEAD |
staging-området og arbeidsmappen |
git restore --source=HEAD~2 app.txt |
commiten HEAD~2 |
arbeidsmappen |
git restore --source=HEAD~2 --staged --worktree app.txt |
commiten HEAD~2 |
staging-området og arbeidsmappen |
To regler forklarer tabellen. Uten --staged er målet arbeidsmappen. Uten --source er kilden HEAD så snart --staged er med, og ellers staging-området, også kalt indeksen. Stien kan være én fil, en mappe eller . for alt under mappen du står i, så git restore . kaster alle ustagede endringer på én gang.
Det restore skriver til arbeidsmappen, overskriver filen uten å spørre. En endring som aldri ble staget eller committet, ble aldri lagret i Git, så ingen Git-kommando kan gi den tilbake. Se først med
git diff, og brukgit stashhvis du er usikker.
Forkast bare noen av endringene: git restore -p
-p (patch) viser hver bit av endringen (hunk) og spør før den forkaster den. Det er nyttig når en fil har en god rettelse og noen feilsøkingslinjer:
$ git restore -p README.md
@@ -1,2 +1,3 @@
Welcome
-Open 9-15
+Open 9-16
+Closed Sundays
(1/1) Discard this hunk from worktree [y,n,q,a,d,e,p,P,?]?
Svar y for å forkaste biten, n for å beholde den, q for å stoppe. s deler en stor bit i mindre når det går. git restore -p --staged README.md gjør det samme for stagede biter, og git add -p er speilbildet i motsatt retning.
Eldre skrivemåter du vil møte
git restore kom i Git 2.23 (2019). Før det gjorde git checkout og git reset de samme jobbene, og mange veiledninger og kolleger bruker dem fortsatt:
| Eldre kommando | Det samme som |
|---|---|
git checkout -- README.md |
git restore README.md |
git checkout HEAD~1 -- README.md |
git restore --source=HEAD~1 --staged --worktree README.md |
git reset README.md |
git restore --staged README.md |
Legg merke til raden i midten: checkout med en commit skriver både staging-området og arbeidsmappen, så den gamle versjonen er allerede staget etterpå. Bare --source rører kun arbeidsmappen. -- betyr «alt etter dette er filnavn», og det betyr noe når en fil og en branch har samme navn. git checkout bytter også branch, og derfor ble den delt i git switch og git restore.
Restore rører ikke usporede filer
Restore kjenner bare filer Git sporer. Spør du om en ny fil, feiler den:
$ git restore scratch.txt
error: pathspec 'scratch.txt' did not match any file(s) known to git
Usporede filer sletter du selv, eller med git clean. Kjør alltid git clean -n først: den lister bare hva som ville blitt slettet. Den ekte kjøringen krever -f, og det er nettopp den typen valg du bør skrive sakte.
Slutt å spore en fil uten å slette den: git rm --cached
Noen ganger er feilen at filen spores i det hele tatt, for eksempel en lokal .env med innstillinger. git rm --cached fjerner filen fra staging-området, så neste commit ikke lenger inneholder den, men lar kopien din ligge på disken:
$ git rm --cached .env
rm '.env'
$ git status --short
D .env
?? .env
Filen er staget som slettet og vises samtidig som usporet. Legg den i .gitignore og commit begge endringene. Eldre commits inneholder fortsatt filen. Hvis den inneholdt et passord eller en API-nøkkel, må du bytte hemmeligheten: å slutte å spore en fil skjuler ingenting som allerede er committet eller pushet.
Restore, reset eller revert?
Restore retter filer og staging. Reset flytter din egen branch. Revert legger til en ny commit som opphever en gammel. Tabellen i leksjonen «Revert» viser hvilket verktøy som passer når.
Offisiell dokumentasjon
- git-restore
- git-rm, se
--cached - git-clean
- Pro Git: Undoing Things
Per-Arne's Git Good!