Git - fix your history
Published on: 2020-08-31

1. Změna posledního commitu
S příkazem commit můžeme použít tzv. flags, které upravují chování tohoto příkazu. Jedním z takových flags je --amend. Pomocí tohoto flags měníme poslední commit.
Pomocí přikzu $ git commit --amend můžeme:
1. kombinovat změny, které máme v tuto chvíli ve staged fázi s posledním commitem
2. změnit poslední commit message, v které jsme udělali chybu nebo překlep. Ovšem tato změna změní uložení commitu a v historii ji budeme vidět s hvězdičkou (*). Tedy vytvoří se nový commit se stejnými informacemi, ale jinou zprávou a navíc bude obsahovat hvězdičku.
1. Přidat soubory ve staged fázi do posledního commitu
Představme si následující sled událostí:
Editujeme soubory hello.py a main.py. Po ukončení změn přidáme do gitu pouze main.py a provedeme commit. V příkazové řádce by úkony vapadly nějak takto:
$ git add main.py
$ git commit
V tuto chvíli si autor uvědomí, že zapomněl přidat do gitu také soubor hello.py, který chtěl mít ve společném commitu také se souborem main.py, který už je ale v tuto chvíli commitnutý. Tento problém se při vývoji objevuje poměrně čast a git si s touto situací umí hravě poradit.
Postup opravy může vypadat takto:
$ git add hello.py
$ git commit --amend --no-edit
Použitý flag --no-edit nám zajistí, že se zapomenutý soubor přidá do posledního commitu, ale commit message se nezmění. Tedy flag --no-edit = chceme přidat nové změny do posledního commitu bez úpravy commit message.
2. Změna zprávy v posledním commitu
Pro změnu poslední commit message použijeme tento příkaz:
$ git commit --amend
Tímto příkazem se nám objeví námi defaultně nastavený editor textu pro git a v něm poslední zpráva tu můžeme libovolně upravit a následně změny potvrdit, jak jsme zvyklý u běžných commitů.
Jednořádková změna commit message se provádí pomocí príkazu:
$ git commit --amend -m "your new or updated commit message"
Když přídáme do příkazu options -m můžeme změnit ři přepsat commit message přímo v příkazové řádce aniž bychom museli otevírat textový editora celý proces se takto výrazně zrychlí.
Upozornění: Příkaz amend nepoužívejte pokud jste změny už poslali do public prostoru třeba na GitHub. Jelikož --amend udělá nový commit, tak bude problém jej pushnout do stejné větve na remote. Jak jsme si řekli --amend udělá nový commit na větvi a ten starý z ní zmizí, při pushnutí této změny dojde ke konfliktu.
2. Změna jednoho, libovolně starého commitu
Změna se provádí pomocí příkazu git rebase. Tento příkaz je poněkud složitější a podíváme se tedy na něj v kapitole Git rebase trochu blíže.
Pro změnu konkrétního starého commitu můžeme použít tento příkaz:
$ git rebase <id_old_commit>
id - bude hash commitu
Tento příkaz započne proces rebase. Proces se zastaví a dá nám na výběr co můžeme udělat.
Většinou pomocí příkazu --amend uděláme změny a následně řekneme procesu rebase, že může pokračovat. Proces by mohl vypadat nějak takhle:
$ git commit --amend
$ git rebase --continue
3. Změna několika, libovolně starých commitů
Pro změnu několika commitů najednou se používá tzv. interaktivní rebase. Tento typ rebase se zapíná pomocí příkazu:
$ git rebase -i
nebo
$ git rebase --interactive
Během rebase několika commitů najednou máme možnost si vybrat z několika možností jak takové commity spojit dohromady.
- Reword nebo zkráceně ‘r’ - zastaví proces 
rebasea nechá Vás přepsat konkrétnícommit message - Squash nebo kráceně ‘s’ - během procesu 
rebase, všechny commity označené pomocísse sloučí s posledním commitem. Procesrebasese pozastaví a budeme vyzvání k přepsání posledního commitu. - Fixup nebo zkráceně ‘f’ - se chová podobně jako 
squash. Narozdíl odsquashe, takfixupnepozastaví procesrebasek otevření textového editoru.commit meassagezůstane stejná jako je poslední v poslednímcommitupouze se tomuto poslednímu commitu přilepí commity, které jsme označili písmenemf.commit messagesobsažené v commitech, které jsme označili pomocífjsou zahozeny. 
drop
Kromě spojování commitů, je možné v interaktivním rebase také commity smazat pomocí slovíčka drop nebo d. Smazat commit je také možné pokud před daný commit nedáte žádné specialní slovo.
pickup
Slovo pickup nebo p znamená, že tento commit chceme zachovat vzít.
V interaktivním rebase můžeme také přehazovat pořadí jednotlivých commitů, jak v historii gitu půjdou za sebou.
4. Git rebase
Pro lepší pochopení celého kontextu se nevyhneme detailnímu popsání příkazu git rebase.
Na začátek git rebase a git merge jsou v základu stejné příkazi. Oba dva slučují jednu větev do druhé. Ale každý to dělá jinak. Na konci článku je část, která se zabývá přímo srovnáním těchto dvou příkazů.
Příkaz git rebase je možné používat ve dvou módech:
- standardní či manuální mód
 - interaktivní mód (pomocí přepínače 
-inebo--interactive) 
Nejčastejší použití rebase můžeme vidět, když máme projekt, který je na větvi master. Tento projekt potřebuje vyvinout novou featuru. Pro tyto účely si založíme novou větev feature_branch. Na nové feature budeme pracovat nějaký čas. A v tomto čase, kdy mi budeme pracovat na feature, kterou jsme dostali za úkol, bude zbytek týmu pracovat na dalších features projektu. Tím se samozřejmě podoba větve master změní od podoby, z které jsme vytvořili novou větev feature_branch. Tento proces můžeme vidět na diagramu níže:
a - b - c - g - h  (master)
     \
      d - e   (feature_branch)
Novou větev feature_branch jsme vytvořili když větev master měla poslední commit c. Nyní když bych chtěl mou featuru mergnout tak větev master se posunula o další dva commity g a h. Abychom mohli naši větev pěkně mergnout musíme na ni udělat nejříve udělat rebase. Tedy chceme založit naše další změny na změnách ostatních - “I want to base my changes on what everybody has already done.”
Užitečné odkazy - další studium
Text článku byl čerpán hlavně z těchto zdrojů: