diff options
Diffstat (limited to 'es/1.md')
-rw-r--r-- | es/1.md | 610 |
1 files changed, 610 insertions, 0 deletions
@@ -0,0 +1,610 @@ +--- +title: GIT +subtitle: Introducción y uso básico +license: CC-BY-NC-SA 4.0 +author: Ekaitz Zarraga - ElenQ Technology +links-as-notes: true +lang: spanish +polyglossia-lang: + name: spanish +how-to: pandoc -f markdown+smart -t beamer % -o pdf/1.pdf --pdf-engine=xelatex --template=./template.tex +... + +## Licencia + +- CC-BY-SA 4.0 +- El contenido del documento ha sido adaptado de [**Pro Git (Scott Chacon, Ben + Straub)**](https://git-scm.com/book/en/v2). + +# Introducción: sistemas de control de versiones + +## Sistemas de control de versiones + +`Document_v3_FINAL.pdf` + +--- + +![Centralizados](img/zentralizatuak.png){ height=180px } + +--- + +![Descentralizados](img/banatuak.png){ height=300px } + +# Git: Introducción + +## Contexto + +- 2005 +- Para el desarrollo de Linux + - Miles de desarrolladores + - Código fuente muy extenso +- Es distribuído (*distributed*) +- Se basa en *snapshots* +- La mayoría de las operaciones ocurren en local y no son destructivas +- Control de integridad mediante SHA-1 (o SHA-256) +- Tres estados:\ + `ARCHIVO — STAGING AREA — REPOSITORIO` + +## Instalación + +Debian: + +``` +apt-get install git +``` + +En el resto de distros es similar. + +## Sistema de configuración + +- Sistema: `/etc/gitconfig` +- Configuración general: `~/.config/git/config` o `~/.gitconfig` +- Local por repositorio: `$REPOSITORIO/.git/config` + +Funciona en modo cascada, de local a sistema. Para ver de dónde se toman los +valores: + +``` +git config --list --show-origin +``` + +## Gestión de configuración + +Los comandos leen y escriben los archivos de configuración de forma ordenada, +aunque se puede hacer a mano: + +``` +git config [--global] <SECTION>.<KEY> [<VALUE>] +``` + +- El `<VALUE>` es opcional. Si se usa, se escribe la configuración con ese + valor. Si no se usa, se devuelve el valor en esa línea de la configuración. + +Realmente es más complejo que esto: ver documentación. + +## Configuración inicial + +Definir la identidad para que se registre el autor de los commits: + +``` +git config --global user.name "John Doe" +git config --global user.email johndoe@example.com +``` + +Seleccionar editor de texto por defecto: + +``` +git config --global core.editor vim +``` + +## Ayuda + +- `git help` +- `man` + + + + +# Git basico + +## Obtener un repositorio + +Dos alternativas: + +- Crear un repositorio nuevo: `git init`. Esta opción crea un directorio `.git` + en el directorio actual, donde se almacenará la información interna de Git. + +- Clonar un repositorio existente: `git clone <URL>`. Esta opción copia el + repositorio en el directorio actual, incluyendo su `.git`. Puede usar varios + protocolos diferentes + + +## Estados de un archivo + +![Ciclo de vida de los archivos](img/lifecycle.png){ height=180px } + + +## Visualizar estado de un repositorio + +- `git status` +- Para ignorar archivos, añadirlos a un archivo `.gitignore`. + Utiliza *glob pattern*s. + +## Para cambiar de estado + +- Añadir archivos con: `git add` +- Para enviar los cambios al *staging area*: `git add` + +## Para ver cambios + +- `git diff` +- `git diff --cached|--staged` +- `git difftool` (si está configurada) + +La salida de `git diff` puede guardarse a archivo y después aplicarse sobre el +repositorio mediante `git apply`. + + +## Para escribir los cambios + +- `git commit` + +Pide rellenar un mensaje mediante el `$EDITOR` o el `git config --global +core.editor` + + +## Borrar archivos + +- `git rm` +- `git rm --cached` + +## Renombrar + +- `git mv` + +Equivalente a `git rm` + `git add`. + + +## Para ver la historia + +- `git log` + +Es un comando muy complejo. + +- `-<N>` Muestra los últimos N commits. +- `-p/--patch` muestra el *patch*. +- `--stat` muestra estadísticas. +- `--pretty` cambia el formato de salida, tiene muchas opciones. +- `--graph` modo gráfico. + +Se pueden combinar: + +`git log --graph --pretty=oneline --decorate --all` + + +## Filtrar la historia + +La salida de `git log` puede filtrarse: + +- `--since` desde cuando, por ejemplo: `--since=2weeks` +- `--author` filtrar por autor +- `--grep` búsqueda por palabras clave +- `-S/-G/...` *pickaxe function*s, buscan palabras en los cambios aplicados en + el commit. +- `git log -- archivo` mostrar commits que afectaron a ese archivo. +- `--no-merges` descartar commits de tipo *merge* + +Ver la ayuda: `git help log` + + +## Deshacer cambios + +- `git commit --amend` reescribe el último commit + - Cambiar el mensaje + - Añadir o quitar archivos + - ... + +- `git reset` quita cambios de la *staging area*. CUIDADO con `--hard`. +- `git checkout` para deshacer los cambios. CUIDADO +- `git restore` comando nuevo (>2.23.0), parecido a los anteriores. + +Los comandos `reset` y `checkout` son parte integral de Git y realizan más +acciones que las que se acaban de mencionar. Se estudian más adelante en +detalle. + +## Remotos (*remote*) + +Son copias de un repositorio. Se pueden actualizar enviándoles cambios locales +mediante *push* o se pueden descargar cambios desde ellos para actualizar el +repositorio local mediante *fetch* y *pull*. + +Pueden ubicarse en otras máquinas y accederse mediante la red, en otras partes +del mismo disco duro, etc. + +## Gestión de remotos + +- `git remote` + +Están escritos en `.git/config`. También pueden editarse a mano. No se +recomienda hacerlo. + + +- `git clone` añade el remoto llamado `origin` automáticamente, apuntando al + repositorio del que se clonó. +- `git remote -v` +- `git remote add <nombre> <URL>` +- `git remote show <nombre>` +- `git remote rename <nombre> <nuevo nombre>` +- `git remote remove <nombre>` + +## Intercambiar información con el remoto + + +- `git fetch [<remote>]` descarga la información del remoto sin alterar el + repositorio local. + +- `git pull` aplica un `fetch` seguido de un `merge` si las ramas están + configuradas correctamente:\ + ``` + git pull = git fetch + git merge + ``` + +- `git push [<remote> <branch>]` sube los cambios al remoto de forma segura. En + caso de conflicto los rechaza. + + +## Etiquetas (*tag*) + +Nombres que se les pueden asignar a los commits. Sirven para identificar los +commits con nombres fáciles de recordar, son útiles para señalar *releases*. + +- `git tag -l` muestra las etiquetas + +Hay dos tipos de etiquetas: + +- **Lightweight**: son referencias, como una rama fija. Sólo son un + identificador. +- **Annotated**: son un objeto más en Git, como un commit, y pueden tener + autor, firma, mensaje, etc. + +## Annotated tags + +- `git tag -a <nombre> [<commit>]` + +Se muestran en `git show`. + +## Lightweight tags + +- `git tag <nombre> [<commit>]` + +`git show` no las muestra, sino que muestra el commit al que hacen referencia. + +## Compartir tags + +- `git push [<remote>] <tag>` +- `git push [<remote>] --tags` para enviar todos + +## Eliminar tags + +- `git tag -d <tag>` +- `git push [<remote>] --delete <tag>` + + +## Aliases + +Permiten escribir nuevos comandos usando los que ya están disponibles en Git +como base. Son valores de la configuración: + +- `git config --global alias.co checkout` +- `git co` => `git checkout` + +Yo uso mucho: + +``` +git config --global alias.lg log --graph \ + --decorate --all --oneline +``` + + + +# Git básico: Ramas + +## Rama (*branch*) + +Las ramas permiten al desarrollo del repositorio tomar diferentes caminos sin +alterar el desarrollo principal. + +En Git las ramas son fundamentales, ya que está diseñado alrededor de éstas. + +En otros sistemas de control de versiones el uso de ramas es pesado, pero en +Git es muy ligero y no es raro ver repositorios con cientos de ramas distintas. + +## Git por dentro + +- Cuando los archivos se mandan al *staging area* Git guarda sus contenidos en + un *blob* y calcula su *checksum* (SHA-1) +- Cuando se aplica un commit, calcula los checksums de todos los directorios y + construye un objeto *tree* por cada uno de ellos. Los objetos *tree* apuntan + a los objetos *blob* indicando su nombre, y formando la estructura de + archivos. El *tree* principal se añade al commit, junto con el autor, fecha, + mensaje y otros datos. Se almacena el objeto *commit* resultante. +- Los *commit* hacen referencia a sus *commit* padre. Los commits "normales" + tienen un único padre, los commits de tipo *merge* tienen varios padres y el + commit inicial no tiene padre. + +Las ramas son referencias móviles que apuntan a los *commits*. + +## Git por dentro + +![Datos internos](img/commit-and-tree.png) + +## Git por dentro + +![Estructura de commits](img/commits-and-parents.png) + +## Crear ramas + +- `git branch <branchname>` + +Por defecto hay una rama llamada `master` (puede configurarse), y siempre debe +haber al menos una rama, donde se irán añadiendo los commits nuevos. + +Git guarda una referencia que apunta a la rama actual: `HEAD` + +## Cambiar de rama + +- `git checkout <branchname>` +- `git checkout -b <branchname>` crear rama y saltar a ella + +Como `checkout` es un comando complejo se ha añadido el comando `switch` que +cumple esta tarea de forma más clara: + +- `git switch <branchname>` +- `git switch -c <branchname>` crear rama y saltar a ella +- `git switch -` saltar a la rama anterior + + +## Ramas y cambios — I + +![`git branch testing`](img/head-to-master.png) + +## Ramas y cambios — II + +![`git checkout testing`](img/head-to-testing.png) + +## Ramas y cambios — III + +![`git commit ...`](img/advance-testing.png) + +## Ramas y cambios — IV + +![`git checkout master`](img/checkout-master.png) + +## Ramas y cambios — V + +![`git commit ...`](img/advance-master.png) + +## Ramas y cambios — VI + +Visto desde la interfaz de Git: + +``` +$ 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 +``` + +> CUIDADO: Si no se añade `--all` no se muestran todas las ramas al hacer `git +> log`, sino que sólo se muestra la rama actual. + + +## Ramas y merges — I + +![](img/basic-branching-4.png){ height=180px } + +## Ramas y merges — II + +Caso **fast forward**, una rama contiene la otra + +![`git checkout master`\ +`git merge hotfix`](img/basic-branching-5.png){ height=200px } + +## Ramas y merges — III + +Siempre no es así de fácil: + +![](img/basic-branching-6.png){ height=180px } + +## Ramas y merges — IV + +Se busca el ancestro común (*common ancestor*) y se aplica un *three-way +merge*. + +![`git checkout master`\ +`git merge iss53`](img/basic-merging-1.png){ height=180px } + +## Ramas y merges — V + +Crea un commit nuevo que combina ambas ramas. + +Es un *Merge*: tiene al menos dos padres. + +![`git checkout master`\ +`git merge iss53`](img/basic-merging-2.png){ height=180px } + + +## Conflictos — I + +El caso de antes no siempre sale bien. Es posible que haya un conflicto si se +han editado los mismos archivos en las dos ramas. + +``` +$ git merge iss53 +Auto-merging index.html +CONFLICT (content): Merge conflict in index.html +Automatic merge failed; fix conflicts and then +commit the result. +``` + +## Conflictos — 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") +``` + +## Conflictos — III + +El archivo se ve así: + +``` +<<<<<<< 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 +``` + +Aparecen unos separadores: `<<<<<<<`, `=======` y `>>>>>>>`. + +En el primer trozo aparece el contenido del `HEAD` y en el segundo `iss53`. + +Si está configurada una herramienta, puede usarse `git mergetool` + + +## Gestión de ramas + +- `git branch` muestra las ramas +- `git branch --merged | --no-merged` muestra las ramas mergeadas o las no + mergeadas con la actual. +- `git branch -d <adarra>` borra ramas. Las no-mergeadas no las borra, hay que + hacer `-D` para eso (diferencia mayúsculas y minúsculas). +- `git branch --move <adarra> <rama_nueva>` cambiar nombre de rama +- `git push -u|--set-upstream <remote> <adarra>` asigna una rama a un remoto +- `git push <remote> --delete <adarra>` borra una rama en un remoto + +## Workflows habituales + +- *Long-running branches*: `master`, `testing` y `development` +- *Topic branches*: por cada issue o feature se trabaja en una rama + independiente. + +## Ramas en los remotos + +Git guarda referencias a los remotos para poder ver su estado (`git ls-remote +<remote>` o `git remote show` para verlo). + +Las ramas en los remotos pueden verse con el nombre `<remoto>/<rama>`. No son +ramas normales, sino que se muestran como tal. La diferencia es que estas ramas +no se pueden alterar de forma directa. La forma de manipularlas es hacer +cambios en el remoto, para que éstos se reflejen en la rama. + +![Ejemplo: el repositorio local tiene dos commits nuevos](img/remote-branches.png) + +## Hacer push + +- `git push <remote> <branch>` envía la rama al remoto. Hay que hacerlo + manualmente para no subir más que la rama que se quería. Facilitando el uso + de ramas locales. + +- `<rama-local>:<rama-remota>` para usar diferente nombre en local que en el + remoto. + +## Tracking branches + +Es una forma de relacionar una rama remota (*upstream*) y una local +(*tracking*): + +- `git checkout -b <rama> <remote>/<rama>` relaciona `<remote>/<rama>` con + `<rama>` +- `git checkout --track <remote>/<rama>` relaciona la rama actual con la + remota. +- `git checkout <rama>` si la rama local `<rama>` no existe, se crea + relacionada con `<remoto>/<rama>` automáticamente. +- `git clone` crea una rama local relacionada con la remota automáticamente. +- `git branch -u|--set-upstream-to <remote>/<adarra>` también relaciona las + ramas. Ver `git push` + +> Una vez relacionadas, para referirse a la rama remota puede usarse +> `@{upstream}` o `@{u}` + +## Hacer pull + +Si hay una rama de tracking configurada, hacer `git pull` es equivalente a +hacer `git fetch` seguido de un `git merge`. + +Cuidado: a veces es difícil ver qué ocurre con el `merge`. Para evitar +problemas, hacer `fetch`, ver el estado del repositorio y hacer el `merge` +manualmente. + + +## Ramas y rebases — I + +![](img/basic-rebase-1.png) + +## Ramas y rebases — II + +![Al hacer `git merge` pasa esto](img/basic-rebase-2.png) + +## Ramas y rebases — II + +![`git checkout experiment`\ +`git rebase master`](img/basic-rebase-3.png) + +Ahora el merge es *fast-forward* y no añade commit de merge. + + +## Un rebase más complejo — I + +![](img/interesting-rebase-1.png) + +## Un rebase más complejo — II + +![`git rebase --onto master server client`](img/interesting-rebase-2.png) + +Pasa los cambios de `client` a `master` sin incluir los de `server`. + +Ahora se puede hacer un rebase de `server` en `master` y después hacer un +`merge` *fast-forward*. + +## Cuidado con los rebase + +Al hacer rebase, se crean commits nuevos con contenidos similares a los que +había anteriormente, pero con diferente valor. Al enviarlos a un remoto +(`push`) se fuerza al resto de nuestro equipo a hacer rebases: + +- `git push --force` reescribe la historia en el remoto. Es peligroso. +- `git pull --rebase` puede ayudar a la hora de hacer pull de un repositorio en + el que hayan ocurrido rebases. Se puede configurar Git para que siempre se + comporte así en el pull. + +## Rebase vs Merge + +En función de la filosofía con la que se trabaje es interesante usar uno u +otro. + +- Si se entiende el repositorio como un histórico de cambios el *rebase* no + tiene sentido, porque puede manipular el pasado. (*El sistema de control de + versiones fossil usa esta filosofía, y no tiene forma de hacer rebases*) +- Si se entiende el repositorio como un *making-of*, tiene sentido aplicar + rebases, porque limpian la historia haciéndola más fácil de leer. + +Consejo: En local todo vale. En el servidor compartido cambiar la historia es +peligroso porque afecta al equipo de desarrollo, usuarios, etc. |