Git je nástroj pro správu verzí a hromadné sledování změn souborů v rámci jednoho projektu. Rozdíl dvou verzí souboru se označuje jako diff z anglického slova difference a popisuje nám jak se soubory navzájem liší.
Změnu jednoho souboru můžeme popsat textovým souborem s koncovkou .diff, který nám popisuje, jaké změny musíme provést, abychom se dostali z jedné verze na druhou. Tomuto vygenerovanému souboru se pak říká patch (záplata).
Takový soubor vypadá například takto:
diff --git a/file.txt b/file.txt
index 322e040..13f7c5d 100644
--- a/file.txt
+++ b/file.txt
@@ -1,2 +1,3 @@
-test modified content
+test modified 2 content
new test line
+third new line
\ No newline at end of file
Poznámka: Pro vygenerování diff souboru lze na Unix-like systémech příkaz diff a pro aplikaci této záplaty zase příkaz patch.
K čemu je to dobré, když se nám Git o sledování změn stará automaticky? Patche se nám hodí když:
- potřebujeme poslat změnu souboru nebo commit pomocí e-mailu, např. chceme poslat někomu opravu a jeho systém neumí přijímat pull requesty
- pro přenos commitů z jednoho repozitáře do druhého
- když musíme udělat změnu (opravu) v rámci složky, která se běžně ignoruje (typicky opravy ve složce vendor)
- chceme si pro sebe zaznamenat nějakou změnu souboru, nebo opravu, aniž bychom vytvářeli složitě repozitář pro verzování
Patch vytváříme vždy vůči nějakým změnám. První co tedy musíme udělat, je provést nějakou změnu v repozitáři. Pak je více způsobů jak patch vytvořit a záleží už na nás, co použijeme:
Jak vytvořit patch z commitu
Vytvoříme změnu a uděláme commit. V konzoli zadáme:
git format-patch -1 73511d3
kde 73511d3 je prvních 7 znaků z hashe provedeného commitu. To nám automaticky vytvoří soubor s příponou .diff. V programu SourceTree toto samé můžeme udělat pomocí Actions -> Create patch -> Patch from commits. Zde vybereme commit ze kterého chceme patch vytvořit.
Hash commitu můžeme zjistit pomocí:
git log --pretty=oneline -3
Což nám zobrazí poslední 3 commity, každý hezky na jednu řádku.
Příkaz format-patch nám vygeneruje rozšířený diff soubor v mbox formátu, který obsahuje i údaje o commitu a lze poslat přímo e-mailem:
From 42127fb46108f622d4f82d9178e65982be3f7984 Mon Sep 17 00:00:00 2001
From: Vojta Svoboda <vojtasvoboda.cz@gmail.com>
Date: Sat, 9 Aug 2014 10:58:35 +0200
Subject: [PATCH] New commit
---
file.txt | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/file.txt b/file.txt
index 08cf610..322e040 100644
--- a/file.txt
+++ b/file.txt
@@ -1 +1,2 @@
-test content
\ No newline at end of file
+test modified content
+new test line
--
2.0.0
Tento soubor lze poslat příkazem:
git send-email patch.diff
který používá interní funkci /usr/sbin/sendmail.
Jak vytvořit patch bez commitu
Vytvoříme změnu souborů. Pokud nemáme soubory v indexu (nejsou ve stage) napíšeme:
git diff > patch.diff
kde patch.diff je název souboru kam chceme patch uložit. Pokud chceme udělat diff ze souborů co jsou ve stage, tak použijeme příkaz:
git diff --cached > patch.diff
V programu SourceTree toto samé můžeme udělat pomocí Actions -> Create patch -> Patch from Working copy.
Jak vytvřit patch vůči jiné větvi
Jedna z dalších možností je vytvoření patche vůči nějaké větvi, typicky nějaká master větev kterou právě opravujeme v naší větvi. Provedeme opravu jedním, nebo více commity a zadáme:
git format-patch master --stdout > patch.diff
kde master je větev kterou opravujeme a aktuálně jsme přepnutý v naší větvi.
Aplikace patche
Nyní když máme patch vytvořený můžeme ho zkusit použít. Nejdříve se podíváme co patch obsahuje:
git apply --stat patch.diff
kde patch.diff je soubor s patchem, nám vypíše seznam změn, které patch provádí. Dále:
git apply --check patch.diff
nám provede kontrolu patche ještě než ho aplikujeme do naší větve. Pokud je vše v pořádku, zadáme:
git apply patch.diff
což nám aplikuje daný patch. Apply nám ale pouze změní dané soubory, nevytváří žádný commit. Pro kompletní rekonstrukci použijeme:
git am patch.diff
což je aplikovaní patche včetně merge do aktuální větve v přesné formě jak byl zamýšlen. Zkratka am znamená apply mail, tzn. přijmutí patche který jsme přijali e-mailem. Tento poslední příkaz nám vytvoří kompletní commit včetně nastavení autora a popisu (commit message). V programu SourceTree toto samé můžeme udělat pomocí Actions -> Apply patch a vybereme soubor s patchem.
Git bundles
Pro přenos historie commitů nebo celých větví, z jednoho repozitáře do druhého, můžeme také použít příkaz:
git bundle create changes.bundle master
Tento příkaz vlastně zastupuje příkazy git fetch a git pull, když zrovna nemáme dostupný příme síťové spojení do repozitáře.
Problém s chybou "patch does not apply"
V případě problémů s patchováním můžeme zkusit příkaz:
git apply --ignore-space-change --ignore-whitespace mychanges.patch