Jste zde

git pull? git up!

V následujícím příspěvku se podíváme na lepší alternativu za git pull.

Úvod

Dejme tomu, že jste v hlavní větvi (master) vašeho git repozitáře. Uděláte několik commitů a chcete je hodit na server. Provedete tedy

git push

Pokud vás již však někdo stačil předběhnout a hodil na server své změny, tak dostanete chybové hlášení podobnému tomuto:

To ssh://login@server/git/repo
! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'ssh://login@server/git/repo'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

Pokud se v gitu moc neorientujete, tak dáte

git pull

Potom již git push projde.

No a? V čem je tedy problém?

Když se následně podíváte do logu, tak tam kromě commitů, které jste provedli u sebe, uvidíte další váš commit podobný tomuto:

Merge branch 'master' of ssh://login@server/git/repo

Pokud vaši kolegové v projektu taktéž používají git pull, tak je pravděpodobné, že takovýchto commitů tam naleznete celou řadu. Říká to, že se provedl merge (sloučení) hlavní větve (master) do sebe sama. Podobné commity jsou však v drtivé většině případů nežádoucí a pouze zbytečně znepřehledňují a zaneřáďují commit historii.

Proč a jak tento vůbec commit vznikl?

Když se vám objevilo ono chybové hlášení, tak na serveru byly nové commity, které nemáte stáhnuté lokálně u sebe. Když dáte git pull, tak git za vás udělá následující dvě akce: git fetch a git merge. Tedy stáhne změny ze serveru (git fetch) a provede sloučení hlavní větve tak, jak je na serveru (origin/master) do vaší lokální master větve. Tím vznikne onen merge commit. Je to podobné, jako když děláte merge sami, akorát zde je to nad master větví.

Jak se podobným commitům vyhnout?

Možností je více. Já zde zmíním dvě cesty, jak se jim vyhnout.

  1. git pull --rebase=preserve. Místo toho, abyste dali pouze git pull, tak dáte git pull --rebase=preserve. Ten místo toho, aby za vás udělal git fetch a git merge, tak místo merge udělá rebase. Pak budete moct provést git push a nevznikne onen zbytečný merge commit. Poznámka: volba preserve způsobí, že rebase zachová lokální merge, pokud jste nějaký provedli a ještě jej nepushnuli (detaily).
  2. git up. Nainstalujte si skript git-up, který vám umožní používat git up místo git pull. Tento příkaz za vás automaticky aktualizuje všechny lokální větve a místo merge použije rebase, takže se vyhnete zbytečným commitům. V opačném případě, pokud máte více větví a používáte git pull, tak je nutné je aktualizovat všechny ručně, což je zdlouhavé.

    Co se týče nastavení tohoto skriptu, tak používám následující nastavení v .gitconfig:

    [git-up "rebase"]
    	arguments = --preserve-merges
    	log-hook = "echo \"* changes on $1:\"; git log --no-merges --pretty='format:%C(yellow)%h %C(green)%ai %C(bold blue)%an %C(red)%d%C(reset) %s' $1..$2"

    Ono první nastavení zachová merge, pokud jste nějaký provedli a po něm dali git up. Pokud toto nastaveno nemáte, tak se váš merge změní na rebase a budete se divit, co se stalo. Ono druhé nastavení přehledně vypíše seznam změn, které proběhly od poslední aktualizace. Více viz popis skriptu.

Důležité upozornění

Je třeba vzít do úvahy to, že v obou případech zmíněných výše se používá rebase, což vám (a především pak vašim kolegům) při nesprávném použití může způsobit bolesti hlavy. Je třeba se dobře seznámit s tím, co to rebase je a kdy se nesmí používat. Hlavním problémem je, že tento příkaz mění historii. Proto neváhejte a nastudujte si, co tento příkaz dělá. Naučíte se tak podstatnou a důležitou část gitu. Když už něco používáte pro svou práci, tak byste měli chápat, jak to funguje a jak se vyhnout tomu, aby vás to pokousalo. Pokud tedy nevíte, jak rebase funguje, tak si to nastudujte. Jinak o hodně přijdete.

Komentáře

Drobný leč zásadní překlep:
Když dáte git push, tak git za vás udělá následující dvě akce: git fetch a git merge.

Jinak dobrý tip, díky.

Jejda, díky za upozornění! Opraveno.

Přidat komentář