Git
Chapters ▾ 2nd Edition

2.4 Základy práce se systémem Git - Návrat do předchozího stavu

Návrat do předchozího stavu

Kdykoli se může stát, že něco chcete vrátit do původního stavu. Proto se podíváme na pár základních nástrojů pro vracení změn, které jste udělali. Ale buďte opatrní, protože ne vždy můžete návrat zpět vrátit zase vpřed. Je to jedna z mála oblastí, kdy při neuváženém postupu v Gitu riskujete, že přijdete o část své práce.

Jeden z běžných důvodů pro vracení úprav nastane, když zapíšete revizi příliš brzy a například jste zapomněli přidat některé soubory, nebo jste něco popletli ve zprávě k revizi. Chcete-li poslední revizi vytvořit znovu, můžete spustit příkaz commit s volbou --amend:

$ git commit --amend

Tento příkaz vezme vaši oblast připravených změn a použije ji k vytvoření revize. Pokud jste od poslední revize neprovedli žádné změny (například spustíte tento příkaz bezprostředně po předchozím zápisu), bude snímek vypadat úplně stejně a jediné, co změníte, je zpráva k revizi.

Spustí se stejný editor pro editaci zpráv k revizím, ale tentokrát už obsahuje zprávu z vaší předchozí revize. Zprávu můžete editovat stejným způsobem jako vždy, ale předchozí revize se přepíše.

Pokud například zapíšete revizi a potom si uvědomíte, že jste zapomněli připravit k zapsání změny v souboru, který jste chtěli do této revize přidat, můžete provést následující:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

Výsledkem je jediná revize — druhý příkaz commit nahradí výsledky prvního.

Odstranění souboru z oblasti připravených změn

Následující dvě části popisují, jak se poprat s oblastí připravených změn a se změnami v pracovním adresáři. Dobré je, že příkaz, jímž se zjišťuje stav těchto dvou oblastí, zároveň připomíná, jak v nich nežádoucí změny zrušit. Řekněme například, že jste změnili dva soubory a chcete je zapsat jako dvě oddělené změny, jenže omylem jste zadali příkaz git add * a oba soubory jste tím připravili k zapsání. Jak lze tyto dva soubory vrátit z oblasti připravených změn? Připomene vám to příkaz git status:

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

Přímo pod textem „Changes to be committed“ („Změny k zapsání“) se říká: „pro odstranění z oblasti připravených změn použijte příkaz git reset HEAD <soubor>...“ Budeme se tedy řídit touto radou a z oblasti připravených změn odstraníme soubor CONTRIBUTING.md:

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Příkaz je sice trochu zvláštní, ale funguje. Soubor CONTRIBUTING.md má stav „změněn“, ale už se nenachází v oblasti připravených změn.

Note

Příkaz git reset sice může být nebezpečný, pokud jej voláte s volbou --hard, ale v našem případě zůstane soubor v pracovním adresáři nedotčen. Volání git reset bez dalších parametrů není nebezpečné — dotkne se jen oblasti připravených změn.

Prozatím je tato magická formule vše, co o příkazu git reset potřebujete vědět. Podrobněji se budeme tím, co příkaz reset dělá a jak jej využít pro opravdu zajímavé věci, v podkapitole Reset Demystified.

Rušení změn ve změněných souborech

A co když zjistíte, že nechcete zachovat změny, které jste provedli v souboru CONTRIBUTING.md? Jak je můžete snadno zrušit a vrátit soubor zpět do podoby při posledním zápisu revize (nebo při prvním klonování nebo při jakékoliv činnosti, kterou jste soubor dostali do pracovního adresáře)? Příkaz git status vám naštěstí i tentokrát řekne, co dělat. U posledního příkladu vypadá oblast připravených změn takto:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Git přímo říká, jak se dají vámi provedené změny zrušit. Uděláme, co nám radí:

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Jak vidíte, změny byly vráceny zpět.

Important

Je důležité, abyste porozuměli tomu, že příkaz git checkout -- <soubor> je nebezpečný. Veškeré změny, které jste v souboru provedli, jsou ztraceny — Git je právě přepsal jiným souborem. Nikdy tento příkaz nepoužívejte, pokud si nejste zcela jisti, že už daný soubor nebudete potřebovat.

Pokud byste chtěli provedené změny souboru uchovat, ale pro tento okamžik je přesto chcete odklidit z cesty, podíváme se později na odkládání (stashing) a v kapitole Větve v systému Git na větvení. Tyto postupy bývají většinou vhodnější.

Zapamatujte si, že vše, co je v Gitu zapsáno, lze téměř vždy obnovit. Obnovit lze dokonce i objekty revizí na odstraněných větvích nebo objekty revizí, které byly přepsány příkazem commit --amend (obnovování dat se věnuje kapitola Data Recovery). Pokud však dojde ke ztrátě dat, která dosud nebyla součástí žádné revize, už je asi nikdy neuvidíte.