--- title: GIT — EITB 2022 subtitle: Sarrera eta erabilera basikoa 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/1.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. # Sarrera: Bertsio kontrol sistemak ## Bertsio kontrolerako sistemak `Document_v3_FINAL.pdf` --- ![Bertsio kontrol sistema zentralizatuak](img/zentralizatuak.png){ height=180px } --- ![Bertsio kontrol sistema banatuak](img/banatuak.png){ height=300px } # Git: Hasiera ## Kontestua - 2005-ean argitaratu zen - Linux garapenerako garatu zen - Milioika garatzaile - *Codebase* handiak kudeatzeko - Sistema banatua (*distributed*) da - *Snapshot*etan oinarrituta - Operazio gehienak lokalak dira eta normalean ez ditu datuak ezabatzen - Integritate kontrola egiten du SHA-1 erabiliz - Hiru egoera: `FITXATEGIA — STAGING AREA — REPOSITORIOA` ## Instalazioa Debian-en oinarritutako distribuzioetan: ``` apt-get install git ``` Beste distribuzioetan antzeko komandoren batekin egin daiteke. ## Konfigurazio sistema - Sistema mailakoa: `/etc/gitconfig` - Konfigurazio orokorra: `~/.config/git/config` edo `~/.gitconfig` - Konfigurazio lokala. Repositorio bakoitzeko: `$REPOSITORIOA/.git/config` Kaskada moduan dabil, konfigurazio lokalak orokorra zapaltzen du. Nondik datorren ikusteko: ``` git config --list --show-origin ``` ## Konfigurazioa kudeatzea Komandoek konfigurazio fitxategia irakurri edo idazten dute. Eskuz egin daiteke. Komando orokorra: ``` git config [--global] atala.klabea [] ``` - `` gehitzen ez bada konfigurazioa irakurtzen da idatzi beharrean. - `--global` konfigurazio globala kudeatzeko erabiltzen da. Benetan konplexuagoa da, laguntza begiratu. ## Hasierako konfigurazioa Identitatea definitu (beharrezkoa da commiten egilea nor den jakiteko): ``` git config --global user.name "John Doe" git config --global user.email johndoe@example.com ``` Editorea aukeratu: ``` git config --global core.editor vim ``` ## Laguntza lortzeko - `git help` - `man` # Git basikoa ## Repositorio bat lortzen Bi aukera: - Repositorio berri bat hasi: `git init`. Oraingo direktorioan `.git` direktorioa eratuko du, bertan Git-en datuak gordeko dira. - Repositorio bat klonatu: `git clone `. Oraingo direktorioan emandako repositorioa kopiatuko du, bere `.git` direktorioa barne. Protokolo ezberdinetan egin daiteke komunikazioa. ## Fitxategien egoerak ![Fitxategien egoera ezberdinak](img/lifecycle.png){ height=180px } ## Repositorioaren egoera ikusteko - `git status` - Fitxategi batzuei jaramonik ez egiteko: `.gitignore` fitxategi bat gehitu. *Glob pattern*ak erabiltzen ditu. ## Egoeraz aldatzeko - Fitxategi berriak gehitzeko: `git add` - Aldaketak *staging area*ra bidaltzeko: `git add` ## Aldaketak ikusteko - `git diff` - `git diff --cached|--staged` - `git difftool` (konfiguratuta badago) `diff` komandoaren irteera fitxategi batean gorde eta gero, beste norbaiti pasatu ahal zaio, berak bere repositoriaren kopian `git apply` erabiliz aplikatzeko. ## Aldaketak idazteko - `git commit` Mezu bat idaztea eskatzen du: `$EDITOR` edo `git config --global core.editor` programa exekutatuz. ## Fitxategiak ezabatzeko - `git rm` - `git rm --cached` ## Izenak aldatzeko - `git mv` Edo bestela fitxategia eskuz lekuz aldatu eta gero `git rm` + `git add` egin. ## Commit historia ikusteko - `git log` Oso komando konplexua da. Aukera asko ditu. - `-` azkeneko `` commitak aurkezten ditu. `` zenbaki bat izan behar da. - `-p/--patch` commit-en *patch*-a ateratzen du. - `--stat` estatistikak aurkezteko. - `--pretty` formatua aldatzeko, modu asko dauzka. - `--graph` grafiko modua. Konbinatu daitezke: `git log --graph --pretty=oneline --decorate --all` ## Commit historia iragazteko `git log`-en irteera mugatu daiteke, eskaerak eginez: - `--since` noiztik ikusi nahi diren. Adibidez: `--since=2weeks`. - `--author` autorez iragazi. - `--grep` commit mezuan *keyword*ak bilatzeko. - `-S/-G/...` *pickaxe function* deiturikoak, aldaketetan testua bilatzen dute. - `git log -- fitxategia` fitxategi horretan gertatutako aldaketak bakarrik atera. - `--no-merges` merge commitak baztertu. Laguntza ikusi: `git help log` ## Aldaketak desegiteko - `git commit --amend` azkeneko commita berridazten du. - Mezua aldatu - Fitxategiak edo aldaketak gehitu - ... - `git reset` aldaketak *staging area*tik kentzeko. KONTUZ `--hard`-ekin - `git checkout` aldaketak desegiteko eta commiteatutako egoera berreskuratzeko. KONTUZ - `git restore` komando berria da (>2.23.0) `reset` eta `checkout`-ek egiten dituzten gauzak egiten dituena, baina intuitiboagoa da. ## Remoteak Repositorioaren kopiak dira. Remoteak eguneratu daitezke repositorio lokaletik aldaketak igotzen (*push*) edo repositorio lokala eguneratu daiteke remotean dauden aldaketak ekartzen (*fetch & pull*). Remoteak beste makinetan egon daitezke, sarearen bidez sarbidea emanda, edota makina berdinean, fitxategi sistemaren beste leku batetan. ## Remote-en kudeaketa - `git remote` `.git/config` fitxategian daude idatzita. Hortik ere kudeatu daitezke. - `git clone` -k remotea automatikoki gehitzen du konfiguraziora, `origin` izenarekin. - `git remote -v` - `git remote add ` - `git remote show ` - `git remote rename ` - `git remote remove ` ## Remotearekin informazioa elkarbanatu - `git fetch []`-ek remotearen informazioa deskargatzen du, repositorioa zapaldu gabe. - `git pull`-ek informazioa deskargatu eta `merge`atzen du adarrak ondo konfiguratuta badaude: ``` git pull = git fetch + git merge ``` - `git push [ ]`-ek datuak eta commitak igotzen ditu. Norbaitek commitak erdian gehitu baditu ez du uzten (aurrerago azalduko da). ## Tag-ak Commitei jarri ahal zaizkien izenak dira, normalean *release*ak errezago identifikatzeko. Horrela, tag-en izenak erabiltzen dira *commit-id*-ak balira moduan baina guk erabakitako izenekin. Adibidez, `v1.0`. - `git tag -l` tagak bistaratzeko Bi tag mota dago: - **Lightweight**: erreferentzia bat dira. Adar finko baten modukoak - **Annotated**: Git-en datu basean objektu oso bat dira: Mezu bat daukate, autorea, sinatu daitezke... ## Annotated tags - `git tag -a []` `git show` -k erakusten ditu. ## Lightweight tags - `git tag []` `git show`-k ez ditu erakusten, azpitik dagoen commita erakusten du. ## Tag-ak partekatzeko - `git push [] ` - `git push [] --tags` guztiak bidaltzeko ## Tag-ak ezabatzeko - `git tag -d ` - `git push [] --delete ` ## Aliasak Gitek komando berriak eratzea ahalbidetzen du aliasen bitartez. Beste konfigurazio balioak bezala idazten eta irakurtzen dira: - `git config --global alias.co checkout` - `git co` => `git checkout` Nik asko erabiltzen dut: ``` git config --global alias.lg log --graph \ --decorate --all --oneline ``` # Git basikoa: Adarrak ## Adarrak (*branch*) Adarrek repositorioaren garapenean beste bide bat hartzea ahalbidetzen dute, bertan bide nagusian aldaketarik eragin gabe lan egiteko. Git adarrak erabiltzeko diseinatuta dago eta haien erabilera sustatzen du. Beraz, **oso garrantzitsuak** dira. Beste bertsio kontrol sistema batzuetan adarrak erabiltzea prozesu astuna da, errekurtso asko behar dituena. Git-en oso prozesu sinplea da eta ez du ia errekurtsorik behar. Git-en bitartez kudeatzen diren proiektuetan ez da arraroa ehundaka adar ikustea. ## Git barrutik - Fitxategiak *Staging Area*ra bidaltzean, Git-ek haien argazkiak gordetzen ditu *blob* objektu moduan eta haien checksuma kalkulatzen du (SHA-1) - Commita egiterakoan direktorio bakoitzaren checksuma kalkulatzen du eta *tree* objektu bat gordetzen du direktorio bakoitzeko. *Tree* objektuek *blob* objektuetara apuntatzen duten erreferentziak dituzte. Gainera commitek beste datuak gordetzen dituzte: autorea, mezua, data... - Commitek haien gurasoei apuntatzen duten erreferentziak dituzte: lehengo commitek erreferentziarik ez dute, commit normalek erreferentzia bakarra dute eta *merge* commitek erreferentzia asko dituzte. Adarrak commitetara apuntatzen duten erreferentzia mugikorrak dira. ## Git barrutik ![Git repositorio baten barne datuak](img/commit-and-tree.png) ## Git barrutik ![Git repositorio baten commit estruktura](img/commits-and-parents.png) ## Adarrak eratzeko - `git branch ` Defektuz `master` deitutako adar bat dago. Izena konfiguragarria da, baina gutxienez adar bat egon behar da beti, bertan commitak gehitzen direlako. Git-ek oraingo adarrera apuntatzen duen erreferentzia bat gordetzen du: `HEAD` deiturikoa. ## Adarraz aldatzeko - `git checkout ` - `git checkout -b ` adarra eratu eta bertara aldatzeko Bertsio berrietan, `checkout` komandoak gauza gehiegi egiten dituenez, komando espezifiko bat eratu zen adarrekin lan egiteko: - `git switch ` - `git switch -c ` adarra eratu eta aldatzeko - `git switch -` aurreko adarrera bueltatzeko ## Adarrak eta aldaketak — I ![`git branch testing`](img/head-to-master.png) ## Adarrak eta aldaketak — II ![`git checkout testing`](img/head-to-testing.png) ## Adarrak eta aldaketak — III ![`git commit ...`](img/advance-testing.png) ## Adarrak eta aldaketak — IV ![`git checkout master`](img/checkout-master.png) ## Adarrak eta aldaketak — V ![`git commit ...`](img/advance-master.png) ## Adarrak eta aldaketak — VI Giten interfazetik ikusita: ``` $ git log --oneline --decorate --graph --all * c2b9e (HEAD, master) Made other changes | * 87ab2 (testing) Made a change |/ * f30ab Add feature #32 * 34ac2 Fix bug #1328 * 98ca9 initial commit ``` > KONTUZ: Ez bada `--all` egiten ez dira defektuz adar guztiak bistaratzen `git > log`-en bitartez. ## Adarrak eta mergeak — I ![](img/basic-branching-4.png){ height=180px } ## Adarrak eta mergeak — II **Fast forward** kasua. Adar bat bestearen barruan dago. ![`git checkout master` `git merge hotfix`](img/basic-branching-5.png){ height=200px } ## Adarrak eta mergeak — III Beti ez da hain erreza. Demagun: ![](img/basic-branching-6.png){ height=180px } ## Adarrak eta mergeak — IV Arbaso amankomuna (*common ancestor*) ateratzen saiatzen da eta bi buruekin eta arbaso amankomunarekin *three-way merge* bat egiten du. ![`git checkout master` `git merge iss53`](img/basic-merging-1.png){ height=180px } ## Adarrak eta mergeak — V Commit berri bat gehitzen du, bi adarrak lotzen dituena. *Merge* commita da: bi guraso (edo gehiago) ditu. ![`git checkout master` `git merge iss53`](img/basic-merging-2.png){ height=180px } ## Konfliktoak — I Aurreko kasua ez da beti ondo ateratzen, batzuetan konfliktoak egon daitezke bi adarretan aldaketak leku berdinetan agertzen direnean: ``` $ git merge iss53 Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result. ``` ## Konfliktoak — II ``` $ git status On branch master You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: (use "git add ..." to mark resolution) both modified: index.html no changes added to commit (use "git add" and/or "git commit -a") ``` ## Konfliktoak — III Fitxategia horrela ikusten da: ``` <<<<<<< HEAD:index.html ======= >>>>>>> iss53:index.html ``` Separadoreak daude `<<<<<<<`, `=======` eta `>>>>>>>`. Lehenengo zatian `HEAD`-en zegoena dago eta bigarrenean `iss53`-n zegoena. `git mergetool` erabili daiteke konfliktoak errazago konpontzeko. ## Adarrak kudeatzeko - `git branch` adarrak listatzeko - `git branch --merged | --no-merged` oraingo adarrarekin mergeatuta edo mergeatu gabe dauden adarrak listatzeko - `git branch -d ` adarrak ezabatzeko. Mergeatu gabe dauden adarrak ez ditu zuzenean ezabatzen. - `git branch --move ` izenez aldatzeko. - `git push -u|--set-upstream ` remoteari zein adar erabili behar duen esateko - `git push --delete ` remotean adar bat ezabatzeko ## Adarrekin workflow ezberdinak - Long running branches: `master`, `testing` eta `development` - Topic branches: issue eta feature bakoitzeko adar berri bat eratzen da. ## Adarrak remotetan Gitek remoten erreferentziak gordetzen ditu remoten egoera ikusi ahal izateko. `git ls-remote ` edo `git remote show ` erabiliz remoteen egorea ikusi daiteke. Remoten adarrak lokalean ikusi daitezke `/` izenarekin. Ezin dira aldatu. Push egiterakoan aldatzen dira, remotearen egoera aldatu delako. ![Adibidea: repositorio lokalak bi commit berri ditu](img/remote-branches.png) ## Push egitea - `git push ` adarra remotera pusheatzeko. Eskuz egin behar da. Horrela adar lokalak babesten dira eta ez dira automatikoki igotzen. - `:` erabiltzean izen ezberdinak jarri ahal zaizkie adarrei, bata lokalean eta bestea remotean ## Tracking branches Remoteak jarraitzeko erabiltzen mekanismoa da. Remotearen adar bat (*upstream*) adar lokal baten (*tracking*) arteko erlazioa da. - `git checkout -b /`-k `/` `` izenarekin *track*eatzen du - `git checkout --track /` oraingo adarra eta remotearena erlazionatu. Sinpleago. - `git checkout `-k erlazioa eratzen du automatikoki, `` lokalean existitzen ez bada. Sinpleago. - `git clone` egiterakoan `master` adar lokala eratzen da `origin/master` adarra *track*eatzen. - `git branch -u|--set-upstream /` zure adarraren upstream-a aldatzeko. Ikusi `git push`-en. > `@{upstream}` edo `@{u}` idatzi daiteke hortik aurrera remotearen adarraren > izen osoa erabili beharrean ## Pull egitea Tracking adarra aktibatuta badago, `git pull` egiteak zuzenean `git fetch` eta `git merge` aldi berean egingo ditu. Kontuz ibili: batzuetan `git pull`-en magia ulertzeko zaila izan daiteke. Proiektua jende askok ukitzen badu, hobe `git fetch` egitea. ## Adarrak eta rebaseak — I ![](img/basic-rebase-1.png) ## Adarrak eta rebaseak — II ![`git merge` egitean gertatzen dena](img/basic-rebase-2.png) ## Adarrak eta rebaseak — II ![`git checkout experiment` `git rebase master`](img/basic-rebase-3.png) Orain merge-a *fast-forward* izango da eta ez du merge commit-ik gehituko. ## Rebase konplexuago bat — I ![](img/interesting-rebase-1.png) ## Rebase konplexuago bat — II ![`git rebase --onto master server client`](img/interesting-rebase-2.png) `client`-en dauden aldaketak pasatzen ditu `master`-era `server`-en daudenak izan ezik. Orain `server` `master`-en rebaseatu daiteke eta gero `git merge` *fast-forward* bat egin. ## Rebasekin kontuz ibili Rebaseak egiterakoan commit berriak egiten dira, aurrekoen antzekoak edukiz, ez dira berdinak. Remote-an pusheatzerakoan beste lankideek rebaseak egitera behartzen ditu: - `git push --force` remotean historia berridazten du. Git zerbitzuetan adar babestuak existitzen dira hau saihesteko. Kontuz. - `git pull --rebase`-k lagundu dezake `pull` egiterakoan, remotean historia berridatzi bada. Pull-en estrategietako bat da, asko daude eta defektuz egiteko konfiguratu daitezke. ## Rebase vs Merge Filosofiaren arabera bata edo bestea gehiago erabiltzea komeni da: - Repositorioa historiko moduan ulertuta: rebase egitea txarra izango litzateke, historikoa zapaltzen baitu. (*fossil-ek filosofia hau jarraitzen du, ez dauka rebase egiteko tresnarik*) - Repositorioa *making of* modura ikusten bada aproposa da rebase egitea. Historikoa garbiagoa uzten duelako. Aholkua: lokalean rebase egin commit historikoa garbitzeko baina behin zerbitzarira igota historia ez aldatu, lankideen prozesuan eragina baitu.