Do háje, Git!?!

Git je složitý: něco rozbít je jednoduché, ale přijít na to, jak z toho ven někdy téměř nemožné. Hledat něco v dokumentaci Gitu jde těžko pokud tedy už nevíš název té věci, kterou hledáš.

Tady jsou některé situace, kdo kterých jsem se dostal a také řešení, která vedla k nápravě ve srozumitelné formě.

Do háje, něco jsem hodně pokazil. Nemá náhodou git nějaký stroj času?!?

git reflog
# uvidis seznam vsech veci, ktere jsi
# delal v gitu ve vsech vetvich
# kazda z nich ma index HEAD@{index}
# najdes tu, ktera fungovala nez jsi to vsechno rozbil 
git reset HEAD@{index}
# magicky stroj casu

Díky tomu můžeš dostat zpět věci, které jsi omylem smazal, nebo prostě smazat věci kterými sis si rozbil repozitář, nebo opravit stav po špatném mergování, nebo prostě cestovat v čase zpět do bodu, kdy ještě věci fungovaly. Já používám reflog HÓÓÓDNĚ. Klouboček všem těm mnoha mnoha mnoha mnoha lidem, kteří navrhli přidat sem tento tip!

Do háje, commitnul jsem a pak jsem si hned uvědomil, že ještě potřebuji udělat jednu malou změnu!

# udelej potrebnou zmenu
git add . # nebo pridej jednotlive soubory
git commit --amend --no-edit
# nyni tvuj posledni commit obsahuje i tuto zmenu!
# VAROVANI: nikdy nepouzivej na sdilene/verejne commity

Toto se mi většinou stane, když commitnu, a potom spustim testy/lintery... a jéje, nedal jsem mezeru za rovnítko. Toto by šlo vyřešit také přidáním změny v novém commitu a následně spuštěním rebase -i abych commity spojil (squash) dohromady. Ale amend je milionkrát rychlejší na provedení.

Varování: Nikdy bys neměl měnit commity, které jsou již nahrané do veřejné/sdílené větve! Měň jen commity, které jsou jen v tvé lokální kopii repozitáře, jinak hrozí nepřijemnosti.

Do háje, potřebuji změnit popisek posledního commitu!

git commit --amend
# postupuj podle pokynu ke zmene popisku posledniho commitu

Ach, otravné konvence pro popisky commitů...

Do háje, omylem jsem udělal do masteru commit, který ale měl být v zcela nové větvi!

# vytvor novou vetev ze soucasneho stavu masteru
git branch nazev-nejake-nove-vetve
# odstran posledni commit z master vetve
git reset HEAD~ --hard
git checkout nazev-nejake-nove-vetve
# tvuj commit je nyni v teto vetvi :)

Poznámka: toto nezafunguje, pokud jsi již provedl push tohoto commitu do veřejné/sdílené větve. Pokud jsi již zkoušel jiné věci, tak možná budeš potřebovat git reset HEAD@{pocet-commitu-zpet} namísto HEAD~. To zamrzí. Mnoho mnoho mnoho lidí navrhovalo super kratší postup, o kterém jsem nevěděl. Díky vám všem!

Do háje, omylem jsem udělal commit do špatné větve!

# vrat zpet poslední commit, ale zmeny v souborech nech
git reset HEAD~ --soft
git stash
# presun se do te spravne vetve
git checkout nazev-te-spravne-vetve
git stash pop
git add . # nebo pridej jednotlive soubory
git commit -m "vas popisek sem"
# nyni jsou tvoje zmeny ve spravne vetvi

Hodně lidí navrhovalo také možnost použití cherry-pick pro tuto situaci. Prostě si vyber, která z možností ti dává největší smysl!

git checkout nazev-te-spravne-vetve
# prekopirujte posledni commit z masteru
git cherry-pick master
# smazte jej z masteru
git checkout master
git reset HEAD~ --hard

Do háje, spustil jsem diff, ale nic se nestalo?!

Pokud víš, že jsi udělal změny, ale diff je prázdný, pak sis pravěpodobně přidal(add) soubory do staging stavu a proto budeš potřebovat použít speciální příznak.

