====== GIT ======
{{::git-transport.png}}
* workspace
* adresář se soubory projektu
* index (staging area)
* binární soubor (''.git/index'') obsahující seznam všech souborů včetně jejich sha1sum a časových razítek
* local repository
* skrytý adresář ''.git'' celého repozitáře obsahující mimo jiné podadresář objects
* objects obsahuje všechny verze, všech souborů, všech větví v podobě komprimovaných souborů
* remote repository
* vzdálený repozitář (bez workspace)
* může být zpřístupněn přes SSH, HTTPS nebo dokonce jen jako jiný lokální adresář
===== Založení repo =====
* založení repositáře
* pro založení repositáře na git serveru (pouze meta soubory) se používá přepínač ''--bare''
git init [slozka]
* připojení ke vzdálenému
* vzdálených může být více, ''origin'' je default název vzdáleného repo
git remote add origin https://example.com/user/test.git
* stažení vzdáleného
git clone https://example.com/user/test.git [lokalni_slozka]
* nastavení idenfiikace
git config [--global] user.name "First Last name"
git config [--global] user.email "first.last@example.com"
===== Nastavení =====
* ukládání credential (cache = dočasně, store = trvale)
git config [--global] credential.helper "cache"
===== Commit =====
* staging area
* obsahuje dávku ke commitu
* modifikované/nové soubory se nejprve musí vložit do staging area, pak commit
* zobrazení stavu souborů
git status [cesta]
* přidání do staging
git add [cesta]
* vlastní commit
git commit [-m "MSG"]
* nahrání na vzdálený repositář
* pokud jich je více (nebo pokud se nahrává poprvé) zadává se navíc jeho název
git push [name]
* stažení ze vzdáleného repositáře
git pull [name]
* konfigurace default editoru pro commit zprávy
git config --system core.editor
==== Změny ====
* message u posledního commit lze změnit příkazem
git commit --amend
* pokud byl commit už odeslán na vzdálený repozitář, je třeba použít přepínač force ''-force-with-lease''
* pokud už někdo navázal na tento commit, akce se neprovede
git push --force-with-lease [repository] [branch]
===== Vracení změn =====
==== Reset ====
* vracení změn přidaných do staging area
* zrušení všech necommitovaných lokálních změn
* zrušení lokálních commitů
git reset [cesta]
git reset --hard
git reset [revize]
* režim
* ''--soft'' - resetuje pouze HEAD
* zruší následující commity a soubory ponechá ve staging area
* ''--hard'' - resetuje HEAD, index a working tree
* zruší následující commity a všechny soubory vrátí do původní verze
* default revize je ''HEAD''
* lez použít čislo commitu nebo i relativní odkaz přes HEAD~2 apod
* pokud je zadána starší revize, zruší všechny následující commity
* nemělo by se dělat na pushnuté (nahrané na vzdálený repozitář) commity, naruší se posloupnost a vzniknou konflikty
==== Checkout ====
* revertování lokálních změn souborů
* přepnutí na jinou větev (vytvoření)
* získání souboru z jiné větve
git checkout [revize] [cesta]
git checkout [vetev]
git checkout [vetev] [cesta]
* default revize je HEAD
* lze zadat sha1sum commitu
* nebo relativně jako například HEAD~2 (2 commity dozadu)
* při přepnutí na jinou větev se lokální necommitované změny souborů přenáší do nové větve
* pokud by nastal konflikt, nepřepne se
==== Revert ====
* vrácení změn provedené zadaným commitem a provedení nového commitu
git revert [commit]
===== Odkládání změn =====
* stash
* lze použít pro řešení konfliktů při mergování
* lze použít na dočasné uložení rozdělané práce
* může jich být víc, lze je pojmenovávat
* Uschování všech změn v lokálním repozitáři do stash a vrácení repozitáře do čistého stavu
git stash [save "stash_name"]
* Výpis všech uschovaných stashů
git stash list
* Výpis detailů stash
* pokud není uveden název stash, bere se ta poslední
git stash show [stash_name]
* Aplikace změn ze stash do aktuální větve
git stash apply [stash_name]
* Aplikace změn ze stash a odstranění stash
git stash pop [stash_name]
* Odstraní stash
git stash drop [stash_name]
* Odstraní úplně všechny stash
git stash clear
===== Vyzvedávání změn =====
* Příkaz ''git pull'' provádí ''git fetch'' a ''git merge''
==== Fetch ====
* Příkaz fetch vyzvedne reference (větve, tagy, commity..) a ponechá je nesloučené s ukazatelem FETCH HEAD
* z hlavního vzdáleného repozitáře
* lze vyzvednout i jen konkrétní větev z konkrétního repozitáře
git fetch [ [master]]
* Parametr prune smaže všechny lokální reference, které na vzdáleném repozitáři neexistují
git fetch --prune
==== Merge ====
* Sloučení vzdálené větve origin/master do aktuální lokální
git merge origin/master
* Vypsání všech commitů mezi lokální a vzdálenou master větví
* lze použít také ''git diff''
git log --oneline master..origin/master
===== Větve =====
* jsou podstatou gitu
* slouží jako kopie projektu (workspace)
* hlavní větev se většinou označuje jako master
* další větve vznikají libovolně, využívají se například pro
* merge requests (po akceptování merge do hlavní větve se zdrojová zahodí)
* nezávislý vývoj nových feature
* dělí se na
* lokální - před prvním push se musí nastavit/založit odpovídající vzdálená větev
* vzdálené - nelze přímo upravovat, ze vzdálené se vytvoří nejprve lokální větev
==== Informace ====
* Vypíše seznam všech větví
* parametr ''--all'' zobrazí kromě lokálních také vzdálené větve
git branch [--all|-a]
* Vypíše seznam větví včetně názvu vzdálené, kterou sleduje
git branch -vv
==== Úpravy ====
* Vytvoří novou větev s názvem new_feature, neprovede ale přepnutí (checkout)
git branch new_feature
* Vytvoří větev a přepne se do ní (provede checkout)
git checkout -b new_feature
* Přepnutí do existující větve
git checkout master
* Vymaže lokální větev (pokud je mergnutá do jiné větve)
git branch -d new_feature
* Odstraní lokální reference na vzdálené větve, které byly na vzdálené straně odstraněny
git fetch --prune
* Přejmenuje aktuální větev
git branch -m awesome_feature
===== Tagy =====
* slouží k označení komitu
* měl by být unikátní, nelze mít dva commity se stejným tagem
==== Informace ====
* Vypíše seznam všech tagů
git tag
* Vypíše pouze tagy se jménem, které splňují daný pattern
git tag --list "v1*"
* Vypíše tagy na daném commitu, lze použít i jiné objekty gitu
git tag --points-at b7ef32
* Prohlížení pomocí jména tagu, zobrazí informace o tagu i commitu
git show v1.0
==== Úpravy ====
* Přidá tag k aktuálnímu commitu
* POZOR -- vynecháním přepínače ''-a'' se vytvoří lightweight tag
git tag -a v2.0-beta -m "Releasing v2 beta"
* Přidání zpětně ke staršímu commitu
git tag -a v2.0-beta -m "Releasing v2 beta" dd7216
* Následující operace nelze provést po pushnutí tagů do remote
* Přesun tagu na jiný commit pomocí --force
git tag -a v1.0 --force
* Odstranění tagu
git tag -d v1.0
===== Prohlížení commitů =====
* zobrazení commitů
git log
git log -n2 # maximálně dva commity
git log --oneline # jeden řádek na commit
* zobrazení commitů ve všech větvích
git log --all
===== Prohlížení rozdílů =====
* zobrazení rozdílů v souborech
* bez parametrů vypíše rozdíly mezi HEAD a aktuálními změnami pro všechny soubory
* lze vypsat konkrétní cestu
git diff [path]
* Lze specifikovat commit vůči kterému se porovnává
git diff [ [path]]
* Parametr ''--cached'' porovnává HEAD/commit vůči souborům přidaným do staging area.
* Opět lze specifikovat soubory
git diff ---cached [ [path]]
* Porovnává soubor/y mezi dvěma commity
git diff
* zobrazení commitů mezi lokálním a centrálním repositářem
git log --oneline master..origin/master
git diff master..origin/master
* zobrazení všech změn externím nástrojem (meld) mezi aktuální branch a zadanou
git difftool --dir-diff origin/moje-branch
===== Externals =====
* hodí se pro připojení jiného git projektu jako podprojekt
* možnosti jsou
* subtree - udělá jakoby checkout obsahu jiného projektu do složky v projektu
* submodule - vytvoří se jen vazba adresáře na jiný git repozitář
==== Submodule ====
* Klonování projektu se submoduly
git clone
git submodule init // inicializuje adresář subprojektu
git submodule update // nastaví obsah adresáře subprojektu na referenci
* Aktualizace souborů submodulů
* pokud chceme do superprojektu dostat novější verzi submodulu
* v superprojektu nastaví referenci na poslední komit ve vzdáleném repozitáři
* adresář submodulu v superprojektu změní svůj stav na modifikovaný
* změní obsah adresáře submodulu, aby odpovídal referenci
* a) v adresáři submodulu zavolat (doporučeno)
git pull
* b) v adresáři superprojektu zavolat (vytvoří detached head)
git submodule update --remote
* Detached head
* Pokud se provádí update na referenci jinou než je commit v HEAD vzdáleného repozitáře, vznikne detached head.
* Pokud neplánujeme měnit soubory subprojektu, tak by to nemělo ničemu vadit.
* Detached head lze vrátit zpět na HEAD postupem:
* zjistit branch, kterou má repo sledovat
* kouknout, zda sledujeme nejakou konkretni v .gitmodules
* pokud ne, tak třeba přes git branch --remote zjistit kam smeruje HEAD, zda to chceme
* v adresáři submodulu pak
git checkout
git pull
* Odstranění submodulu
* pro verzi 1.7.8+ stačí:
git submodule deinit
git rm
rm -rf .git/modules/ // zruší zbytek lokalních referencí, jinak může dělat v budoucnu problémy
* Přidání submodulu
git submodule add [-b ] [URL] [DIR]
* Přepnutí branch u submodulu
* prý stačí
git config -f .gitmodules submodule..branch
* a nebo možná
* editovat branch v .gitmodule souboru (pokud tam není, tak připsat)
* zavolat git submodule deinit
* zavolat git submodule init
* zavolat git submodule update --remote
* a nebo možná
git submodule update --remote
cd [SUBMODULE]
git checkout [NEWBRANCH]
====== Workflow ======
===== GitLab =====
* Ruby projekt pro projekty v Git
* Fork
* celý projekt patří jednomu uživateli
* pokud chce někdo provést změnu, vytvoří si fork celého projektu
* následně vytvoří merge request do původního projektu ze svého
* Větve
* projekt má více členů
* hlavní větve jsou protected proti přímé editaci
* pokud chce někdo provést změnu, vytvoří si novou větev z cílové
* následně vytvoří merge request do původní větve
===== Řešení konfliktů při merge =====
VER_FROM=
VER_TO=
git fetch origin
git checkout ${VER_FROM}
git pull
git branch -D merge-${VER_FROM}-to-${VER_TO}
git checkout -b merge-${VER_FROM}-to-${VER_TO} origin/${VER_TO}
git merge --no-ff ${VER_FROM}
git mergetool
git commit -m "Resolve conflicts"
git push origin merge-${VER_FROM}-to-${VER_TO}
* dobrý mergetool (lze nastavit) je meld
* levé okno je FROM
* pravé okno je TO
* prostřední je výsledek merge
====== Git HTTPS server ======
* jsou dvě možnosti
* přes webdav
* přes [[https://www.kernel.org/pub/software/scm/git/docs/git-http-backend.html|git-http-backend]] (doporučuje se)
===== Webdav =====
* [[http://blog.bobbyallen.me/2012/07/23/installing-a-git-server-using-apache-webdav-on-ubuntu-server-12-04/|installing-a-git-server-using-apache-webdav-on-ubuntu-server]]
* [[bft_apache#webdav|Apache + WebDav]]
* je zde problém s AUTH na metodu PROPFIND: git neposílá auth, ale webdav ji očekává (nebo tak něco)
* zobrazuje se hláška
error: Cannot access URL https://XXXXXX, return code 22
fatal: git-http-push failed
* na serveru v logu je u PROPFIND error 401 (unauthorized)
* zkoušel jsem [[https://jsosic.wordpress.com/tag/http/|fix]], ale nepomohlo
* musel jsem rozchodit přes přidání username přímo do url (buď při clone nebo ručně následovně)
vim .git/config
[remote "origin"]
url = https://USER@XXXXX/YYYY.git
* pokud na serveru máme selfsigned certifikát, je třeba při clone zadat
git clone https://XXX/YYYY.git -c http.sslVerify=false
* alternativně to lze zadat přes git config nebo přímou editací .git/config souboru
* sslverify jen pro určitý server se vypne takto:
[http "https://XXXXXX"]
sslverify = false
===== Odkazy =====
* workflow s gitem
* https://www.atlassian.com/git/tutorials/comparing-workflows
* jeden z mnoha návodů na git
* http://www.kutac.cz/blog/pocitace-a-internety/jak-na-git-dil-0-co-proc-jak/
* aplikace pull request z github (pokud ho ještě autor nemergoval)
* https://help.github.com/articles/checking-out-pull-requests-locally