diff options
Diffstat (limited to 'eu/2.md')
-rw-r--r-- | eu/2.md | 1026 |
1 files changed, 1026 insertions, 0 deletions
@@ -0,0 +1,1026 @@ +--- +title: GIT — EITB 2022 +subtitle: Erabilera aurreratua +license: CC-BY-SA 4.0 +author: Ekaitz Zarraga - ElenQ Technology +links-as-notes: true +lang: basque +polyglossia-lang: + name: basque +how-to: pandoc -f markdown+smart -t beamer % -o pdf/2.pdf --pdf-engine=xelatex --template=./template.tex +... + +## Lizentzia + +- CC-BY-SA 4.0 +- Dokumentu honen edukiak eta irudiak [**Pro Git (Scott Chacon, Ben + Straub)**](https://git-scm.com/book/en/v2) liburutik atera dira. + +# Git zerbitzarian + +## Git zerbitzarian: sarrera + +Lankideen artean kodea partekatzeko zerbitzari bat izatea ideia ona da: beti +dago eskuragarri, kudeaketa sinplifikatzen du, etab. + +Zerbitzarietan *bare repository*-ak erabiltzen dira. Hauek ez dute *working +directory*-rik. `.git` direktorioan dagoena bakarrik dute. + +- `git init --bare` *bare repository* bat eratzeko. + +## Protokoloak + +Protokolo ezberdinak erabili daitezke repositorioen arteko komunikazioa +egiteko: + +- **Local**: beste fitxategi batean dagoen repositorioa. `git clone + /path/to/file`-en bitartez klonatu daiteke. +- **HTTP**: *smart* edo *dumb* moduak ditu. *Smart*-ek baimenak kudeatu ditzake. + *Dumb*-ek fitxategiak eman baino ez du egiten. +- **SSH**: Askotan erabiltzen da. Erabiltzaile bat behar du. + `git clone ssh://[<user>@]<host>/<project>.git` erabiliz. SCP-ren modu + laburra erabili daiteke: `[<user>@]<host>:<project>.git`. +- **Git**: SSH-ren antzekoa da baina autentikazio barik. + +## Protokoloak — Adibide bat + +Nire [zerbitzaria](https://git.elenq.tech/): + +- Web bitartez proiektuak aztertu daitezke. `cgit` erabiltzen du. Beste aukera + batzuk daude: `gitweb` adibidez, Git-ekin datorrena. +- Proiektu publikoak Git-en bitartez zerbitzatzen dira edonork kopiatu ahal + izateko. +- Idazteko baimena SSH-ren bitartez zerbitzatzen da, baimena kontrolatu ahal + izateko. + +*Liburuan azaltzen da gauza hauek nola muntatu.* + + +# Git workflowak + +## Workflow zentralizatua + +Git-en izaera banatuak *workflow* ezberdin asko ahalbidetzen ditu baina gaur +egun *workflow zentralizatua* erabiltzen da gehien, Web zerbitzu integratuen +arrakastagatik (Github, Gitlab, Gitea...) non tiketak eta kodea kudeatzeko +aukera dagoen. + +![Bezero guztiak zerbitzariarekin sinkronizatzen dira](img/centralized_workflow.png){ height=140px } + +## Email-en bitartez + +Software libre proiektu asko oraindik emailean oinarritzen dira aldaketak +proposatzeko. + +- `git format-patch <commit-selektorea>` aukeratutako commitak patch + fitxategietan idazteko +- `git send-email <patch-fitxategiak>` patch-ak emailez bidaltzeko + (konfigurazioa behar du) +- `git am <patch-fitxategiak>` jasotako patch-ak proiektuan commiteatzeko +- `git apply <patch-fitxategiak>` jasotako patch-ak aldaketa moduan aplikatzeko + + +# Git tresna aurreratuak + +## Commit selektoreak + +Giten komando asko commit askotan aplikatu daitezke. Gitek commit selektore +ezberdinak aplikatzea ahalbidetzen du commitak aukeratzeko. + +- `git show <commit-selektorea>` aukeratutako objektuak erakusteko + +*Ikusi `git show`-n laguntza. Objetu ezberdinak erakutsi ditzake* + +*Ikusi `git rev-parse`-n laguntza, selektoreen sintaxia azaltzen baitu.* + + +## Commit selektoreak — I + +- **SHA-1 hasha**: commit identifikadorea bera erabili daiteke selektore moduan. + Oso luzeak direnez, hasierako karaktereak bakarrik erabili daitezke anbiguoak + ez badira. `git log --abbrev-commit` commit id-aren laburpena egiten du. + +- **Adarren burua**: adarraren izena erabiltzean, adarraren buruaren commita + aukeratzen da: `git show <adarra>`. Adarraren buruaren commit id-a + ateratzeko: `git rev-parse <adarra>`. + +- **Reflog-a**: Reflog-a repositorioaren egoera gordetzen du historiko baten + modura. Reflog-aren sarreren izenak erabili daitezke commit selektore moduan. + Gainera denbora erabili daiteke: `HEAD@{yesterday}`. + + - `git reflog` reflog-aren sarrerak erakusteko + +## Commit selektoreak — II + +- **Gurasoak**: aukeratutako commiten gurasoak eta aitzindariak lortu daitezke: + + - Txapela (`^`) erabiliz aukeratutako commitaren gurasoak lortu daitezke. + Adibidez: `git show HEAD^`. Merge commitetan (guraso asko dituztenak) + gurasoen artean aukeratzeko `^` eta gero gurasoaren zenbakia jarri + daiteke guraso konkretua lortzeko. + - Tildea (`~`) erabiliz aitzindariak lortu daitezke. Zenbaki bat gehituta + aurreko aitzindaria lortu daiteke. Adibidez `git show HEAD~2`: aurreko + commitaren aurrekoa lortu. + +## Commit selektoreak — III + +- **Commit tartea**: bi commiten arteko tartea lortzeko: `..` + Adarrekin ere egin daiteke, adar batetik besteraren burura ailegatzeko behar + diren commitak lortzeko: + ![](img/double-dot.png){width=350px} + - `git log master..experiment` => D C + - `git log experiment..master` => F E + +## Commit selektoreak — IV + +- **Puntu tripleak**: bi adarretatik ailegatu ahal diren commitak, baina + amankomunean ez daudenak: + ![](img/double-dot.png){width=350px} + - `git log master...experiment` => F E D C + - Zein adarretik datozen ikusteko `--left-right`: + ``` + git log master...experiment --left-right + < F + < E + > D + > C + ``` + +## Commit selektoreak — V + +- **Puntu multipleak**: eskaera konplexuagoak egiteko `^` (aurretik) edo + `--not` erabili daiteke, adar horren commitak baztertzeko: + - Hurrengo komandoak baliokideak dira: + ``` + git log refA..refB + git log ^refA refB + git log refB --not refA + ``` + - Hurrengo komandoek `refA`tik eta `refB`tik lortu daitezkeen commitak + hartzen dituzte, `refC`tik lortu daitezkeenak baztertuz: + ``` + git log refA refB ^refC + git log refA refB --not refC + ``` + +## Staging interaktiboa + +- `git add --interactive|-i` stage-a modu interaktiboan kudeatzeko +- `git add --patch|-p` gehituko diren aldaketak modu interaktiboan + aukeratzeko. Blokez bloke + +*Komando askotan erabili daitezken aukerak dira hauek. +Oso erabilgarriak dira.* + +## Stash-a + +Aldaketak gordetzeko zaku bat da *stash*a. Trakeatu gabeko aldaketak bertan +sartu daitezke repositoria aldatu/berriztu/mergeatu eta gero aldaketak berriro +adar berdinean edo beste batean ateratzeko. + +- `git stash [push]` direktorioa garbitu eta aldaketak *stash*era sartzeko +- `git stash list` *stash*aren sarrerak ikusteko +- `git stash apply [<stash-sarrera>]`-k aukeratutako sarrera (defektuz + azkena) aplikatzen dio *working directory*ari. +- `git stash drop [<stash-sarrera>]` aukeratutako *stash* sarrera ezabatzeko +- `git stash pop` = `git stash apply` + `git stash drop` + +*Push* eta *pop* izenak erabiltzen dira *stash*a LIFO ilara edo stack baten +moduan kudeatzen delako. *Gainetik gehitu eta gainetik atera* + +## Stash-a — Aukera interesgarriak + +- `git stash apply --index` egitean *staging area*ra bidaltzen dira *stash*ean + *staging area*an zeuden fitxategiak. Defektuz ez dira *stage*era bidaltzen. +- `git stash --keep-index` indexatutako (*stage*a) fitxategiak ez dira + *stash*era gehitzen, eta *stage*ean mantentzen dira. +- `git stash --include-untracked|-u` trackeatuta ez dauden fitxategiak ere + *stash*eatzeratzeko. +- `git stash --all|-a` baztertutako fitxategiak (`.gitignore`) ere *stash*era + gehitzeko +- `git stash --patch|-p` *stash*eratzeratzeko aldaketak modu interaktiboan + aukeratzeko +- `git stash branch <adar-izena> [<stash-sarrera>]` adar berri bat sortu eta + bertan aukeratutako *stash*a aplikatu. Dena ondo badoa *stash*a garbitzen du + bukatzerakoan. + +## Direktorioa garbitzeko + +- `git stash --all` egitea direktorio osoa garbitzen du, hau da, trackeatuta ez + dauden fitxategiak eta aldaketak *stash*earatzen ditu. +- `git clean` egiten antzeko efektu bat lortu daiteke *stash*a erabili gabe, + zuzenean aldaketak eta fitxategiak ezabatuz. + - `-f` (*force*) beharrezkoa da (defektuz, aukera bat dago desaktibatzeko) + nahi gabe ez egiteko + +> KONTUZ: `git clean --dry-run|-n` erabili badaezpada, zer egingo duen ikusteko +> benetan exekutatu baino lehen. + +## Sinadurak + +Commit faltsuak ekiditeko, commitak sinatu daitezke GPG-ren bitartez. + +> GPG (Gnu Privacy Guard), PGP-ren (Pretty Good Privacy) inplementazio bat da. + +`user.signkey` konfiguratu behar da. + +- `git commit -S` commitak sinatzeko +- `git tag -s` tagak sinatzeko +- `git merge --verify-signatures` sinadurak baieztatzeko mergetan +- `git tag -v` tag-en sinadurak baieztatzeko + +Sinadurak erabiltzen badira, proiektu kide guztiek commitak sinatu behar +dituzte. + +## Bilaketak + +- `git grep` espresio erregularren bitartez bilaketak egiteko. `grep` + komandoarekin alderatuta azkarragoa da eta historikoan eta indexean bilatzen + du. +- `git log` logetan bilatzeko funtzio oso interesgarriak daude: + - `-S` *pickaxe* funtzioa + - `-L` lerroen eboluzioa edo funtzioaren eboluzioa erakusten du + +## Historia berridazten + +- `git commit --amend` mini-rebase baten eragina dauka +- `git rebase -i|--interactive <commit>` aukeratutako commitera ailegatzeko + behar diren commitak aldatu. + Editorearen bitartez commit bakoitzarekin zer egin behar duen adierazi ahal + zaio: commitak batu, aukeratu, mezua berridatzi, editatu... Aukera batzuek + prozesua gelditzen dute. `git rebase --continue` egiten aurrera jarraitzen + da, edo `--abort` egiten prozesua ezeztatzen da. Komandoak berak oso ondo + azaltzen du nola egin. + +> KONTUZ: N+1 commit aldatu emaitza gutxienez commit bat behar duelako + +- `git filter-branch` eta antzeko tresnek aldaketa sakonak egin ditzakete. + Adibidez, fitxategi bat commit *guztietatik* kendu. + +## Reset eta checkout sakonki — I + +Reset eta Checkout ulertzeko Giten fitxategien egoerak eta haien arteko +trantsizioak ondo ulertu behar dira. Hiru egoera posible daude: + +1. HEAD: repositorioaren azkeneko commitaren snapshota +2. Index: *staging area*, hurrengo commitaren proposamena +3. Working Directory: Aldaketak egiten ditugun lekua + +![Egoren arteko trantsizioak](img/reset-workflow.png){height=150px} + +## Reset eta checkout sakonki — II + +- `git reset`-ek hiru modu ditu: + - `--soft`: HEAD-ak apuntatzen duen adarra mugitu + - `--mixed`: `--soft` + egoera indexera pasatu + - `--hard`: `--mixed` + egoera *working directory*ra pasatu, bertako + aldaketak zapalduz + + +## Reset eta checkout sakonki — III + +Grafikoki aztertuz. Repositorio hutsarekin hasita: + +![ ](img/reset-ex1.png) + +## Reset eta checkout sakonki — IV + +Fitxategi bat *indexera* gehitu: + +![ ](img/reset-ex2.png) + +## Reset eta checkout sakonki — V + +Fitxategia repositorioan idatzi: + +![ ](img/reset-ex3.png) + +## Reset eta checkout sakonki — VI + +Fitxategia aldatu: + +![ ](img/reset-ex4.png) + +## Reset eta checkout sakonki — VII + +Egoera *indexera* bidali: + +![ ](img/reset-ex5.png) + +## Reset eta checkout sakonki — VIII + +Commit berria gehitu: + +![ ](img/reset-ex6.png) + +## Reset eta checkout sakonki — IX + +Beste commit bat gehituta: + +![ ](img/reset-start.png) + +## Reset eta checkout sakonki — IX + +`--soft`: + +![ ](img/reset-soft.png) + +## Reset eta checkout sakonki — X + +`--mixed` (defektuz egiten da): + +![ ](img/reset-mixed.png) + +## Reset eta checkout sakonki — XI + +`--hard`: + +![ ](img/reset-hard.png) + +## Reset eta checkout sakonki — XII + +Hiru aukeraz aparte, `git reset`-i fitxategi bat sartu ahal zaio. + +Kasu horretan, lehenengo pausua (HEAD-a mugitzea) ezin da burutu[^head] baina +hurrengo pausuak arazo barik egin daitezke. Horrek funtzionamendu +interesgarriak ahalbidetzen ditu. + +- `git reset <fitxategia>` egiten denean, benetan + `git reset --mixed HEAD <fitxategia>` egiten da. + 1. ~~HEAD-a mugitu~~ + 2. Egoera indexean jarri + + Hau da: **Fitxategia indexetik atera** + +[^head]: HEADa ezin da erdizka mugitu, edo repositorio osorako mugitzen da edo + ez da mugitzen. + +## Reset eta checkout sakonki — XIII + +Grafikoki: + +![ ](img/reset-path1.png) + + +## Reset eta checkout sakonki — XIV + +Adibide konplexuago bat: `git reset <commit> -- <file>` + +1. HEAD-a ezin da mugitu +2. `<file>`-k `<commit>`-en daukan egoera indexera sartzen da (`--mixed`). + +![ ](img/reset-path3.png){height=220px} + + +## Reset eta checkout sakonki — XV + +Ikusitakoa *squash* (commit batzuk bakarrean batu) egiteko erabili +daiteke[^rebase-interactive]. + +- `git reset --soft HEAD~<N>` egitean HEADa atzera eraman daiteke, indexean + aldaketak mantenduz. `git commit` eginda, aldaketak repositorioan idatzi + daitezke, denak **commit bakarrean**. + +[^rebase-interactive]: Beste aukera `git rebase --interactive|-i` erabiltzea da + +## Reset eta checkout sakonki — XVI + +Grafikoki: + +![ ](img/reset-squash-r1.png) + +## Reset eta checkout sakonki — XVII + +HEADa mugitu aldaketak indexean mantenduz: + +![ ](img/reset-squash-r2.png) + +## Reset eta checkout sakonki — XIX + +Commit berria sartu aldaketa guztiekin batera eginda + +![ ](img/reset-squash-r3.png) + +## Reset eta checkout sakonki — XX + +`checkout` eta `reset` antzekoak dira, baina ez dira berdinak: + +- `git checkout`-ek ez du HEADa eraldatzen. HEAD erreferentzia non apuntatzen + duen aldatzen du, ez du azpian dagoen adarra aldatzen. + +- `git checkout <branch>` eta `git reset --hard <branch>` ia berdinak dira + baina `checkout`ek ez ditu aldaketak zuzenean zapaltzen. + +- `git checkout <fitxategia>` fitxategian zeuden aldaketak **zapaltzen ditu** + *working directory*an, `git reset --hard`en antzera. KONTUZ + +Bietan `--patch` erabili daiteke zatika egiteko. + + +## Reset eta checkout sakonki — XXI + +`git checkout` vs `git reset`en efektua HEADan: + +![ ](img/reset-checkout.png) + + + +## Merge aurreratuak, konfliktoen kudeaketa — I + +Mergeak egin baino lehen, ideia ona da *working directory*a garbitzea (`git +stash`), horrela, zeozer txarto badabil atzera buelta eman daiteke aldaketak +galdu barik. + +- `git merge --abort` mergea txarto doanean (konfliktoak) mergea ezeztatzen + du. + + > KONTUZ: aldaketak badaude *working directory*-an ezin izango da abortatu. + + +## Merge aurreratuak, konfliktoen kudeaketa — II + +Konfliktoetan Gitek 3 fitxategi ematen ditu: + +1. Stage 1: *common ancestor*-a (*base*), bi adarretatik iritsi daitekeen + lehengo commita: `git merge-base`-ekin lortu daiteke puntu hau +2. Stage 2: Gure (*ours*) bertsioa, gure adarrean dagoena +3. Stage 3: Haien (*theirs*) bertsioa, mergeatzen dugun adarrean dagoena + +- `git show :<stageN>:<file>` stage fitxategiak ikusteko + - `:<stageN>:<file>`-k blob horren hasha lortzen du. + +- `git diff`-en bitartez ikusi daitezke, stage-a aukeratuz + - `git diff -1|--base` + - `git diff -2|--ours` + - `git diff -3|--theirs` + +## Merge aurreratuak, konfliktoen kudeaketa — III + +- `git show :<stageN>:<file>` eginez, stage bakoitzaren fitxategiak fitxategi + ezberdinetara idatzi daitezke eskuz prozesatzeko + +- `git merge-file` erabili daiteke hiru fitxategiak eskuz mergeatzeko. Merge + algoritmoak aplikatuko ditu + +## Merge aurreratuak, konfliktoen kudeaketa — IV + +Konfliktoak hobeto aztertzeko tresna batzuk: + +- `git checkout --conflict` konfliktoa daukan fitxategiaren konflikto + markadoreak berriro idazten ditu. Eskuz aldatzean nahi gabe ezabatu + ditugunean interesgarria da. + +- `git checkout --ours/--theirs` egin daiteke alde bat edo bestea ikusteko. + +- `git log --oneline --left-right --merge` interesgarria da testuingurua + ulertzeko. + +- `git diff` egitean konfliktoetan *combined diff* bat agertzen da, bi + zutabeetan ikusten dira aldaketak. + +- `git show -p|--patch` egitean `--cc` gehitu daiteke *combined diff*a ikusteko + + +## Merge aurreratuak, konfliktoen kudeaketa — V + +*Combined diff*-aren itxura, konflikto bat konpontzean: + +``` +diff --cc hello.rb +index 0399cd5,59727f0..0000000 +--- a/hello.rb ++++ b/hello.rb +@@@ -1,7 -1,7 +1,7 @@@ + #! /usr/bin/env ruby + + def hello +- puts 'hola world' + - puts 'hello mundo' +++ puts 'hola mundo' + end +``` + +Bi zutabe daude `-` eta `+` sinboloekin, alde bakoitzean zer gertatu den +ikusteko. + +## Merge aurreratuak, konfliktoen kudeaketa — VI + +Konfliktoetan `diff3` erabiltzea interesgarria izan daiteke, defektuz `merge` +erabiltzen da. Atal berri bat gehitzen dio konfliktoari, *base*a bistaratzeko. +``` +<<<<<<< ours + puts 'hola world' +||||||| base + puts 'hello world' +======= + puts 'hello mundo' +>>>>>>> theirs +``` + +- `git checkout --conflict=diff3` konfliktoa 3 stagetan bistaratzeko. + +- `git config --global merge.conflictstyle diff3` konfliktoak 3 bidetan + ikusteko + + +## Mergeak desegiten — I + +Bi aukera ezberdin dago mergea desegiteko: + +1. `git reset --hard HEAD~` (historikoa berridazten du) +2. `git revert -m 1 HEAD` commit bat gehitu aldaketak desegiten dituena. + Arazoak datoz adarra berriro mergeatu behar denean. + +## Mergeak desegiten — II + +`git revert -m 1 HEAD` egitean, mergea desegin da beste commit batekin. `^M` +eta `C6` eduki berdinak dituzte. Baina `topic` adarraren commitak `master`etik +iritsi daitezke. Gitentzat mergeatuta daudela dirudite. KONTUZ + +![](img/undomerge-revert.png) + +## Mergeak desegiten — III + +Txarragoa izan daitekeena, aldaketak gehitzen badira, Gitek commit berriak +baino ez ditu hartzen, bestea mergeatuta dagoela uste duelako. KONTUZ + +![](img/undomerge-revert2.png) + +## Mergeak desegiten — IV + +Arazoa saihesteko, aurreko mergea, desegin duguna, aplikatu behar da. +Horretarako, `revert` commita desegin daiteke beste `revert` bat eginez. + +![](img/undomerge-revert3.png) + +Orain, `topic`-en aldaketa guztiak `master`-en daude. + +## Mergeen preferentziak + +`git merge` aukera eta estrategia ezberdinak daude: + +- `-X` aukerak gehitzeko erabiltzen da. Adibidez: `-Xours` konfliktoak gure + aldera ebazteko + +- `-s` estrategiak gehitzeko. Adibidez: `-s ours` mergea egin beharrean, gure + aldeko aldaketak bakarrik aukeratu (Giti ziria sartzeko interesgarria da) + +Aukerak eta estrategiak ez dira gauza bera. Estrategiak merge algoritmoa +definitzen dute. Aukerek algoritmoa konfiguratzen dute. + +## Subtree-ak + +Subtree-ak beste proiektu bat gure proiektuaren barruan sartzeko mekanismo bat +dira. Azpiproiektua adar independente batean kudeatzen da: beste remote bat +moduan hasierazten da, baina adar berri batean sartu, beste adarrekin +zerikusirik ez duena. + +- `git read-tree` azpiproiektua irakurri eta beste adar baten azpidirektorio + moduan hasiarazteko +- `git merge -Xsubtree` erabiltzen da *subtree*aren adarra proiektuan + arazo barik mergeatzeko +- `git diff-tree` azpiproiektuaren aldaketak aztertzeko, `diff` normal bat ez + dabil + +*Ez da asko erabiltzen, *Submodule*ak gehiago erabiltzen dira. Gehiago ikasteko, +liburua irakurri.* + +## Rerere: Reuse Recorded Resolution — I + +Konfliktoak nola konpondu ditugun erregistratzeko sistema bat da, gero Gitek +konfliktoak automatikoki ebazteko kriterio berdina erabiltzen. Adibide baten +bitartez: + +1. Testing adarra mergeatzen konfliktoak daude +2. Konfliktoak konpontzen dira +3. Testak txarto doaz +4. Mergea desegin behar da +5. Testak konpondu behar dira +6. Mergea berriro egin => konflikto berdinak berriro konpondu behar dira + +`rerere`-ren bitartez lehenengo mergearen konfliktoen ebazpena gorde daiteke. +Horrela, mergea berriro aplikatzerakoan ez da konfliktoa berriro ebatzi behar, +automatikoki aurretik gordetako ebazpena erabiltzen delako. + +## Rerere: Reuse Recorded Resolution — II + +- `git config --global rerere.enabled true` +- `git rerere status` *rerere*ren egoera ikusteko +- `git rerere diff` *rerere*k aplikatuko lituzken aldaketak ikusteko +- `git add` + `git commit` egiterakoan ebazpena gordetzen da: + `"Recorded resolution"` +- `git reset --hard HEAD^` eta mergea berriro egiterakoan konfliktoak + automatikoki konpontzen dira: + `"Resolved with previous resolution"` +- `git checkout --conflict=merge <file>` eginda konfliktoa berreskuratu + daiteke, `rerere`a aktibatu gabe +- `git rerere` egiten berriro mergeatu daiteke automatikoki + + +## Gitekin debuggeatzen + +- `git blame` fitxategi baten aldaketak zein commitean sartu diren ikusi + daiteke. `^`-ekin hasten diren lerroak hasieratik aldatu gabeko lerroak dira. + `-C` aukerarekin mugitutako zatiak aurkitu daitezke[^move] + +[^move]: Gitek ez ditu mugimenduak gordetzen baina fitxategien zatiak aztertu + eta mugimenduak kalkulatu ditzake + +- `git bisect` [bisekzio metodoa][bisect] erabiliz errorea sartu zuen commita + aurkitzeko tresna oso interesgarria. Metodoa: + - Bi commit hartu: bat erroreduna eta bestea errore gabea + - Erdiko puntuan commit bat hartu: errorea badauka, errorea sartu zuen + commita commit honen eta errore gabeko commitaren artean dago. Errorea ez + badago, commit honen artean eta commit erroredunaren artean dago. + - Beste puntu bat hartu eta jarraitu tartea txikitzen commita aurkitzen den + arte. + +[bisect]: https://en.wikipedia.org/wiki/Bisection_method + + +## Gitekin debuggeatzen: `git bisect` + +Bisekzio metodoa aplikatzeko workflowa + +1. `git bisect start` bisekzio metodoa hasi +2. `git bisect bad` oraingo commita txarra da +3. `git bisect good <commit-id>` commit hau ona da +4. `git bisect good/bad` oraingo commita ona edo txarra da. Gitek + hurrengo commita aukeratzen du: + `"Bisecting, N revisions left to test"` +5. `git bisect reset` hasierara bueltatu + +Automatizatu daiteke: `git bisect run <command>` + +- Komandoak `0` bueltatu behar du testa ondo badoa eta beste edozer errorea + badago + + +## Submoduluak + +Gure proiektuaren barruan azpiproiektuak kudeatzeko modu bat da. + +- `git submodule add <URL>` azpiproiekturako karpeta berri bat gehitzen du eta + `.gitmodules` fitxategia hasieratzen du +- `.gitmodules` fitxategian azpiproiektuen informazioa gordetzen da: URLa, + izena eta path-a. +- `git submodule add ...` eta gero `git diff --cached` egitean ikusten da + submoduluen path-a ez dela fitxategi bezala kudeatzen: + `"Subproject commit ---"` +- `git diff --submodule --cached`-ekin hobeto ikusten da +- `git push` egiterakoan submodule-aren direktorioa erreferentzia moduan + pusheatzen da. + +## Submoduluak klonatzeko + +- `git clone`-ek **ez** ditu proiektuen submoduluak deskargatzen +- `git submodule init` submoduluen kontrola hasieratzeko +- `git submodule update` submoduluen fitxategiak berrizteko +- `git clone --recurse-submodule <URL>` zuzenean submodule guztiak + deskargatzeko `clone` egiterakoan. Bestela `git submodule update --init` edo + `git submodule update --init --recursive` egin daiteke klonatu eta gero + +## Submoduluekin lanean + +- `git diff --submodule` ez egiteko `git config --global diff.submodule log` + egin daiteke eta zuzenean submoduluaren diffa ikusi daiteke `git diff` + egitean +- `git submodule update --remote <submodule>` submoduluen edukiak berrizteko + edo bestela submoduluaren barruan `fetch`+`merge` egin daiteke. +- `git config -f .gitmodules submodule.<submodule>.branch <adarra>` adarrez + aldatzeko, edo fitxategia zuzenean aldatu +- `git config status.submodulesummary 1` egitean `git status`-ek submoduluen + egoera bistaratuko du +- `git log --submodule` submoduluen aldaketak ikusteko + +## Submoduluak dituen proiektua berrizteko + +- `git pull` ez ditu submoduluak berritzen, informazioa baino ez du + deskargatzen. +- `git submodule update` aplikatu behar da, `--init`-ekin submodule berriak + gehitu badira, hauek gehitzeko eta `--recursive`, submoduluek submoduluak + badituzte. +- `git pull --recurse-submodules`-k efektu berdina dauka. Konfiguratu daiteke + automatikoki egiteko. +- `git submodule sync` egin behar da URLak aldatu badira. + +## Submoduluetan lanean + +Normalean ez da submoduluetan idazten, baina egin daiteke. + +- `git submodule update`-k azpirepositorioa *detached head* egoeran uzten du. + Bertak commitak gehitzean galduko lirateke (ez dago adarrik commitetara + ailegatzeko). Hau konpontzeko: + + 1. Adarrak konfiguratu behar dira: `cd <submodule> && git checkout <branch>` + 2. `git submodule update --remote --merge/--rebase` egin behar da *detached + head* egoeran ez gelditzeko. Submoduluan aldaketak badaude, konfliktoa + egon daiteke. + +## Submoduluen lana publikatzen + +- `git push` egin daiteke submodulu bakoitzean, Git repositorio normalak + baitira +- `git push --recurse-submodules=check/on-demand` bi estrategia dago. `check` + aldaketak pusheatu behar diren begiratzen du, eta `on-demand`-ek pusha egiten + du submodulu bakoitzean aldaketak badaude + - `git config push.recurseSubmodules check/on-demand` estrategia defektuz + konfiguratzeko + +## Submoduluen trukoak + +- `git submodule foreach <command>` egin daiteke submodule bakoitzean komando + bat executatzeko. Adibidez: `git submodule foreach 'git stash'` + +## Bundle + +Bundle-ak commitak edo repositorio osoak fitxategi baten bidez partekatzeko +sistema dira. + +- `git bundle create <file> [<commit-selector>]` aukeratutako commitak (edo + guztiak) `<file>` fitxategian gorde, bundle formatoan. Normalean, `HEAD` + sartzea komeni da, gero bundle-a kargatzean repositorioa non zegoen jakiteko. + +- `git clone <bundle-file>` bundle fitxategitik clone bat egiteko. Bundle-a + repositorio osoa izan behar du. + +- `git bundle verify <bundle-file>` bundle partzial bat repositorio batean + aplikatu daitekeen konprobatzeko + +- `git bundle list-heads <bundle-file>` bundle fitxategiaren adarrak ikusteko + +- `git fetch/pull <bundle-file>` bundle fitxategitik repositorioa + berriztatzeko + +## Replace + +Giten datu basea orokorrean ezin da aldatu, baina `git replace`-en bitartez +*replace* objektuak eratu daitezke, datu basea aldatu denaren itxura emango +dutenak. + +- `git replace <object> <replacement>` aplikatzetik aurrera, `<object>` + erabiltzean `<replacement>` erabili balitz bezala funtzionatuko du + +*Erabileren adibide bat ikusteko liburuan ikusi, nahiko arraroa da hau ikustea* + +## Kredentzial sistema + +HTTP kredentziala erabiltzean, zerbitzariarekin egiten diren interakzio +guztietan erabiltzailea eta pasahitza eskatzen du Gitek defektuz. +Portaera konfiguratu daiteke: + +- `git config --global credential.helper <modua>` + 1. Beti eskatu (defektuz egiten dena) + 2. `cache` kredentzialak memorian mantendu 15 minutu + 3. `store` kredentzialak gorde + +Aukera gehiago dago (`--timeout`, neurrira egindako kredentzial sistemak, +etab.). *Interesa balego, liburuan begiratu* + +# Git konfigurazio aurreratua + +## Git konfigurazioa + +Konfigurazioaren dokumentazioa ikusteko `git help git-config`. Atal +interesgarrienak: + +- Editorea eta paginadorea: `core.editor` eta `core.pager` +- Commit mezuen txantiloia: `commit.template` +- Merge eta diff tresnak: `merge.tool` eta `diff.tool` +- Espazio hutsen kontrola: `core.autocrlf` eta `core.whitespace` + +## Git attribute-ak — I + +Proiektuen barruan, fitxategi mailan, Giten portaera aldatzeko erabiltzen dira +atributuak (*attribute*). + +- `.gitattributes` fitxategian edo `.git/info/attributes` fitxategian, + repositorioarekin partekatu nahi ezbadira. + +Atributu fitxategia `.gitignore` fitxategiaren antzekoa da, baina lerro +bakoitzean fitxategien izenen txantiloiaz aparte haien atributuak definitu +behar dira. Askotan konfigurazio gehigarria behar da, *driver* programak +definitzeko. Ikusi `git help attributes`. + +## Git attribute-ak — II + +Atributu mota asko dago, interesgarrienetarikoak: + +- `binary` fitxategiak binario moduan identifikatzeko +- `diff=<iragazkia>` diff-a exekutatu baino lehen fitxategiak iragazki batetik + pasatzeko. Konfigurazio gehigarria behar da: + - `git config diff.<iragazkia>.textconv <programa>` + - Adibidez: `*.png diff=exif` + - `git config diff.exif.textconv exiftool` + png fitxategien estatistikak konparatzen dira, eta ez edukiak +- `ident` identifikazioa gehitzeko. `$Id$` testu literala SHA-1era bihurtzen da + espantsio baten bitartez + +## Git attribute-ak — III + +- `filter` fitxategiak iragazki batekin prozesatzeko + - `smudge` *index*etik *working directory*rako bidean + - `clean` *working directory*tik *index*erako bidean + - Adibidez: `*.c filter=indent` + - `git config filter.indent.clean indent` + `git config filter.indent.smudge cat` + fitxategiak automatikoki indentatzeko `git add` egiterakoan +- `export-ignore` artxibo (`git archive`) bat egiterakoan fitxategi batzuk + baztertzeko. +- `export-subst` artxibo bat egiterakoan `git log`-ek aplikatzen dituen + espantsioak aplikatzeko +- `merge` merge estrategiak aukeratzeko + + +## Git hooks + +Hookak gertaera garrantzitsuak gertatzen direnean exekutatzen diren programak +dira. Askotan erabiltzen dira. + +- `.git/hooks` direktorioan idazten dira, izen konkretu batekin eta exekuzio + baimenekin + +Defektuz, `git init` egiterakoan hook batzuk idazten dira, baina desaktibatuta +daude (haien izena `.sample`-n bukatzen delako). Erreferentzia moduan hartu +daitezke haien funtzionamendua ulertzeko. + + +## Bezero aldeko hookak + +Bakoitzarentzako bakarrik. **Ez dira kopiatzen repositorioarekin +batera**[^hookak-partekatu]. +Interesgarriak dira garatzaileei alertak botatzeko: testak ez direla pasatu, +formaturen bat txarto dagoela adierazteko, etab. Interesgarri batzuk: + +- `pre-commit` commit mezua idatzi baino lehen exekutatzen da, zeozer ahaztu + den konprobatzeko erabili ohi da +- `prepare-commit-msg` defektuzko commit mezua aldatzeko erabiltzaileak ikusi + baino lehen. Informazio gehigarriak sartu ahal zaio horrela, edo txantiloia + aldatu... +- `commit-msg` commit mezua aztertzen duen hooka. Txarto badago commita atzera + bota dezake. Normalean commitaren mezua txantiloi konkretu bat jarraitzeko + erabiltzen da. + +[^hookak-partekatu]: Tresna batzuek mekanismoak dauzkate hook hauek + partekatzeko, baina hau ez da Giten defektuzko funtzionamendua. Kontuz + workflow guztia honetan oinarritzearekin. + +## Zerbitzari aldeko hookak + +Politikak inposatzeko aproposak dira, txarto badoaz `push` egiteko eskaerak +atzera bota ditzaketelako. Interesgarri batzuk: + +- `pre-receive` push bat jasotzean erreferentzia guztiak jasotzen dituen + programa, errorea ematen badu ez da ezer berriztuko. +- `update` aurrekoaren antzekoa da, baina behin exekutatzen da adar bakoitzeko +- `post-receive` dena ondo jaso eta gero exekutatzen da, notifikazio moduan + erabili daiteke + + +# Git barrutik + +## Git barrutik: Sarrera + +Git maila baxuko tresna bat da, eta maila horretan lan egiteko komandoak ditu, +*plumbing* deiturikoak. Orain arte erabilitakoak *porcelain* deitzen dira, +maila altuan lan egiten dutelako. + +Git *content-addressing* aplikatzen duen datu base bat da, hau da, *Key-Value* +moduan gordetzen dira elementuak, non Key-a Valuaren edukiaren araberakoa den. +Orain arte ikusi da: elementuak haien edukiaren SHA-1 hasharen bitartez +identifikatzen dira. + +Eduki guzti hau `.git` karpetan gordetzen da. Baina elementu mota ezberdinak +daude. + +## Giten gordetzen diren elementu motak + +Bi elementu mota nagusiak daude Git datu basean: + +- Objektuak: edukiak dauzkaten elementuak dira: commitak, blobak, zuhaitzak, + etab +- Erreferentziak: beste elementuei apuntatzen duten elementuak dira: adarrak, + lightweight tagak, etab + + +## Objektuak + +`.git/objects`-en gordetzen dira, haien hasharen arabera. Lehengo bi +karaktereak direktorio moduan eta hurrengoak fitxategi moduan. +Adibidez: `.git/objects/cf/6cbb8a400c7cad0f7f93610366c3672f598cdd` + +- `git hash-object -w`-rekin idatzi daitezke (bueltan hash-a ematen du) +- `git cat-file`-ekin irakurri daitezke. `-p` egin emaitza **p**olita ikusteko. + +## Objektu motak + +`git cat-file -t`-rekin mota ikusi daiteke. + +- `blob`-ak fitxategien edukiak eta bestelako datuak gordetzeko +- `tree` fitxategien izenak eta direktorioak gordetzeko + Sarrera bat edo gehiago dute beste `tree` edo `blob`etara haien izena eta + hasha identifikatuz. +- `commit` commit datuak gordetzeko: `tree` bat snapshotarekin, mezua, autorea, + etab. + +## Objektu motak: tree + +![](img/data-model-1.png) + +## Objektu motak: commit + +![](img/data-model-3.png) + +## Erreferentziak + +Haien barruan identifikadore bat baino ez dago. + +- `git update-ref` edukia aldatzeko. Eskuz ere egin daiteke. + +Erreferentzia mota ezberdinak daude: + +- Tag-ak: `.git/refs/tag` karpetan. Edozein objetu tageatu + daiteke (normalean commitak). Bi mota dago: + - Lightweight tag: erreferentzia bat baino ez dira + - Annotated tag: tag *objektu* bat eratzen dute eta erreferentzia bat + idazten dute bertara +- Adarrak: `.git/refs/heads` karpetan. Commit-id batera erreferentzia + egiten dute. +- Remote-ak: `.git/refs/remotes` karpetan. Adarren antzerakoak baina ezin dira + aldatu. +- HEAD-a: `.git/HEAD`-en dago. Adar batera apuntatzen du, baina batzutan commit + batera apuntatu dezake (*Detached HEAD*). + +## Erreferentziak: adarrak + +![](img/data-model-4.png) + +## Ariketa: Notak + +- `git notes` komandoarekin kudeatzen dira. + +*Aztertu zer diren eta nola funtzionatzen duten. Ikusi `git help git-notes`* + +## Packfile-ak + +Datuen egitura efizienteagoa egiteko Gitek fitxategiak konprimatzen ditu, baina +hori ez da normalean nahikoa izaten. + +Git snapshotetan oinarritzen da, baina ez ditu fitxategi osoak behin eta +berriro idazten commit bakoitzean, aldaketak baino ez ditu gordetzen. + +Gainera fitxategiak taldekatu eta *packfile* deituriko fitxategietan gordetzen +ditu prozesua arintzeko. + +- `.git/objects/pack`-en ikusi daitezke +- `git gc` (*garbage collector*) fitxategiak taldekatu eta konprimatzeko (berak + bakarrik exekutatzen du beharrezkoa ikusten duenean) +- `git verify-pack` *packfile* baten edukia aztertzeko eta egiaztatzeko + +## Mantenamendua eta datuak berreskuratzea + +- `git gc --auto`-k packfileak berrorganizatzen ditu. +- `git reflog`-en HEAD-ean egindako aldaketak gordetzen dira, beraz commiten + bat galdu bada bertara salto egin daiteke, `reflog`a begiratu eta commita + berreskuratu daiteke. +- `git fsck --full` galdutako elementuak erakusten ditu, bertatik ere + datuak berreskuratu daitezke + +*ARIKETA: Fitxategi handiak nahi gabe gehitzea arazo bat da, `git rm`-k ez +dituelako ezabatzen. Nola egiten da? Zergatik?* + +## Refspec-a + +Lokalaren eta remotearen arteko adarren mapeoa kudeatzeko. `.git/config`-en +edukia `git remote add origin https://github.com/schacon/simplegit-progit` egin +eta gero: + +``` +[remote "origin"] + url = https://github.com/schacon/simplegit-progit + fetch = +refs/heads/*:refs/remotes/origin/* +``` + +`fetch` atalak **refspec** baten bitartez adarrak nola kudeatu behar diren +adierazten du. Sarrera asko egon daitezke arau ezberdinekin. Formatua: + +- Aukerako `+` bat *fast forward* ez direnean ere berrizteko +- `<iturria>:<helmuga>` nola mapeatu behar diren adierazteko. `<iturria>` + eta `<helmuga>` patroiak dira (`*`) + +## Refspec-a eskuz erabiltzen + +`git fetch/push` egitean refspec patroia (1 edo +) gehitu ahal da *"hau hona"* +eta *"beste hau hona"* esateko. + +Refspec-a ikusita, Gitek adarren adierazpenaren espantsioa egiten du: + +- `git log origin/master` + => `git log remotes/origin/master` + => `git log refs/remotes/origin/master` + +Adarrak ezabatzeko lehen refspec-a erabili behar zen: + +- `git push :<adarra>` iturri atala utzik uztean, remotean adarra ezabatzen zen +- Orain `git push --delete <adarra>` egin daiteke + |