---
title: GIT
subtitle: Sarrera eta erabilera basikoa
license: CC-BY-NC-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 [<balioa>]
```

- `<balioa>` 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 <URL>`. 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.

- `-<N>` azkeneko `<N>` commitak aurkezten ditu. `<N>` 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 <izena> <URLa>`
- `git remote show <remotearen_izena>`
- `git remote rename <izena> <izen_berria>`
- `git remote remove <izena>`


## Remotearekin informazioa elkarbanatu

- `git fetch [<remote>]`-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 [<remote> <branch>]`-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 <tagaren_izena> [<commit>]`

`git show` -k erakusten ditu.

## Lightweight tags

- `git tag <tagaren_izena> [<commit>]`

`git show`-k ez ditu erakusten, azpitik dagoen commita erakusten du.


## Tag-ak partekatzeko

- `git push [<remote>] <taga>`
- `git push [<remote>] --tags` guztiak bidaltzeko

## Tag-ak ezabatzeko

- `git tag -d <taga>`
- `git push [<remote>] --delete <taga>`

## 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 <branchname>`

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 <branchname>`
- `git checkout -b <branchname>` adarra eratu eta bertara aldatzeko

Bertsio berrietan, `checkout` komandoak gauza gehiegi egiten dituenez, komando
espezifiko bat eratu zen adarrekin lan egiteko:

- `git switch <branchname>`
- `git switch -c <branchname>` 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 <file>..." 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
<div id="footer">contact : 
    email.support@github.com</div>
=======
<div id="footer">
 please contact us at support@github.com
</div>
>>>>>>> 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 <adarra>` adarrak ezabatzeko. Mergeatu gabe dauden adarrak ez
  ditu zuzenean ezabatzen.
- `git branch --move <adarra> <izen_berria>` izenez aldatzeko.
- `git push -u|--set-upstream <remote> <adarra>` remoteari zein adar erabili behar
  duen esateko
- `git push <remote> --delete <adarra>` 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 <remote>` edo `git remote show <remote>` erabiliz remoteen
egorea ikusi daiteke.

Remoten adarrak lokalean ikusi daitezke `<remote>/<adarra>` 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 <remote> <adarra>` adarra remotera pusheatzeko. Eskuz egin behar
  da. Horrela adar lokalak babesten dira eta ez dira automatikoki igotzen.

- `<adar_lokala>:<adar_remotoa>` 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 <adar_izena> <remote>/<adar>`-k `<remote>/<adar>`
  `<adar_izena>` izenarekin *track*eatzen du
- `git checkout --track <remote>/<adar>` oraingo adarra eta remotearena
  erlazionatu. Sinpleago.
- `git checkout <adarra>`-k erlazioa eratzen du automatikoki, `<adarra>`
  lokalean existitzen ez bada. Sinpleago.
- `git clone` egiterakoan `master` adar lokala eratzen da `origin/master`
  adarra *track*eatzen.
- `git branch -u|--set-upstream-to <remote>/<adarra>` 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.