Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Git introduction

Git introduction

An introduction to Git in spanish

Xabier Larrakoetxea

July 23, 2012
Tweet

More Decks by Xabier Larrakoetxea

Other Decks in Technology

Transcript

  1. Índice • Introducción • Teoría Git • Git básico •

    Git intermedio • Github • Git avanzado
  2. Qué es •Wikipedia: Git es un software de control de

    versiones diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente. •Página oficial: Git es un software libre y gratuito. Se trata de un sistema de control de versiones distribuido diseñado para manejar todo, desde pequeños proyectos a proyectos muy grandes con velocidad y eficiencia.
  3. Quién lo usa •Linux •KDE •Android •Ruby on Rails •Eclipse

    •Gnome •Postgres •Twitter •Blizzard •Facebook •RedHat •Microsoft •Linked In •Yahoo •VMWare •RackSpace •...
  4. Quién lo usa •Blizzard •Facebook •RedHat •Microsoft •Linked In •Yahoo

    •VMWare •RackSpace •... •Linux •KDE •Android •Ruby on Rails •Eclipse •Gnome •Postgres •Twitter
  5. Pro Git ProGit es un libro escrito por Scott Chacon

    (empleado de Github). Es muy completo y casi toda la presentación está basada en el. Se puede adquirir en: • Book depository: http://www.bookdepository.com/Pro-Git-Scott- Chacon/9781430218333 • Amazon: http://www.amazon.com/gp/product/1430218339 El libro es libre y está bajo CC BY-NC-SA 3.0. Asimismo, también se puede descargar de: http://git-scm.com/book
  6. Teoría git • Distribuido/centralizado • Diferencias/snapshots • Varios datos •

    Zona • Estados • Tipos de archivos • Protocolos • Instalación
  7. Distribuido VS Centralizado • Distribuido (todos tienen repositorio propio. Copia

    del repositorio remoto o común). • Ejemplos: Git, Mercurial, Bazaar...
  8. Diferencias VS Snapshots Git no guarda diferencias. Guarda archivos/ficheros completos

    (los no actualizados/modificados no los guarda, sólo los referencia para optimizar).
  9. Varios datos Git •Al contrario que muchos otros SCV son

    (casi) todo operaciones locales. •Tiene integridad muy fuerte gracias a SHA1. Git lleva el control del checksum SHA1 de cada archivo, commit... •Git prácticamente se basa en "el añadido". Casi nunca borra nada, por tanto, todo queda registrado y todo es recuperable.
  10. Las 3 zonas de Git En local, Git se basa

    en "3 zonas". Existe un área intermedia antes del commit que otros SCV no tienen.
  11. Las 3 Zonas de Git •Lugar de trabajo: Donde trabajamos

    (hacemos cambios). •Area intermedia (Staging area): Donde estarán los cambios que irán en el commit (hacemos que Git haga un seguimiento de los archivos antes de confirmar). •Area confirmada: Una vez hecho el commit, tenemos el repositorio con una revisión nueva y por tanto, pasaremos automaticamente a "Lugar de trabajo" para hacer el siguiente ciclo.
  12. Los 3 estados de Git Ya hemos hablado de las

    3 zonas. Ahora hablaremos de los 3 estados existentes en Git (1 por zona). • Commited: sin cambio o confirmado (zona 1 y 3). • Modificado: con cambios (zona 1,5) antes del staging area. • Staged: preparado para commit (tracked by Git). Una vez hecho commit estaríamos en "commited". (Zona 2)
  13. El + 1 estado de Git ¡Se nos olvida un

    estado! Git no sabe qué ficheros existen en el repositorio hasta que se añaden (la primera vez sólo).
  14. Staging Area La Staging Area es muy importante y es

    lo que hace especial a Git. Cuando metemos algo en la Staging Area, es como si se guardase una foto de las modificaciones realizadas. Podemos seguir modificando ese mismo archivo y si queremos meter los cambios de ese mismo fichero en la staging area otra vez, podremos hacerlo, con lo que se sobreescribirá el punto de control anterior de ese mismo fichero. Cuando estemos satisfechos con los cambios haremos el commit. Por tanto, son como puntos de control que ponemos a nuestros ficheros antes de hacer commit.
  15. Los 4 estados de Git Recapitulando: •4 estados •Untracked (Sólo

    la primera vez): Para añadir archivos a Git (para que les siga la pista) y una vez borrados del repo. •Unmodified: Sin modificación. Después de un commit (nueva revisión-> reseteo de cambios). •Modified: Archivos modificados. •Staged: Preparados para la confirmación de revisión (commit).
  16. Tipos de archivos en Git Git tiene 5 tipos de

    achivos: • Object: Unidad de almacenamiento SHA1 -> inmutable. • Commit (Metadatos, tree...): Contiene información de la revisión. • Tag: Identifica otros objetos de Git. • Tree: Referencia blob, permisos... • Blob: Un fichero.
  17. Protocolos Git • Local ◦ Pros: Cómodo y simple. ◦

    Cons: Compartición difícil, no necesariamente rápido. • SSH (el más común) ◦ Pros: Seguro, rápido, eficiente, común. ◦ Cons:No tiene acceso anónimo. • Git ◦ Pros: El más rápido. ◦ Cons: Sin autenticación. • HTTP/S ◦ Pros: Fácil de poner, "anti firewalls". ◦ Cons: Lento. Solución: poner más de un protocolo, por ejemplo HTTP+SSH.
  18. Instalación •GNU/Linux: ◦Suele venir por defecto en la mayoria de

    distros. ◦Si no viene, usar el gestor de paquetes correspondiente. ◦Si no, compilarlo! :D •Windows: ◦Descargar: http://code.google.com/p/msysgit/downloads ◦Usar OpenSSH como opción. •Mac: ◦Viene por defecto en Mac OS X. ◦Si no, descargarlo: http://code.google.com/p/git-osx-installer/downloads
  19. Git básico •Configuración •Inicialización de repositorios •Operaciones ficheros •Tracking de

    archivos •Gitignore •Commit •Estado del repositorio •Recuperación
  20. Configuración Existen 3 tipos de niveles de configuración en Git

    • De sistema: --system ◦ Para todos los usuarios ◦ Archivo: "/etc/gitconfig" • De usuario: --global ◦ Por usuario ◦ El más usado ◦ Archivo: "~/.gitconfig" • De repositorio ◦ Por repositorio ◦ Diferente configuración por repo ◦ Archivo: "$GIT_REPO/.git/config" Una vez configurado "no hace falta configurarlo nunca más". Podemos configurar de todo. Desde usuario y email, hasta el editor de mensajes de commit, de diffs...
  21. git config $ git config --global user.name "Xabier Larrakoetxea" $

    git config --global user.email [email protected] Para configurar se usa git config. Ejemplos comunes: Configurar identidad del commiter (¡IMPORTANTE!): Configurar coloreado de sintaxis (Aconsejable): $ git config --global color.ui true Listar configuración: $ git config --list user.name=Xabier Larrakoetxea [email protected] color.ui=true
  22. git init & git clone Inicializar repositorio (vacio por defecto)

    con git init: $ mkdir ./my-repo && cd ./my-repo $ git init Initialized empty Git repository in /home/slok/my-repo/.git/ Clonar repositorio HTTPs (existente) con git clone: $ git clone https://[email protected]/slok/xlarrakoetxeaorg.git Cloning into xlarrakoetxeaorg... Password: remote: Counting objects: 712, done. remote: Compressing objects: 100% (504/504), done. remote: Total 712 (delta 437), reused 434 (delta 159) Receiving objects: 100% (712/712), 337.24 KiB | 243 KiB/s, done. Resolving deltas: 100% (437/437), done.
  23. --bare Existen dos tipos de repositorio: • Normal: Repositorio de

    trabajo normal. El típico • Bare: Un repositorio bare es un repositorio para servir (por ejemplo los repos alojados en github a los que accedemos son bare). Normalmente no usaremos nada de bare, ya que el repo remoto( p.e. github) es transparente a nosotros. Para crear un repositorio bare lo que haremos será git init --bare y para clonar un repo normal en forma de bare haremos git clone --bare XXXXXXX $ git init --bare bare_repo Initialized empty Git repository in /tmp/bare_repo/ $ ls ./bare_repo/ branches config description HEAD hooks info objects refs
  24. Práctica (configuración) • Crear repositorio: repo_test • Inicializar repositorio •

    Configurar Nombre • Configurar Email • Configurar Colores
  25. Operaciones sobre ficheros El flujo de datos en Git es

    simple. Tenemos 3 operaciones principalmente para manipular ficheros: • Añadir un archivo al repositorio Git (Git a partir de ahora podrá seguirle la pista -> Tracked). $ git add ./README • Borrar un archivo del repositorio Git (Git ya no podrá seguirle la pista -> Untracked). $ git rm ./README • Mover un archivo del repositorio Git (Git ya le llevaba la pista y se la sigue llevando). $ git mv ./README ./README2
  26. Tracking de archivos (git add) Comenzamos por crear un fichero

    en el repositorio. A primera vista, Git no le sigue la pista, por tanto, si hacemos cambios Git no sabrá si ha sido modificado o no. $ git status # On branch master # # Initial commit # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # README nothing added to commit but untracked files present (use "git add" to track) Lo añadimos con git add y vemos como ahora Git sabe que existe. $ git add ./README $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: README #
  27. Tracking de archivos (git add) Despues del commit tenemos nuestro

    repositorio sin cambios. Pero ahora Git (al contrario que antes) ya puede seguirle la pista al archivo README si hacemos algun cambio. $ git commit -m "First commit" [master (root-commit) cfd9056] First commit 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 README $ git status # On branch master nothing to commit (working directory clean) Una vez modificado el archivo Git sabe si ese archivo ha sido modificado. Por tanto, el git add "sólo" se hace la primera vez que metemos el archivo en el repositorio (o lo creamos). $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a")
  28. Tracking de archivos (git add) Al no ser automático no

    añadiremos por error archivos de compilación, archivos del sistema operativo... Por tanto, estamos obligados a añadir cada archivo manualmente. Podemos añadir varios archivos a la vez o incluso directorios enteros. $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # archivo1.txt # archivo2.txt # archivo3.txt nothing added to commit but untracked files present (use "git add" to track $ git add . $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: archivo1.txt # new file: archivo2.txt # new file: archivo3.txt #
  29. Tracking de archivos (git add) Además de añadir archivos, git

    add también vale para meter los cambios a "commitear" en la Staging Area. En este ejemplo, Git ya le sigue la pista al archivo README y vemos que sabe que ha sido modificado. Una vez hecho el "add" Git estará preparado para hacer commit. $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a") $ git add ./README $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: README #
  30. Tracking de archivos (git add) Despues de que un archivo

    este "staged" (preparado para ser commiteado por Git) si se modifica otra vez, estaría como modified y si hacemos commit en ese momento, sólo se metería en el commit los cambios que estén en el stage. Por tanto, los cambios que había en el archivo despues de haberlo metido en el Staging Area seguirán como "modified". $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # README2 nothing added to commit but untracked files present (use "git add" to track) $ git add ./README2 $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: README2 # $ echo "prueba" >> ./README2 $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: README2 # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README2 #
  31. Tracking de archivos (git rm) Si por el contrario queremos

    eliminar un archivo usamos git rm. $ ls archivo1.txt archivo2.txt archivo3.txt README $ git rm ./README rm 'README' $ ls archivo1.txt archivo2.txt archivo3.txt Para que el cambio sea permanente tenemos que hacer git commit. $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: README # $ git commit -m "Deleted README" [master 2eadd8f] Deleted README 1 files changed, 0 insertions(+), 2 deletions(-) delete mode 100644 README $ ls archivo1.txt archivo2.txt archivo3.txt
  32. Tracking de archivos (git mv) Para mover archivos (mover físicamente

    o renombrar) usaremos git mv. $ git mv ./README ./README.txt $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # renamed: README -> README.txt # $ git commit -m "Renamed README" [master 546d0b0] Renamed README 1 files changed, 0 insertions(+), 0 deletions(-) rename README => README.txt (100%)
  33. Práctica (operaciones básicas) • Crear un archivo en el repositorio

    llamado: readme.txt • Añadirlo a la staging area • Commit [más tarde lo veremos mejor] • Renombrar el fichero: README.md • Commit • Borrar el fichero • Commit
  34. Gitignore Gitignore es un archivo usado para que Git pase

    por alto archivos, directorios... con una sintaxis concreta. Para ello hace uso de expresiones regulares. Repositorio con muchos Gitignore comunes: https://github.com/github/gitignore El archivo .gitignore se puede poner en cualquier directorio (comunmente en la raiz del proyecto) y los directorios inferiores sobrescribirán los de los superiores. También suele meterse un .gitignore en las carpetas vacias para que Git las tome en cuenta ya que si hacemos git add de una carpeta vacía Git no lo mete en el commit por estar vacía. *.class # Package Files # *.jar *.war *.ear A continuación se muestra el Contenido de un gitignore común de Java que pasa por alto ficheros con terminación class, war, ear y jar:
  35. Gitignore Como ejemplo, vamos a usar un gitignore que ignore

    los archivos de Python *. pyc y *.pyo: $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # test.py # test.pyc # test.pyo nothing added to commit but untracked files present (use "git add" to track) Una vez puesto el archivo .gitignore en la raiz del repositorio (sin hacer add), es usado automaticamente y como se ve, ignora los archivos con terminación . pyc y .pyo $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # .gitignore # test.py nothing added to commit but untracked files present (use "git add" to track)
  36. git status git status nos saca información sobre el estado

    de nuestro repositorio como por ejemplo, archivos nuevos, modificados, movidos... $ git status # On branch master nothing to commit (working directory clean) $ echo "README edited" >> ./README $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a") Si esto nos parece muy "verbose" y queremos la información al estilo SVN/Mercurial podremos usar -s : $ git status -s $ echo "README edited" >> ./README $ git status -s M README
  37. Práctica (ignore files) • Creamos: file.garbage • miramos el estado

    • Creamos un gitignore ◦ *.garbage • miramos estado
  38. git diff git diff ofrece información en formato "diff" de

    los cambios efectuados. Esto vale para ver cuáles han sido los cambios que hay desde la última revisión (o una anterior). En este ejemplo se ha añadido la línea "README edited" al final del fichero README. $ git diff diff --git a/README b/README index 4a3203e..df5bb62 100644 --- a/README +++ b/README @@ -1 +1,2 @@ README one +README edited En este otro caso aparte de añadir una línea en el archivo README, en README2 hemos editado una línea. $ git diff diff --git a/README b/README index 4a3203e..df5bb62 100644 --- a/README +++ b/README @@ -1 +1,2 @@ README one +README edited diff --git a/README2 b/README2 index c69ccb9..697e1c7 100644 --- a/README2 +++ b/README2 @@ -1 +1 @@ -README two +prueba prueba prueba
  39. git commit git commit hace que los cambios que estén

    en la Staging Area pasen a ser una revisión (es decir, confirmar los cambios). Todos los cambios que no hayan sido pasados a la zona de stage no estarán "commiteados" pero no se perderán esos cambios. En este ejemplo vemos como si no hay nada en el stage el commit no se hace (no tendría sentido hacer commit de nada). Una vez añadido, el commit se realiza sin problema. $ echo "editing readme" >> ./README $ echo "editing readme2" >> ./README2 $ git status -s M README M README2 $ git commit -m "Edited 2 READMEs" # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # modified: README2 # no changes added to commit (use "git add" and/or "git commit -a") $ git add ./README ./README2 $ git commit -m "Edited 2 READMEs" [master 845401d] Edited 2 READMEs 2 files changed, 3 insertions(+), 1 deletions(-)
  40. git commit En este ejemplo vemos como un archivo modificado

    que no está en el stage, después de hacer git commit sigue como "modified". $ echo "editing readme again" >> ./README $ echo "editing readme2 again" >> ./README2 $ git status -s M README M README2 $ git add ./README $ git status -s M README M README2 $ git commit -m "Edited 1 README" [master e4e0a01] Edited 1 README 1 files changed, 1 insertions(+), 0 deletions(-) $ git status -s M README2 $ git add ./README2 $ git commit -m "Edited 1 README again" [master ccc048e] Edited 1 README again 1 files changed, 1 insertions(+), 0 deletions(-) $ git status # On branch master nothing to commit (working directory clean)
  41. git commit -a Como se ha comentado anteriormente, Git destaca

    por su zona especial llamada Staging Area. Sin embargo, a veces resulta un poco pesado hacer git add de todos los archivos modificados. Para ello, Git tiene el parametro "-a" que pasa todos los cambios por el stage automaticamente y hace commit. Por tanto, sería casi igual que git add . + git commit. $ echo "editing readme2 again x 2" >> ./README2 $ echo "editing readme again x 2" >> ./README $ git status -s M README M README2 $ git commit -a -m "Commiting using -a" [master 2e11cb9] Commiting using -a 2 files changed, 2 insertions(+), 0 deletions(-)
  42. git commit -avm Además de todo lo comentado, podemos usar

    más opciones. Haciendo commit sin ningún parámetro (git commit) o con el parámetro -a (git commit -a), Git nos abrirá el editor de texto por defecto para que insertemos el comentario del commit (el editor es configurable con git config). • Si queremos pasarle el comentario directamente en el comando del commit, usamos "-m". • Si queremos que nos de más información que de lo habitual tras hacer el commit (verbose), usaremos "-v". Existen muchos más parámetros para el commit, pero la mayoría de la veces, el comando usado suele ser: git commit -avm "comentario del commit" $ git status -s M README $ git commit -avm "This is a comment" [master d49c9e5] this is a comment 1 files changed, 1 insertions(+), 0 deletions(-)
  43. Práctica (commit) • Creamos un fichero cualquiera • Añadimos una

    linea • commit (Track) • Añadimos otra linea • Hacemos diff • Commit + staging en 1 paso
  44. git log git log puede darnos información formateada de los

    commits. Podremos poner, mucha información, poca, formateada estilo grafo, con todas las ramas... • --graph: Pone en formato grafo los commits. • --oneline: Formato simple de commit en una línea. • --decorate: Con colores para cada rama, checksum, branches... • --all: Visualiza información de todas las ramas. Existen muchos parametros más (incluso hasta para configurar los colores de salida). Por tanto, un comando que proporciona bastante información visible sería: git log --graph --decorate --oneline --all
  45. git log git log es tan flexible como nosotros lo

    deseemos y nos proporciona tanta información o incluso más que un programa con interfaz gráfica como Gitk, Qgit, Gitx... $ git log --graph --decorate --oneline --all * 77c48e7 (HEAD, master) Merge branch 'branch2' |\ | * 3699398 (branch2) Modified README 3 in branch2 * | 3cc6283 Modified README 3 in master branch |/ * 736c954 Modified README 3 * 56dedf6 Modified README 1 and 2 * c2f5d57 Initial commit $ git checkout branch2 Switched to branch 'branch2' $ echo "Editing readme3" > README3 $ git commit -avm "Edited README3 in branch2" [branch2 3b3eac4] Edited README3 in branch2 1 files changed, 1 insertions(+), 1 deletions(-) $ git log --graph --decorate --oneline --all * 3b3eac4 (HEAD, branch2) Edited README3 in branch2 | * 77c48e7 (master) Merge branch 'branch2' | |\ | |/ |/| * | 3699398 Modified README 3 in branch2 | * 3cc6283 Modified README 3 in master branch |/ * 736c954 Modified README 3 * 56dedf6 Modified README 1 and 2 * c2f5d57 Initial commit
  46. git log ¡Podemos incluso hasta visualizar los diffstat de cada

    commit! (con --stat) $ git log --graph --decorate --oneline --all --stat * 3b3eac4 (branch2) Edited README3 in branch2 | README3 | 2 +- | 1 files changed, 1 insertions(+), 1 deletions(-) | * 77c48e7 (HEAD, master) Merge branch 'branch2' | |\ | |/ |/| * | 3699398 Modified README 3 in branch2 | | README3 | 2 +- | | 1 files changed, 1 insertions(+), 1 deletions(-) | * 3cc6283 Modified README 3 in master branch |/ | README3 | 2 +- | 1 files changed, 1 insertions(+), 1 deletions(-) * 736c954 Modified README 3 | README3 | 1 + | 1 files changed, 1 insertions(+), 0 deletions(-) * 56dedf6 Modified README 1 and 2 | README | 1 + | README2 | 1 + | 2 files changed, 2 insertions(+), 0 deletions(-) * c2f5d57 Initial commit 0 files changed, 0 insertions(+), 0 deletions(-)
  47. gitk Gitk es una interfaz gráfica que viene con Git.

    Sin embargo, también existen más como Qgit o gitX. Por defecto, Gitk no visualiza todas las ramas. Para ello, hay que arrancarlo como: gitk --all
  48. git reset git reset es usado para dejar el repo

    limpio (volver a revisiones anteriores). Los cambios que no estén en la Staging Area seguirán en estado "modified" a no ser que usemos --hard. Asimismo, también se le puede especificar a qué momento queremos volver (commit concreto, tag, etc...) de muchas formas. Nombre, hash... $ git log --oneline -n 3 --decorate 82b9172 (HEAD, master) Merge branch 'branch2' f214634 (branch2) Readme6 edited 1aa8f8d Merge branch 'branch3' into branch2 $ echo "Prueba" >> ./README $ git status -s M README $ git reset --hard HEAD HEAD is now at 82b9172 Merge branch 'branch2' $ git status -s $ git log --oneline -n 3 --decorate 82b9172 (HEAD, master) Merge branch 'branch2' f214634 (branch2) Readme6 edited 1aa8f8d Merge branch 'branch3' into branch2
  49. git revert git revert también vale para deshacer cambios pero

    de forma menos intrusiva. Con revert lo que hacemos es revertir los cambios de un commit concreto haciendo un nuevo commit (aplicar el diff de ese commit al reves), dicho de otra forma: "desaplicamos" un commit. También se le puede especificar que no haga commit después de revertir (--no-commit). $ git status # On branch master nothing to commit (working directory clean) $ git log --oneline b7755fb Added file3 a197018 Added file2 c1720d7 Added file1 $ ls file1 file2 file3 $ git revert a197018 [master ef313dd] Revert "Added file2" 0 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 file2 $ ls file1 file3 $ git log --oneline ef313dd Revert "Added file2" b7755fb Added file3 a197018 Added file2 c1720d7 Added file1
  50. git checkout (reverting) git checkout tiene usos muy diferentes. En

    este caso hablamos de git checkout para deshacer cambios (este comando aparecerá de nuevo cuando se hable de las ramas). Con git checkout podemos revertir archivos individuales o repos enteros a revisiones anteriores. Si usamos git checkout -- FICHERO hace lo mismo, pero si tenemos ese archivo en la Staging Area y se ha modificado posteriormente, se revierte a la revisión del staging area. En resumen, sería revertir los cambios hechos en el fichero al estado de después de haberlo metido en el stage. $ git status -s M README2 $ cat ./README2 prueba prueba prueba README editing $ git checkout HEAD README2 $ git status -s $ cat ./README2 prueba prueba prueba
  51. git commit --amend Cuando hablamos de git commit --amend estamos

    hablado de reescribir un commit. Esto no es aconsejable ya que reescribir el historial no es bueno (sobre todo si ha sido publicado). Esto lo podríamos usar después de haber hecho un commit y darnos cuenta que se nos ha olvidado añadir un archivo (pero sin el push). $ touch ./README99 ./README100 $ git add ./README99 $ git commit -m "Added README 99" [master dab69e5] Added README 99 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 README99 $ git log --oneline -n 3 --decorate dab69e5 (HEAD, master) Added README 99 2603c70 Modified readme once again ¬¬ c07be7b Revert "edited README again and again and again" $ git add ./README100 $ git commit --amend -m "Added README 99 and 100" [master c3491b1] Added README 99 and 100 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 README100 create mode 100644 README99 $ git log --oneline -n 3 --decorate c3491b1 (HEAD, master) Added README 99 and 100 2603c70 Modified readme once again ¬¬ c07be7b Revert "edited README again and again and again"
  52. Práctica (solucionar liadas pardas) • Editamos el fichero 2 veces

    haciendo 2 commits • Hacemos reset anteultimo commit • Miramos el log • Editamos y hacemos otro commit • Hacemos revert • Comprobamos el nuevo commit y el estado de los cambios • Hacemos cambios en un fichero • Reseteamos ese fichero (checkout) • Hacemos cambios y un commit • hacemos cambios y reusamos el commit anterior (amend)
  53. Punteros En Git todo va sobre punteros. Cuando hacemos reset,

    revert, branching.... todo son punteros que apuntan a revisiones. Esto es una de las caracteristicas que hace especial a Git. Uno de los punteros más importantes es HEAD que apunta al último commit de la rama donde estemos situados. Además de ello, cada rama tiene un puntero propio que apunta al último commit de dicha rama. En este ejemplo vemos como hay 2 ramas y estamos situados en la rama master (ver posición de HEAD).
  54. Remote Hasta ahora todo se basaba en el repositorio local.

    A partir de ahora, hablaremos de ambos pero mayoritariamente de operaciones remotas.
  55. Remote config Los remotes son "direcciones" remotas donde reside el

    repositorio común el cual será actualizado por todos los usuarios de un repositorio y del cual obtendrán el repositorio. Para configurarlo añadiremos a nuestro repositorio esa dirección. Con: git remote add NOMBRE DIRECCION Podemos tener todos los remotes que queramos, pero el remote por defecto es origin. $ git remote $ git remote add origin [email protected]:slok/xlarrakoetxeaorg.git $ git remote origin $ git remote -v origin [email protected]:slok/xlarrakoetxeaorg.git (fetch) origin [email protected]:slok/xlarrakoetxeaorg.git (push) $ git remote add origin2 [email protected]:slok/xlarrakoetxeaorg.git $ git remote -v origin [email protected]:slok/xlarrakoetxeaorg.git (fetch) origin [email protected]:slok/xlarrakoetxeaorg.git (push) origin2 [email protected]:slok/xlarrakoetxeaorg.git (fetch) origin2 [email protected]:slok/xlarrakoetxeaorg.git (push)
  56. git clone Cuando clonamos un repositorio mediante git clone, el

    remote del cual hemos descargado estará ya establecido por defecto. $ git clone [email protected]:slok/xlarrakoetxeaorg.git Initialized empty Git repository in /home/slok/xlarrakoetxeaorg/.git/ Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 712, done. remote: Compressing objects: 100% (504/504), done. remote: Total 712 (delta 437), reused 434 (delta 159) Receiving objects: 100% (712/712), 337.24 KiB | 550 KiB/s, done. Resolving deltas: 100% (437/437), done. $ cd ./xlarrakoetxeaorg/ $ git remote -v origin [email protected]:slok/xlarrakoetxeaorg.git (fetch) origin [email protected]:slok/xlarrakoetxeaorg.git (push)
  57. Operaciones con remote Existen diferentes formas para interactuar con el

    repo remoto. Las más habituales son: • Push: para propagar las revisiones al repo remoto. • Pull: Obtener las revisiones remotas y aplicarlos a nuestro código (Fetch+merge). • Fetch: Obtener los cambios del repo remoto.
  58. git push Cuando queremos propagar nuestros cambios al servidor Git

    remoto hacemos git push REMOTE RAMA. Lo normal es ir haciendo commits y una vez terminado hacer un git push. $ touch ./README $ git add ./README $ git commit -m "Initial commit" [master (root-commit) 6e4cc7b] Initial commit 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 README $ echo "First line" >> ./numbers $ git add ./numbers $ git commit -m "Added numbers file" [master 703d47e] Added numbers file 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 numbers $ git push origin master Enter passphrase for key '/home/slok/.ssh/id_rsa': Counting objects: 6, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (6/6), 450 bytes, done. Total 6 (delta 0), reused 0 (delta 0) To [email protected]:slok/basic-git.git * [new branch] master -> master
  59. git pull Para actualizar nuestro repo con las revisiones nuevas

    que hay en el servidor Git remoto usamos git pull que es un git fetch + git merge (se explicará con las ramas). Al hacer el git pull pueden pasar 3 cosas: • Que haya conflictos (se explica más adelante). • Que sea un merge fast forward (se explica más adelante). • Que sea un merge limpio (ejemplo debajo). $ git pull origin master Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 5, done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 3 (delta 0) Unpacking objects: 100% (3/3), done. From github.com:slok/basic-git * branch master -> FETCH_HEAD Merge made by recursive. numbers | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
  60. Práctica (remotes) • Clonar repositorio ◦ https://github.com/slok/introduccion_git.git • Esperar a

    que se hagan cambios • Hacer pull • Nos registramos en Github • Creamos un repositorio • Cambiamos los remotes • Hacemos push a nuestro repo
  61. git push (rejected) Algo común es que se vaya a

    hacer un git push y que Git no nos deje. Esto es porque a habido cambios en el repositorio (hechos por otra persona) y es necesario hacer un git pull para integrar los cambios del repo remoto en nuestro repo local antes de subirlo. Al hacer esto, lo que puede pasar es lo mismo que lo comentado anteriormente. En este ejemplo se ve un merge sin conflictos. $ git push origin master Enter passphrase for key '/home/slok/.ssh/id_rsa': To [email protected]:slok/basic-git.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to '[email protected]:slok/basic-git.git' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again. See the 'Note about fast-forwards' section of 'git push --help' for details. $ git pull origin master Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 6, done. remote: Compressing objects: 100% (4/4), done. remote: Total 4 (delta 0), reused 4 (delta 0) Unpacking objects: 100% (4/4), done. From github.com:slok/basic-git * branch master -> FETCH_HEAD Merge made by recursive. 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 words $ git push origin master Enter passphrase for key '/home/slok/.ssh/id_rsa': Counting objects: 8, done. Delta compression using up to 2 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (5/5), 573 bytes, done. Total 5 (delta 1), reused 0 (delta 0) To [email protected]:slok/basic-git.git 817e279..48cdf3a master -> master
  62. Práctica (remotes 2) • Clonar vuestro repositorio en otro sitio

    ◦ https://github.com/xxx/introduccion_git.git • Hacer un cambio, commit y push en el último repo clonado • Hacer un cambio en el otro repo, commit y push • Ver el mensaje de rejected ◦ Ahora tocaría hacer pull para que se actualice el repo. Nosotros borramos el repo, más adelante veremos el merging.
  63. git branch Las ramas son utilizadas para el desarrollo en

    paralelo y organización del desarrollo (rama estable, rama desarrollo, rama de bugfixes...). Git maneja las ramas de forma óptima ya que como hemos comentado anteriormente Git usa sólo punteros. En Git la rama por defecto siempre se llama master. Las demás las podemos llamar como queramos. Con git branch listamos todas las ramas locales y con git branch RAMA creamos una nueva rama local (seguiremos en la rama actual). Para cambiarnos de rama usamos: git checkout RAMA $ git branch * master $ git branch branch2 $ git branch branch2 * master $ git checkout branch2 Switched to branch 'branch2' $ git branch * branch2 master
  64. git branch Para borrar una rama se utiliza el parámetro

    "-d". Por tanto, sería git branch -d RAMA (¡¡La rama master no debemos borrarla!!) $ git branch branch2 * master $ git branch -d branch2 Deleted branch branch2 (was 48cdf3a). $ git branch * master $ git branch -a branch2 * master remotes/origin/branch2 remotes/origin/master $ git push origin :branch2 Enter passphrase for key '/home/slok/.ssh/id_rsa': To [email protected]:slok/basic-git.git - [deleted] branch2 $ git branch -a branch2 * master remotes/origin/master Para borrar una rama remota sería igual que un git push pero con ":" delante del nombre (para borrar una rama en el repo alojado en el servidor de Git): git push REMOTE :RAMA
  65. git branch Para hacerse una idea del concepto de las

    ramas, podemos ver este ejemplo donde existen dos ramas y en la rama master se ha "mergeado" la rama iss53:
  66. git branch (remotas) Aparte de las ramas locales, tenemos unas

    ramas que son remotas. Una y otra vez hemos hablado de punteros y eso es lo que son las ramas. Por eso, se podría decir que estas ramas remotas son punteros que apuntan a las revisiones que el servidor remoto tiene como cabezas y estas son actualizadas al momento de hacer pull (concretamente fetch). Para visualizarlas usaremos git branch -a. Con -v visualizaremos en que revisión (commit) están cada una actualmente (parte de su hash SHA1). $ git branch -a * branch2 master remotes/origin/branch2 remotes/origin/master $ git branch -a -v * branch2 48cdf3a Merge branch 'master' of github.com:slok/basic-git master 817e279 Merge branch 'master' of github.com:slok/basic-git remotes/origin/branch2 48cdf3a Merge branch 'master' of github.com:slok/basic-git remotes/origin/master 48cdf3a Merge branch 'master' of github.com:slok/basic-git
  67. git branch (remotas) En el primer ejemplo vemos como al

    hacer el clone obtenemos una rama remota master y una rama master que apuntan al mismo lugar. En el segundo ejemplo vemos como alguien ha hecho un push al repo remoto y nosotros localmente tenemos el puntero remoto en una revisión que está desactualizada. Además, hemos hecho commits locales.
  68. git branch (clone) ya hemos visto como crear una branch

    en un repositorio, pero ¿y si ese repositorio lo hemos clonado y no queremos trabajar como master?. Por defecto cuando clonamos el repositorio estamos en la branch master. En ese momento realmente en local solo tenemos las branch master y las remote/xxxxx por tanto tendremos que crear la branch remote en una branch en la que podamos trabajar. Como vemos en el ejemplo, solo tenemos las rama master, para poder usar una rama remota tenemos que hacer tracking de ella. $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/submodules
  69. git branch (clone) Para hacer tracking de la rama hay

    2 formas (realmente 3). La primera es hacerlo a mano (si queremos que la rama se llame diferente a la remota debemos usar esta forma). Esto consiste en crear una rama "copiando" los datos de su remote local y luego nos metemos en ella con checkout (el proceso de "copiar/clonar" una rama se denomina tracking) $ git branch submodules origin/submodules Branch submodules set up to track remote branch submodules from origin. $ git checkout submodules Switched to branch 'submodules' $ git branch -a master * submodules remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/submodules
  70. git branch (clone) La segunda forma y que está a

    partir de la versión 1.6.2 de Git es la de usar git checkout --track o -t $ git checkout --track origin/submodules Branch submodules set up to track remote branch submodules from origin. Switched to a new branch 'submodules' $ git branch -a master * submodules remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/submodules Por último la 3ra forma que no es muy correcta (ya que es mejor especificarselo a git), es hacer checkout normal y que git lo automatice $ git checkout submodules Branch submodules set up to track remote branch submodules from origin. Switched to a new branch 'submodules' $ git branch -a master * submodules remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/submodules
  71. Práctica (branchs) • Creamos una branch: other (en un repo

    clonado) • Hacemos push de master y push de other • Borramos el repo • Clonamos el repo • Hacemos track de other • Borramos la rama other en local y en remoto
  72. git fetch Siguiendo con el ejemplo de antes (tenemos la

    rama remota desactualizada en local). Para actualizarla tendremos que hacer git fetch y luego para integrar esos cambios remotos en nuestra rama haremos un git merge, que es lo mismo que git pull (como se comentó anteriormente git pull = git fetch + git merge).
  73. git merge git merge integra ramas. O por decirlo de

    otra forma, mezcla una rama en otra. En ocasiones pensamos que sólo lo usaremos si funcionamos con varias ramas pero como se ha comentado anteriormente, Git usa ramas remotas con las cuales actualizamos nuestro repositorio local al estado más actualizado del repo remoto y por tanto, esos cambios se deben mezclar. Es por ello que cuando actualicemos el repo a la última versión también se usará git merge directa u indirectamenete (git pull). Después de actualizar una rama remota localmente con git fetch debemos integrar esos cambios en nuestra rama y para ellos usamos git merge también. Para mezclar una rama en otra lo que debemos hacer es situarnos en la rama sobre la que se va a mezclar y hacer git merge RAMA-A-MEZCLAR $ git checkout master Switched to branch 'master' $ git merge branch2 Updating 817e279..48cdf3a Fast-forward README | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
  74. Fast-forward merge El Fast-forward merge es un caso especial de

    merge gestionado por Git automaticamente al hacer git merge. Git al usar punteros los aprovecha de tal forma que en este tipo de merge no necesita mezclar nada y sólo avanzar el puntero. Esto pasa cuando la rama a mezclar tiene en común el último commit de la rama donde se mezcla. Por tanto, no hay que mezclar nada, sólo avanzar el puntero al mismo lugar que la rama a mezclar. En este ejemplo se mezcla la rama hotfix en master. Es un merge fast-forward. $ git checkout master $ git merge hotfix
  75. Práctica (merging) • Nos situamos en la branch other •

    Editamos y hacer commit • Hacemos merge de other en master (fast forward)
  76. Conflictos Los conflictos suelen aparecer cuando Git no ha podido

    hacer el merge porque había conflictos y se necesita un humano para que los corrija. Los conflictos pueden aparecer en varias ocasiones: • Después de merge. • Después de un pull (en el fondo es un merge). El aspecto de los conflictos es de este tipo: <<<<<<< HEAD Here is the master branch change ======= I'm editing this line in branch2 branch >>>>>>> branch2 En este ejemplo, estamos intentando integrar la rama branch2 en la rama master (en la cual estamos y por tanto es el puntero HEAD). Como se ve, en la parte de arriba sale el código de la rama en la que estamos, y en la parte de abajo está el código conflictivo de la rama que queremos mezclar. El conflicto es que las 2 ramas han editado la misma linea y Git no sabe cual es la correcta
  77. Conflictos Para resolver conflictos podemos ayudarnos de herramientas especificas para

    ello: • Diffuse: http://diffuse.sourceforge.net/ • Meld: http://meldmerge.org/
  78. Conflictos Tras solucionar el conflicto (si lo hacemos a mano)

    hay que meter los cambios en la Staging Area y hacer commit (git add + git commit o git commit -a) A no ser que usemos git mergetool (arranca el editor de diffs, para configurarlo es la variable merge.tool) que al guardarlo ya los meterá en la staging area automaticamente. Git arrancará el editor configurado y pondrá un comentario similar a " Merge branch 'RAMA' " que es el mensaje por defecto (podemos cambiarlo). $ git checkout master Switched to branch 'master' $ git merge branch2 Auto-merging README CONFLICT (content): Merge conflict in README Automatic merge failed; fix conflicts and then commit the result. $ git mergetool Merging the files: README Normal merge conflict for 'README': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffuse-3way): $ git add ./README $ git commit reading .git/COMMIT_EDITMSG [master f950b05] Merge branch 'branch2'
  79. Práctica (Conflicts) • Editamos y hacer commit • Nos situamos

    en la branch other • Editamos la misma línea que en master con otra cosa • Hacemos commit • Hacemos merge de other en master • Resolvemos conflicto (a mano) • Commit
  80. Tags Los tags son punteros (sí, otra vez...) estáticos que

    "no" se mueven e identifican esa revisión concreta. Se suele usar para versionar. Para crear un tag se usa git tag. Si no se le dice qué commit tag-ear (mediante su checksum) pondrá el tag donde apunta HEAD. Normalmente se suele utilizar el parametro "-a" (y es recomendable hacerlo) para que el tag guarde el momento y quién lo ha creado. Al igual que en git commit podemos usar "-m" para poner un comentario. $ git log -n 3 --oneline --decorate 1c7b99f (HEAD, origin/master, origin/HEAD, master) Updated README f950b05 Merge branch 'branch2' f539ca3 Upated README in branch2 $ git tag -a v1.0 -m "Version 1.0" $ git log -n 3 --oneline --decorate 1c7b99f (HEAD, tag: v1.0, origin/master, origin/HEAD, master) Updated README f950b05 Merge branch 'branch2' f539ca3 Upated README in branch2 $ git tag -a v0.1 f539ca3 -m "Version 0.1 in branch2" $ git log -n 3 --oneline --decorate 1c7b99f (HEAD, tag: v1.0, origin/master, origin/HEAD, master) Updated README f950b05 Merge branch 'branch2' f539ca3 (tag: v0.1) Upated README in branch2
  81. Tags Los tags son referenciables para cualquier cosa como hacer

    reset, revert... Hay que pensar de forma que el nombre del tag es como el nombre de una variable que contiene el checksum del commit (como siempre, estos también son punteros). Para eliminar un tag usamos git tag -d NOMRE-TAG $ git log --decorate --graph --oneline --all * bd232e0 (origin/branch2) Updated README in branch2 again? | * 1c7b99f (HEAD, tag: v1.0, origin/master, origin/HEAD, master) Updated README | * f950b05 Merge branch 'branch2' | |\ | |/ |/| * | f539ca3 (tag: v0.1) Upated README in branch2 | * 01ddc18 Edited README in master branch |/ * 48cdf3a Merge branch 'master' of github.com:slok/basic-git |\ | * 817e279 Merge branch 'master' of github.com:slok/basic-git | |\ | * | c9d3710 Added words file * | | d37aaf3 Edited README | |/ |/| * | c9c8201 Added second line to numbers |/ * 703d47e Added numbers file * 6e4cc7b Initial commit
  82. Tags Para que que los tags sean creados en el

    repostiorio remoto habrá que hacer git push de ellos, pero de una forma especial; esto es, con el parámetro --tags. Por tanto, sería: git push --tags REMOTE $ git push --tags origin Enter passphrase for key '/home/slok/.ssh/id_rsa': Counting objects: 2, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 311 bytes, done. Total 2 (delta 0), reused 0 (delta 0) To [email protected]:slok/basic-git.git * [new tag] v0.1 -> v0.1 * [new tag] v1.0 -> v1.0
  83. Práctica(Tags) • Hacemos 3 commits • Creamos un tag en

    el 2do • Pasamos los tags al repo remoto • Comprobamos los tags en github y en local
  84. Github •Introducción •Registro (Hecho previamente) •Crear repositorio (Hecho previamente) •Añadir

    clave pública ssh •Navegación básica por github •Fork •Pull request •Gist •Github pages
  85. Historia • 2008 (Años antes empezaron) • 3 emprendedores ◦

    Tom preston werner (Mojombo) -> Gravatar ◦ Chris wanstrath (Defunkt) ◦ PJ Hyett (pjhyett) • Rails conf • Más de 100 empleados en 4 años
  86. Clave pública SSH $ ssh-keygen -t rsa Generating public/private rsa

    key pair. Enter file in which to save the key (/home/slok/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/slok/.ssh/id_rsa. Your public key has been saved in /home/slok/.ssh/id_rsa.pub. The key fingerprint is: 1d:a2:ee:77:4f:a1:a3:6b:f1:e6:a5:13:50:d1:7e:a2 slok@slok-TN120R The key's randomart image is: +--[ RSA 2048]----+ | .o | | . . | | .... | | ..o .o . | | . S....o | | . . E. . | | . oo.o | | . o.== | | .oo=oo. | +-----------------+ Como se ha comentado previamente, git soporta el protocolo SSH. Para poder usarlo necesitamos una clave ssh (rsa o dsa). Es importante que la clave sea creada con OpenSSH para evitar problemas de compatibilidad. Para crearala usaremos ssh-keygen -t TIPO [-C EMAIL] (Si no se proporciona email se pondrá: user@host). Por defecto la clave se guardará en la carpeta de usuario de ssh (.ssh) y archivo: id_rsa Se crearán dos archivos uno privado y otro publico (.pub), el privado solo debemos conocerlos nosotros (no debe salir de nuestros ordenadores). Durante el proceso también se podrá añadir una contraseña (Enter passphrase)
  87. Clave pública SSH $ cat /home/slok/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDbFvaugge1YQ1OQPUyo4sYkO8SaEEwD/nscLjEVyIafSoplfEeEPYAGwVZec74F36Ee9pFtZ lx3VQgoqvGIDO2gFFby9CjGIRnlZyynFt9O65TiwgDaBYpw5X+KFQQfp/5nIgtbzTq3gxaOTORPta/fqBwKe8IX+x5EJcTBqoi7OqC c4leXXC2RFyvDjFi4czV0yHo4oE2mdkNrQuw1XUTJnK9UgF8ewO+xx6sOttqenFlBeuIHbErIPyGI0/qfEApb7cQ2rQ5BOwWF+K2DN

    XjYTsxyLLorUBAR0QihAyqAmjjxTLI3t7LIUcXnY95oFNmjib0+YBz80P/spmp88dX slok@slok-TN120R Ahora debemos coger el contenido del archivo público que se ha creado en la carpeta de usuario en el directorio .ssh (id_rsa.pub). el cual tendrá un aspecto similar a este: Copiamos esa clave pública y en settings -> ssh-keys añadimos una nueva clave
  88. Navegación básica (Dashboard) En el dashboard tenemos las notificaciones de

    los usuarios y repos que seguimos, así como nuestros propios repos y los que seguimos (watched repositories)
  89. Navegación básica (Repo) En el repositorio Tenemos muchos datos, desde

    las direcciones, lenguajes usados, archivos (en el último commit), forks, pull requests, README...
  90. Navegación básica (Commits) En la lista de commits podemos acceder

    a los ficheros que tenía el repo en un commit exacto. También podemos acceder al commit en sí, usuarios...
  91. Fork "Forkear" un repo es hacer una copia de un

    repositorio público de otra persona
  92. Pull request Un pull request es una petición para que

    alguien admita una contribución en el código. Para poder hacer esto Son necesarios varios pasos: • primero necesitamos hacer un fork • Luego los commits que queramos • [Es aconsejable limpiar el historial mediante rebasing] ◦ http://git-scm.com/book/en/Git-Branching-Rebasing • Por último hacer la pull request. ◦ Pull request aceptado ◦ Pull request denegado • Si es aceptado entonces se hará el merge
  93. Pull request (Send) Tras haber hecho un fork del repo

    testing_git de la user Sharem hemos hecho un commit y ahora queremos que ese cambio sea incorporado al repo original
  94. Pull request (Send) Una vez hecho el pull request este

    permanecerá abierto hasta que el usuario lo decline o lo acepte
  95. Pull request (Receive) La user Sharem ha hecho un fork

    de introduccion_git ha hecho unos commits, los ha subido a su repositorio y a continuación ha hecho un pull request sobre el repositorio original. El usuario dueño del repo al que se le hace el pull request (en este caso nosotros) recibirá un email. Si vamos a pull requests de nuestro repositorio veremos todas las que tenemos (en concreto una)
  96. Pull request (Receive) Tras aceptar, nos dará la opción de

    revisar y editar el commit del merge (el pull request no deja de ser un merge de ramas) Y por último si vamos al historial del commit veremos el commit original y el commit del merge (commit del pull request)
  97. Gist Gist es un pastebin con esteroides. El paste en

    sí es un repo git y se puede ir modificando si se quiere (como repo git o mediante la web). Además podemos añadir más de un paste
  98. Github pages Github pages son páginas web estáticas que podemos

    crear mediante repositorios git. Los hay 2 dos tipos, por usuario y por proyecto Las páginas de usuario estarán alojadas en: USUARIO.github.com Para crearlas tenemos que crear un repositorio llamado USUARIO.github.com y ahí meter los html, css, js... (el archivo CNAME es usado para redirigir desde otro dominio, p.e: xlarrakoetxea.org redirigirá a slok.github.com)
  99. Github pages El segundo tipo es para crear páginas de

    proyecto. estas son muy útiles ya que para proyectos normalmente no necesitamos cosas dinámicas y con páginas estáticas para poner ejemplos, documentación... Para ello en el repo del proyecto tenemos que crear una rama que se llame: gh-pages y seguimos el mismo proceso que para las páginas personales
  100. Git alias En otros SCV existen comandos más pequeños y

    rápidos para hacer las mismas acciones como commit = ci, status = st... En git la cosa cambia. Cada persona es diferente y tiene sus formas de crear "shorcuts" para eso están los alias. Además los alias también cogen opciones que solemos pasarle como parámetro a dichos comandos. Para crear un alias debemos crearlo en la configuración y mediante config -- NIVEL_CONF alias.SHORCUT comando. Por ejemplo para un commit: git config --global alias.ci commit $ git st git: 'st' is not a git command. See 'git --help'. Did you mean one of these? status reset stage stash $ git config --global alias.st status $ git st # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: test.txt # no changes added to commit (use "git add" and/or "git commit -a")
  101. Git stash git stash es algo así como un "saco"

    en el se guardan diferentes "snapshots" de lo que hemos desarrollado y deja la copia limpia (como en HEAD). El uso común suele ser crar una rama y no llevarse los cambios a la nueva rama, resolver un bug... Git mantiene una pila de todos los stash que vamos haciendo de esta forma podemos aplicarlos en el orden que queramos Para "stashear" el estado actual lo hacemos con git stash , así nos pondrá el comentario de WIP on RAMA: SHA COMENTARIO_HEAD si queremos meterle un comentario al stash podemos hacerlo mediante git stash save COMENTARIO $ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: test.txt # no changes added to commit (use "git add" and/or "git commit -a") $ git stash Saved working directory and index state WIP on master: 47be95f Initial commmit HEAD is now at 47be95f Initial commmit $ git status # On branch master nothing to commit (working directory clean)
  102. Git stash Para listar todos los stash que tenemos disponibles

    usamos el comando list Por tanto con git stash list veríamos los stash que tenemos en el "saco" $ git stash list stash@{0}: On master: This is the last stash :D with custom comment stash@{1}: WIP on master: 47be95f Initial commmit El estilo que tienen los identificadores de stash son: stash@{N} donde N es el identificador en orden inverso que han llegado, por tnato el último stash será el 0 Principalmente hay dos formas de aplicar el stash. La primera es con git stash pop que saca el último stash y lo borra del "saco" y la otra forma es usando git stash apply stash@{N} que lo aplica pero no lo borra del saco y por tanto habría que usar git stash drop stash@{N} para borrarlo del "saco" de stashes $ git status # On branch master nothing to commit (working directory clean) $ git stash pop # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: test.txt # no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (1aed8ca483528a97e81333bb84895913f5e0bc8a) $ git stash list stash@{0}: WIP on master: 47be95f Initial commmit
  103. Práctica (alias & stash) • Hacemos 3 alias ◦ st

    -> status ◦ ci -> commit ◦ lg -> log --oneline --graph --decorate --all • creamos 2 archivos ◦ File1 ◦ File2 • Hacemos stash • Creamos un archivo ◦ File3 • Commit (usando el alias ci) • Aplicamos stash • Status (usando el alias st) • Commit • log (usando el alias lg)
  104. Git patch patch en sí no es un subcomando de

    git si no una opción del git add por tnato lo correcto sería decir --patch (o -p). Git patch es utilizado para añadir cachos de código concretos en el stage. De esta forma podremos ser más flexibles a la hora de hacer nuestros commits. Por defecto --patch trae una serie de opciones que nos ayudarán en el proceso de añadido de cachos de código (hunk) $ git add --patch diff --git a/README b/README index 65018b8..5208a20 100644 --- a/README +++ b/README @@ -1,3 +1,9 @@ +I'm Git's first friend + Git is my friend :D +Hello Git!!! + And mine too! :P + +And mine also! ;) Stage this hunk [y,n,q,a,d,/,e,?]?
  105. Git patch Como vemos anteriormente git add nos va mostrando

    cada hunk y nos pregunta si queremos añadirlo (y) o pasar al siguiente (n). Pero tiene más opciones como la de hacer más pequeños los hunks (s) Stage this hunk [y,n,q,a,d,/,e,?]? y - stage this hunk n - do not stage this hunk q - quit; do not stage this hunk nor any of the remaining ones a - stage this hunk and all later hunks in the file d - do not stage this hunk nor any of the later hunks in the file g - select a hunk to go to / - search for a hunk matching the given regex j - leave this hunk undecided, see next undecided hunk J - leave this hunk undecided, see next hunk k - leave this hunk undecided, see previous undecided hunk K - leave this hunk undecided, see previous hunk s - split the current hunk into smaller hunks e - manually edit the current hunk ? - print help Si decidimos hacerlos más pequeños entonces nuestro hunk anterior será dividido por Git donde el crea conveniente creando varios hunks (sigue...)
  106. Git patch Se ha dividido en 3 cachos. Añadimos el

    primer hunk Stage this hunk [y,n,q,a,d,/,e,?]? s Split into 3 hunks. @@ -1,2 +1,4 @@ +I'm Git's first friend + Git is my friend :D Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? y @@ -1,3 +3,5 @@ Git is my friend :D +Hello Git!!! + And mine too! :P Stage this hunk [y,n,q,a,d,/,K,j,J,g,e,?]? n El segundo hunk no lo añadimos al stage @@ -3 +7,3 @@ And mine too! :P + +And mine also! ;) Stage this hunk [y,n,q,a,d,/,K,g,e,?]? y Y por último, el 3er hunk si lo añadimos al stage. Quedando en el stage el hunk 1 y 3 mientras que el 2do está en modified (sigue)
  107. Git patch Si miramos el estado del repo veremos que

    el README está en 2 estados, modified y staged $ git status -s MM README Primero vemos que cambios están staged (hunk 1 y 3) $ git diff --staged diff --git a/README b/README index 65018b8..907b181 100644 --- a/README +++ b/README @@ -1,3 +1,7 @@ +I'm Git's first friend + Git is my friend :D And mine too! :P + +And mine also! ;)
  108. Git patch Ahora vemos los cambios unstaged (hunk 2) $

    git diff ./README diff --git a/README b/README index 907b181..5208a20 100644 --- a/README +++ b/README @@ -2,6 +2,8 @@ I'm Git's first friend Git is my friend :D +Hello Git!!! + And mine too! :P And mine also! ;) Solo se habrán "commiteado" los hunks elegidos (los que estaban en el stage) $ git commit -m "Testing --patch" [master e26e46f] Testing --patch 1 files changed, 4 insertions(+), 0 deletions(-) $ git status -s M README
  109. Git interactive De la misma forma que usamos --patch podemos

    usar --interactive o -i Para sacar un menú mucho más completo que el de patch. Veremos el estado del repo en ese momento $ git add --interactive staged unstaged path 1: unchanged +2/-0 README *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now> Podremos cambiar de fichero, revertir, sacar diffs... ¡incluso meternos en el propio patch! What now> 5 staged unstaged path 1: unchanged +2/-0 README Patch update>> 1 staged unstaged path * 1: unchanged +2/-0 README Patch update>> diff --git a/README b/README index 907b181..5208a20 100644 --- a/README +++ b/README @@ -2,6 +2,8 @@ I'm Git's first friend Git is my friend :D +Hello Git!!! + And mine too! :P
  110. Práctica (patch) • Creamos un archivo con líneas impares hasta

    la 7 ◦ línea n + 2 • Commit • Editamos ese archivo metiendo las líneas pares donde corresponden • Dividimos el commit en 2 commits (usando patch) ◦ 1er commit líneas 2 y 6 ◦ 2do commit línea 4
  111. Git submodules Los submodulos se utilizan para usar proyectos Git

    dentro de proyectos Git (gitInception!!). De esta forma tenemos un repositorio Git que es usado por otro pero que a su vez este otro es totalmente independiente de el. Esto nos proporciona varias ventajas como tener separados los proyetos pero usarlos entre ellos, poder incluir proyectos ajenos y no commitear código sin querer en ee proyecto... $ git submodule add [email protected]:slok/submodulo_git.git Cloning into submodulo_git... Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 10, done. remote: Compressing objects: 100% (9/9), done. remote: Total 10 (delta 2), reused 6 (delta 1) Receiving objects: 100% (10/10), done. Resolving deltas: 100% (2/2), done. $ git status # On branch submodules # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: .gitmodules # new file: submodulo_git # Vamos a incluir el proyecto submodulo_git al proyecto introduccion_git mediante git submodule add REPO_DEL_SUBMODULO
  112. Git submodules Como vemos despues de hacer el submodule add

    se nos han creado 2 archivos: . gitmodules y submodulo_git .gitmodules es el archivo que hace tracking de el submodulo. Es algo así como el .gitignore y se hace así para que cualquier persona que descargue el repositorio, su repo tenga constancia de que necesita un submodulo. En el tenemos la información referente a la localización del módulo (puede haber más de un submodulo) $cat ./.gitmodules [submodule "submodulo_git"] path = submodulo_git url = [email protected]:slok/submodulo_git.git
  113. Git submodules El otro archivo es el submodulo en sí.

    Si vamos dentro de el vemos que están los archivos del submodulo $ ls ./submodulo_git README.md helloWorld.py helloWorld.rb Pero para git no es un directorio más del repositorio si no un tipo de fichero especial. Si vemos el diff de nuestra staging area (en concreto del submodulo_git). Vemos que lo que hace es el tracking de un SHA concreto a un commit, por ello sabemos que para git el submodulo es el repo en un commit concreto, por tanto pese a que una persona actualize el repo (submodulo) independientemente de nuestro repo, nuestro repo siempre apuntará a un commit concreto (el que digamos) del submodulo (esto nos da seguridad) $ git diff --staged ./submodulo_git diff --git a/submodulo_git b/submodulo_git new file mode 160000 index 0000000..93a42dd --- /dev/null +++ b/submodulo_git @@ -0,0 +1 @@ +Subproject commit 93a42ddab7b4e94465578a932b3e3529269de8f6
  114. Git submodules Hacemos commit para que se reflejen los cambios

    ya que hasta que no hacemos commit el submodulo no se registra para git $ git commit -avm "Added submodule" [submodules b937440] Added submodule 2 files changed, 4 insertions(+), 0 deletions(-) create mode 100644 .gitmodules create mode 160000 submodulo_git Si nos fijamos en el número que representa el tipo de archivo para git es 160000, este número representa la entrada de un commit y no la de un directorio
  115. Git submodules Git funciona igual que antes, la diferencia ahora

    es que dependiendo en que directorio funcionemos, git estará un repo u en otro. Para nuestro repo (el principal) los cambios hechos dentro del directorio del submodulo no le importan y al reves los cambios hecho en el repo (principal) al submodulo no le importan. En resumen, depende de donde estes (principal o submodulo) git funciona independiente $ git status # On branch submodules # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # no changes added to commit (use "git add" and/or "git commit -a") slok@argentum:introduccion_git$ cd ./submodulo_git/ slok@argentum:submodulo_git$ git status # On branch master nothing to commit (working directory clean)
  116. Git submodules Son independientes salvo cuando el submódulo cambia de

    HEAD ya que como hemos comentado antes Git en los submódulos hace tracking de commits y no de archivos. En este ejemplo el submódulo ha sido actualizado (pull) y ahora el HEAD del submódulo ha cambiado. Si hacemos commit (del repo principal) con el nuevo SHA del submódulo (el cambio del "archivo" submodulo_git), el repo original ahora apuntará al commit donde el submódulo tiene HEAD. $ git status # On branch submodules # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: submodulo_git (new commits) # no changes added to commit (use "git add" and/or "git commit -a"
  117. Git submodules Hasta ahora hemos explicado como crear submódulos y

    como trabajar con ellos. ¿Pero y si clonamos un repo con un submódulo existente? La forma de inicializar el repo y sus submódulos son diferentes. En primero lugar clonamos el repo con git clone como siempre, esto hará que descargue todo el repo incluidos los apuntadores de los submódulos y las referencias al estado concreto de los mismos (commits/SHA) pero no los archivos del propio submódulo con los cuales nosotros trabajamos (pero que al git del repo principal le dan igual), para poder descargarlos hacemos $ git submodule init Submodule 'submodulo_git' ([email protected]:slok/submodulo_git.git) registered for path 'submodulo_git' $ git submodule update Cloning into submodulo_git... Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 10, done. remote: Compressing objects: 100% (9/9), done. remote: Total 10 (delta 2), reused 6 (delta 1) Receiving objects: 100% (10/10), done. Resolving deltas: 100% (2/2), done. Enter passphrase for key '/home/slok/.ssh/id_rsa': Submodule path 'submodulo_git': checked out '93a42ddab7b4e94465578a932b3e3529269de8f6'
  118. Git submodules Los sumódulos pueden ser peligrosos. Ya que guardan

    estados concretos (apuntan a commits). Si a la hora de hacer un submodule update estamos apuntando a un commit que no existe en el repositorio remoto porque no se ha subido, git nos dará un error $ git submodule init Submodule 'submodulo_git' ([email protected]:slok/submodulo_git.git) registered for path 'submodulo_git' $ git submodule update Cloning into submodulo_git... Enter passphrase for key '/home/slok/.ssh/id_rsa': remote: Counting objects: 10, done. remote: Compressing objects: 100% (9/9), done. remote: Total 10 (delta 2), reused 6 (delta 1) Receiving objects: 100% (10/10), done. Resolving deltas: 100% (2/2), done. Enter passphrase for key '/home/slok/.ssh/id_rsa': fatal: reference is not a tree: fbe172136c123acdb5a42b634c7a108d4cd4dbf8 Unable to checkout 'fbe172136c123acdb5a42b634c7a108d4cd4dbf8' in submodule path 'submodulo_git'
  119. Git submodules Para resolverlo existen dos formas. Recuperar ese commit,

    por ejemplo decirle al autor o autores del submodulo que suban al repo remoto ese commit que aún no han subido. Y la otra es cambiar el estado (apuntador al commit) del submodulo. Para hacer eso, son 3 pasos. • Nos metemos en el submodulo y buscamos una versión del módulo correcta (su SHA) • reseteamos a ese SHA el submodulo y salimos • añadimos los cambios a la staging area y hacemos commit (no necesitamos update ya que ahora apunta a una revisión (SHA )correcta) $ cd ./submodulo_git/ $ git log --oneline 93a42dd Added ruby hello world df62d27 Added python hello world 271f394 Initial commit $git reset --hard 93a42 HEAD is now at 93a42dd Added ruby hello world $ cd .. $ git status -s M submodulo_git $ git commit -avm "Fixed submodules" [submodules 2e88d78] Fixed submodules 1 files changed, 1 insertions(+), 1 deletions(-)
  120. Git reflog En ocasiones perdemos commits por hacer resets y

    cuando queremos volver a ellos hemos perdido la pista de esos commits, pero esos commits aún existen y podemos obtener los punteros a ellos mediante git reflog o git log -g por ejemplo vamos a recuperar el primer commit despues de un reset $ git log --oneline -n 4 2835217 Added file 3 3790aa3 Added file 2 99ee77e Added file 1 e26e46f Testing --patch $ git reset HEAD^^^ $ git log --oneline -n 2 e26e46f Testing --patch 8311f5b Merge pull request #1 from sharem/master $ git reflog e26e46f HEAD@{0}: HEAD^^^: updating HEAD 2835217 HEAD@{1}: commit: Added file 3 3790aa3 HEAD@{2}: commit: Added file 2 99ee77e HEAD@{3}: commit: Added file 1 e26e46f HEAD@{4}: clone: from [email protected]:slok/introduccion_git.git $ git reset HEAD@{1} $ git log --oneline -n 1 2835217 Added file 3
  121. Git rebase Para mezclar cambios entre ramas existen 2 formas.

    La primera, más usada y más básica es la que se ha visto anteriormente, usando merge. La otra forma, es usando rebase. Para explicarlo veamos un ejemplo con dibujos. Pongámonos en contexto: • 2 ramas (master y experiment). • Queremos mezclar experiment en master Usando merge: $ git checkout master $ git merge experiment
  122. Git rebase Usando rebase: El rebase tiene 2 pasos al

    contrario que el merge que se hace en uno solo. En primer lugar rebase lo que hace es coger todos los cambios de la rama que queremos mergear(experiment) y crea una especie de parche basandose en el ancestro común de rama donde hacer el merge (master). Este aplica ese parche en la cabeza de la rama donde queremos hacer el merge creando un nuevo commit y haciendo que la rama a mergear (experimental apunte ahí) "desaparezca" haciendo que su padre sea la punta de la rama master $ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it... Applying: C3 commit
  123. Git rebase Después del primer paso tenemos un commit que

    tiene como padre el último commit de la rama donde queremos hacer el merge (master) por tanto quedaría hacer el merge de experiment en la rama master. Lo bonito es que ahora master solo tiene que hacer un fast-forward merge. $ git checkout master $ git merge experiment Updating C4..C3' Fast-forward FILE2.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
  124. Git rebase ¿Por qué usar rebasing cuando podemos usar merging?

    Existen varias razones. • Limpieza de historial ◦ Si tenemos muchos commits en una rama el rebase nos creará un parche en un commit limpiando el historial de mini commits ◦ Quitar commits embarazosos que no queremos que se vean (fallos, comentarios mal hechos...) • Colaboración ◦ Por ejemplo, en github si forkeamos un repositorio y hacemos un pull request no queremos que el propietario del repo se coma el marrón de hacer merge (conflictos, etc), por tanto con un rebase el propietario sólo tendrá que hacer un fast-forward merge y no tendrá ni conflictos ni historias extrañas
  125. $ echo "Eskerrik asko :)" > ./README $ git commit

    -avm "Se acabó" $ git push origin master
  126. Enlaces de interés • Libros ◦ Pro Git : http://progit.org/book

    • Alojamiento Git ◦ Github: https://github.com/ ◦ Bitbucket: https://bitbucket.org/ ◦ Gitorious: http://gitorious.org/ • Referencias ◦ GitRef: http://gitref.org/ ◦ Git-guide: http://rogerdudler.github.com/git-guide/ • Cheat Sheet ◦ https://github.com/AlexZeitler/gitcheatsheet • Casts ◦ GitCasts: http://gitcasts.com/ • Probar Git dinámicamente ◦ Trygit: http://try.github.com
  127. Imágenes • http://www.dylanbeattie.net/git_logo/ (Git custom logo) • http://southparkstudios.mtvnimages.com/shared/about/show-disclaimer.jpg (South park

    disclaimer) • http://www.peterhajas.com/media/img/email_icon.png (email Icon) • http://www.peterhajas.com/media/img/github_icon.png (github Icon) • http://www.peterhajas.com/media/img/twitter_icon.png (twitter Icon) • http://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Linus_Torvalds.jpeg/391px-Linus_Torvalds.jpeg (Linus Torvalds photo) • http://www.gnulinux.cat/wp-content/uploads/2011/12/Git-logo.svg_.png (Git logo) • http://progit.org/images/book-big.jpg (Progit book cover) • http://progit.org/figures/ch1/18333fig0102-tn.png (Progit book Ch 1-1) • http://progit.org/figures/ch1/18333fig0103-tn.png (Progit book Ch 1-1) • http://progit.org/figures/ch1/18333fig0104-tn.png (Progit book Ch 1-3) • http://progit.org/figures/ch1/18333fig0105-tn.png (Progit book Ch 1-3) • http://progit.org/figures/ch1/18333fig0106-tn.png (Progit book ch 1-3) • http://progit.org/figures/ch3/18333fig0301-tn.png (Progit book ch 3-1) • http://progit.org/figures/ch2/18333fig0201-tn.png (Progit book ch 2-2) • http://whygitisbetterthanx.com/images/index1.png (Why git is better than X staging area 1) • http://whygitisbetterthanx.com/images/index2.png (Why git is better than X staging area 2) • http://progit.org/figures/ch3/18333fig0308-tn.png (Progit book ch 3-1) • http://progit.org/figures/ch3/18333fig0309-tn.png (Progit book ch 3-1) • http://whygitisbetterthanx.com/images/local-remote.png (Why git is better than X data flow) • http://progit.org/figures/ch3/18333fig0317-tn.png (Progit book ch 3-2) • http://progit.org/figures/ch3/18333fig0322-tn.png (Progit book ch 3-5) • http://progit.org/figures/ch3/18333fig0323-tn.png (Progit book ch 3-5) • http://progit.org/figures/ch3/18333fig0324-tn.png (Progit book ch 3-5) • http://progit.org/figures/ch3/18333fig0313-tn.png (Progit book ch 3-2) • http://progit.org/figures/ch3/18333fig0314-tn.png (Progit book ch 3-2) • http://git-scm.com/figures/18333fig0327-tn.png (Progit book ch3-6) • http://git-scm.com/figures/18333fig0328-tn.png (Progit book ch3-6) • http://git-scm.com/figures/18333fig0329-tn.png (Progit book ch3-6) • http://git-scm.com/figures/18333fig0330-tn.png (Progit book ch3-6) • http://memegenerator.net/instance/23840726 (Philosoraptor)
  128. Todo el contenido (salvo las imágenes) de esta presentación esta

    distribuido bajo la licencia Creative commons BY-NC-SA 3.0 y pertenece a su autor Xabier (slok) Larrakoetxea Las imágenes pertenecen a sus respectivos dueños y conservan su licencia (ver imágenes)