git diff --staged

¯\_(ツ)_/¯ - já vím, že to je validní chování a ne chyba, ale když se vám to stane poprvé, tak je to záhada!

Do háje, potřebuju vrátit zpět zpět 5 minut starý commit!

# najdi commit, ktery potrebujes vratit zpet
git log
# pouzij sipky nahoru a dolu k posunovani v historii
# az najdes svuj commit, uloz si jeho hash
git revert [ulozeny hash]
# git vytvori novy commit, ktery puvodni commit vrati zpet
# postupuj podle pokynu ke zmene popisku noveho commitu
# nebo proste jenom uloz a proved commit

Ukázalo se, že abys vzal změny zpět, nemusíš hledat a překopírovávat obsah staré verze souboru do současné verze. Pokud jsi udělali v commitu chybu, můžeš ji vzít zpět pomoci příkazu revert.

Můžeš také třeba vzít zpět i změnu jen v jednom souboru a ne všech v commitu! Ale jak to tak s Gitem bývá, toto by už znamenalo použít úplně jiné příkazy...

Do háje, potřebuju vzít zpět změny na jednom souboru!

# najdi hash commitu pred zmenou
git log
# pouzij sipky nahoru a dolu k posunovani v historii
# az najdes svuj commit, uloz si jeho hash
git checkout [ulozeny hash] -- cesta/k/souboru.pripona
# puvodni verze souboru bude v tvych zmenach
git commit -m "Jéé, není potřeba překopírovat původní obsah souboru, abych vzal změnu zpět"

Přijít na toto byla VELKÁ POMOC. VELKÁ POMOC. V-E-L-K-Á P-O-M-O-C. Ale upřímně, na které planetě dává smysl použít checkout -- jako nejlepší způsob jak vrátit změny v souboru? :hrozit-rukou-na-linuse-torvaldse:

Zapomeňme na to, vzdávám to.

cd ..
sudo rm -r zatracene-git-repo
git clone https://nejaka.github.url/zatracene-git-repo.git
cd zatracene-git-repo

Díky Ericu V. za tento tip. Všechny stížnosti na použití sudo prosím směřovat na něj.

Ale opravdu, pokud je tvoje větev tak strašně rozbitá, že potřebuješ resetovat její stav 1:1 vůči vzdálenému "schválenému" repozitáři potom vyzkoušej tohle, ale měj na paměti, že tyto změny jsou nevratné!

# ziskej nejnovejsi stav vzdaleneho origin-u
git fetch origin
git checkout master
git reset --hard origin/master
# smaz nesledovane soubory a adresare
git clean -d --force
# opakuj checkout/reset/clean pro kazdou rozbitou vetev

Varování: Tato stránka nemá být vyčerpávající dokumentací. A ano, vždycky jsou i jiné cesty, jak konkrétní problémy vyřešit jinými (teoreticky čistšími) způsoby, ale toto jsou moje postupy, ke kterým jsem dospěl po mnoha chybách, nadávání a bušení pěstí do stolu. Nyní je s Vámi sdílím za pomocí zdravé dávky nadsázky. Berte nebo nechte být!

Díky moc všem, kteří se dobrovolně zapojili do překladu této stránky do nových jazyků. Dobře vy! Moritz Stückler (de) · Daniil Golubev (ru) · Łukasz Wójcik (pl) · fedemcmac (it) · Michel (fr) · Andriy Sultanov (ua) · Meiko Hori (ja) · Alex Tzimas (gr) · Martijn ten Heuvel (nl) · Elad Leev (he) · Franco Fantini (es) · Catalina Focsa (ro) · Davi Alexandre (pt_BR) · Nemanja Vasić (sr) · Tao Jiayuan (zh) · Eduard Tomek (cs) · Ricky Gultom (id) · Khaja Md Sher E Alam (bn) · Rahul Dahal (ne) . Dále pomohli Iain Murray · Frank Taillandier · David Fyffe · Lucas Larson

Pokud byste chtěli přidat překlad také do svého jazyka, vytvořte PR na GitHub