Loading

Taller: Git es nuestro amigo

jansete

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

Git es nuestro amigo

Juanen Bernal Carrillo

about me

Juanen Bernal Carrillo / jansete

 

Drupalero desde 2011

 

Asistente MLP desde 2013, clan Sepiauno

 

Co-organizador Drupal Day Murcia 2015

 

Drupal Developer en WebPartners, Madrid

 

IRC y drupal.org: jansete / @jansev3n

Introducción

  • ¿Qué es un sistema de control de versiones?
    • Locales
    • Centralizados
    • Distribuidos
  • Ventajas
    • Historial de cambios
    • Posibilidad de deshacer cambios
    • Trabajo en equipo

 

CVS Local

Guardar de forma local una copia de seguridad de un archivo.

CVS Centralizado

Aparecen los primeros CVS orientados al trabajo en equipo, un ejemplo sería Subversion.

CVS Distribuido

  • Cada entorno clona por completo el repositorio. 

 

  • Si el servidor falla, es posible restaurar el repositorio a partir de cualquiera de sus clonaciones.

Breve historia de Git

  • Durante el mantenimiento de Linux entre 1991-2002 la mayoría de cambios se hacían en forma de parches y archivos.
  • En 2002 empezaron a usar un DVCS propietario, BitKeeper.
  • En 2005, la relación entre la comunidad de Linux  y BitKeeper se vino abajo.
  • La comunidad de Linux (Linus Torvalds en particular) desarrolló su propia herramienta a partir de la forma de trabajar que habían aprendido con BitKeeper.

 

Git: Fundamentos

  • Instantáneas, no diferencias.
  • Casi cualquier operación es local:
    • No necesitas acceder al servidor para navegar por el historial y volver a versiones anteriores.
    • No necesitas conexión para confirmar cambios.
  • Tiene integridad
    • Utiliza SHA-1 para generar el checksum, no puedes perder información o modificar archivos sin que Git lo sepa.
  • Muy dificil que el sistema haga algo que no se puede deshacer

Git: Estados

  • Confirmado (committed)
  • Modificado (modified)
  • No modificado (unmodified)
  • Preparado (staged)
  • Eliminados (deleted)
  • Bajo seguimiento (tracked)
  • Sin seguimiento (untracked)

Git: Áreas

  • Directorio de trabajo (working directory)
  • Área de preparación (staging area)
  • Git directory (repository)

Instalación

Instalación

  • Windows 
    • Instalador, GIT Bash
  • Linux
  • Mac 
    • Instalador
    • XCode
    • Brew

Niveles de configuración

Git: Configuración

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
$ git config --global core.editor emacs
$ git config --global merge.tool vimdiff
$ git config --list
user.name=Scott Chacon
user.email=schacon@gmail.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...
$ git config user.name
Scott Chacon

Git: Ayuda

$ git help <comando>
$ git <comando> --help
$ man git-<comando>
 git help config

Útil al no necesitar conexión para su consulta.

Se puede acceder de tres formas diferentes.

Git: Utilidades

$ git co<tab><tab>
commit config
$ git config --global alias.co checkout
$ git config --global alias.unstage 'reset HEAD --'

Git alias

Configurarte el autocompletado

 

Git: Comandos básicos

$ git init
$ git clone git://github.com/schacon/grit.git mygrit

Inicializar repositorio

Clonar repositorio

  • GIT
  • HTTP(S)
  • SSH

git status

$ git status
# On branch master
nothing to commit (working directory clean)

Comprobar el estado de tus archivos

Tip: Utiliza git status como guía.

$ vim README.md
$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   README.md
nothing added to commit but untracked files present (use "git add" to track)
$ git status .

Estado de tus archivos a partir del directorio actual.

git add

$ git add README.md

Seguimiento de nuevos archivos

Pasamos de estado untracked a estado staged (preparado)

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   README.md
#

Tip: Si quieres añadir a partir del directorio actual. Luego hablaremos de Git diff.

$ git add .
$ git add . --all # git add . -A

Preparando archivos modificados (1)

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   README.md
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#   modified:   index.html
#

Preparando archivos modificados (2)

$ git add index.html
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   README
#   modified:   index.html
#

Git no añade directorios vacíos

Ignorando archivos: .gitignore

Excluir todos los archivos que no tengan que ver con la estructura de tu proyecto:

  • Cache y otros archivos generados: (.sass-cache)
  • Recursos que forman parte del contenido: Fotos de una noticia, adjuntos, etc.

 

 

.gitignore

.gitignore admite:

  • Comentarios (#)
  • Expresiones regulares
  • Indicación de directorios (/)
  • Negar un patrón (!)

.gitignore

En una estructura de ficheros y directorios:

# se ignora todo
kitkat

# se ignora sólo el directorio kitkat
kitkat/

# se ignoran todos los archivos kitkat excepto el 
# directorio kitkat
kitkat
!kitkat/ 

git diff

Antes de preparar cualquier archivo, super recomendable

$ git diff [directorio|archivo]

Muestra las diferencias de los archivos trackeados y modificados.

Revisar diferencias de los archivos preparados:

$ git diff --cached
$ git diff --staged

Tip: Puedes crear un parche con:

$ git diff > parche.patch

También podemos hacer diff a una rama (lo veremos luego).

git diff

Aspecto de git diff

$ git diff
diff --git a/benchmarks.rb b/benchmarks.rb
index 3cb747f..da65585 100644
--- a/benchmarks.rb
+++ b/benchmarks.rb
@@ -36,6 +36,10 @@ def main
           @commit.parents[0].parents[0].parents[0]
         end
 
+        run_code(x, 'commits 1') do
+          git.commits.size
+        end
+
         run_code(x, 'commits 2') do
           log = git.commits(`master`, 15)
           log.size
$ git diff .

Diff a partir del directorio actual.

git commit

Confirmando nuestros cambios: pasamos del área de preparación a guardar los cambios en el directorio de git.

# Resumen de cambios, necesitamos introducir un mensaje.
$ git commit

# Igual pero te muestra también un diff
$ git commit -v 

# Introducimos directamente el mensaje
$ git commit -m 'Add title in index.' 

# Te añade al commit los archivos trackeados
$ git commit -am 'Fix checkbox behavior.' 

git commit

Tips:

  • Commits descriptivos para facilitar futuras búsquedas
  • Utilización de infinitivos en los mensajes.
  • Evitar realizar commits con cambios a medio hacer.

git rm

Hay varias formas de eliminar archivos de seguimiento.

# Elimina el archivo pero no de git
$ rm grit.gemspec 

# Elimina el archivo de git (staged), 
# y si existe también del disco duro.
$ git rm grit.gemspec 

# Si un archivo ha sido eliminado 
# podemos también pasarlo a staged.
$ git add . --all 

# Eliminamos del stage. Luego veremos más usos
$ git rm --cached readme.txt 

También existe git mv para archivos que cambian de ruta o de nombre.

$ git mv file_from file_to

git log

Viendo el histórico de confirmaciones

$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700
 
    changed the version number
 
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700
 
    removed unnecessary test code
 
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700
 
    first commit

git log

Algunas opciones

  • Se pueden añadir las diferencias introducidas (-p)
  • Limitar las entradas a mostrar (-2)
  • Estadísticas (--stat)
  • Formateo CUSTOM (--pretty)
  • Ver un gráfico de ramas (--graph)
  • Filtrar por fechas (--since y --until)

Ejemplo:

$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

Oooops

Git te ayuda a solucionar tus cagadas

git commit --amend

Hice commit demasiado rápido:

  • Me equivoqué en el mensaje
  • Se me olvidaron añadir archivos.
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

git reset HEAD <file>

Hice git add . y añadí archivos que no quería.

$ git add .
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   README.txt
#       modified:   benchmarks.rb
#

git reset HEAD <file>

Quitamos los archivos del stage.

$ git reset HEAD benchmarks.rb
benchmarks.rb: locally modified
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   README.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   benchmarks.rb
#

Tip: git status ya nos dice cómo hacerlo.

git checkout <file>

Este cambio no me vale!

$ git status
# En la rama master
# Cambios no preparados para el commit:
#   (use «git add <archivo>...» para actualizar lo que se ejecutará)
#   (use «git checkout -- <archivo>...« para descartar cambios en le directorio de trabajo)
# 
# 	modified:   despensa/kitkat/juanen
# 
# no hay cambios agregados al commit (use «git add» o «git commit -a»)
$ git checkout .
$ git status
# En la rama master
# nothing to commit, working directory clean

acabo de commitear datos sensibles

contraseñas, cuentas bancarias, fotos de la mujer de mi mejor amigo

Con git filter-branch podemos borrar un archivo sin dejar rastro en el repositorio, es decir, ese archivo no aparecerá en ningún commit, su funcionalidad es reescribir grandes porciones del historial de forma automática.

$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
Ref 'refs/heads/master' was rewritten

eliminar el último commit subido a un remote: git revert

Con git revert realizamos un nuevo commit que deshace los cambios a partir del commit que le digamos bajo la nomenclatura HEAD~N

$ git revert HEAD~3

Crea un commit deshaciendo los 3 últimos commits.

eliminar un archivo del repo sólamente: git rm --cached <archivo>

El típico caso que has subido al repositorio algún archivo de configuración de tu IDE o de tu sistema operativo.

$ git rm --cached .idea

remotes

  • Para trabajar en equipo es necesario gestionar los repositorios remotos. 
  • Con ellos obtendremos (pull) y enviaremos (push) nuestros cambios.
  • Normalmente tenemos origin como remote por defecto, pero podemos tener más.

git remote -v

A ver con qué remote trabajo...

Listando los remotes disponibles

$ git remote -v
origin	git@bitbucket.org:juanenbernal/beershanseaticos.git (fetch)
origin	git@bitbucket.org:juanenbernal/beershanseaticos.git (push)
server	ssh://juanen@beershanseaticos.com:/opt/git/beershanseaticos.git (fetch)
server	ssh://juanen@beershanseaticos.com:/opt/git/beershanseaticos.git (push)

git remote sin opción sólo te muestra el nombre del remote sin su url asociada.

git remote add

Añadiendo más repositorios remotos

$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
origin  git://github.com/schacon/ticgit.git
pb  git://github.com/paulboone/ticgit.git

git remote

Otras opciones

$ git remote show origin
* remote origin
  URL: git://github.com/schacon/ticgit.git
  Remote branch merged with 'git pull' while on branch master
    master
  Tracked remote branches
    master
    ticgit

# Modifica el nombre del remote
$ git remote rename pb paul

# Elimina el remote paul
$ git remote rm paul

# Actualizar la información de los remotes
$ git remote update 

git fetch <remote>

git fetch origin recupera toda la información enviada a ese servidor desde que lo clonaste (o desde la última vez que ejecutaste fetch).

 

Sólo recupera la información y la pone en tu repositorio local, no la une automáticamente con tu trabajo ni modifica aquello en lo que estás trabajando. Tendrás que unir ambos manualmente a posteriori .

Este proceso también lo hace git pull y une los cambios a tu repo local.

git tag

Marcar como importante el estado del repositorio.

  • Etiquetas Ligeras
    • Un puntero a una confirmación específica.
  • Etiquetas anotadas
    • Objetos completos en la BD de Git.
      • Checksum
      • Nombre del etiquetador
      • Email
      • Fecha
      • Mensaje, etc

Etiquetas ligeras

Para crear una etiqueta ligera no añadimos las opciones -a-s -m:

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5

$ git show v1.4-lw
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sun Feb 8 19:02:46 2009 -0800
 
    Merge branch 'experiment'

Etiquetas anotadas

$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4

$ git show v1.4
tag v1.4
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Feb 9 14:45:11 2009 -0800
 
my version 1.4
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sun Feb 8 19:02:46 2009 -0800
 
    Merge branch 'experiment'

También existen las etiquetas firmadas y verificadas con GNU Privacy Guard

tag a posteriori y compartir tags

$ git tag -a v1.2 9fceb02

$ git push origin v1.5
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
* [new tag]         v1.5 -> v1.5

$ git push origin --tags
Counting objects: 50, done.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (44/44), 4.56 KiB, done.
Total 44 (delta 18), reused 8 (delta 1)
To git@github.com:schacon/simplegit.git
 * [new tag]         v0.1 -> v0.1
 * [new tag]         v1.2 -> v1.2
 * [new tag]         v1.4 -> v1.4

ramas

git branch

Con git branch podemos obtener un listado de las ramas disponibles, crear ramas nuevas y eliminarlas.

# Creamos la rama develop
$ git branch develop

# Creamos otra rama
$ git branch feature/ZEL-455 

# Listamos las ramas disponibles
$ git branch 
#   develop
#   feature/ZEL-455
# * master

# Borramos la rama de forma local
$ git branch -d feature/ZEL-455 

# Obtener sólo las ramas remotas
$ git branch -r 

# Obtener sólo ramas remotas y locales
$ git branch -a 

git branch

Eliminando las ramas de tu repositorio remoto

$ git push origin :feature/ZEL-455

git checkout

Ya vimos como rechazar los cambios con git checkout .

git checkout también tiene otras utilidades

# Cambiamos a la rama develop con todos los 
# archivos del área de trabajo si los hay
$ git checkout develop

# Cambiamos a una rama que creamos
$ git checkout -b feature/ZEL-455

# Consultamos un commit, pero no para trabajar sobre él
$ git checkout 84ac4b0

git merge <rama>

Una vez creada la rama feature/ZEL-455 queremos unir nuestros cambios a la rama de desarrollo y posteriormente eliminar la rama ya no usada.

$ git checkout -b feature/ZEL-455
$ git checkout develop
$ git merge feature/ZEL-455
$ git branch -d feature/ZEL-455
$ git push origin :feature/ZEL-455

resolución de conflictos

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

 Si hay modificaciones dispares en una misma porción de un mismo archivo en las dos ramas distintas que pretendes fusionar, Git no será capaz de fusionarlas directamente.

Podemos encontrar conflictos que deberemos resolver manualmente.

resolución de conflictos

 <<<<<<< HEAD:mergetest
 This is my third line
 =======
 This is a fourth line I am adding
 >>>>>>> 4e2b407f501b68f8588aa645acafffa0224b9b78:mergetest

 Si accedemos al archivo conflictivo tenemos:

<<<<<<< Comienzo del conflicto

======= Break point de la comparación

>>>>>>> Final del conflicto

Una vez seleccionado el código correcto, preparamos y confirmamos los cambios.

gestión de ramas

$ git branch
#   develop
#   feature/ZEL-455
#   feature/ZEL-461
#   feature/ZEL-464
#   feature/ZEL-466
#   feature/ZEL-467
# * master

Es importante tener unos remotes ordenados y controlar el número de ramas que hay en ellos. Un buen truco para eliminar ramas que ya no son usadas y están incluidas en otras es:

git branch --merged

gestión de ramas

$ git branch --merged
#   develop
#   feature/ZEL-461
#   feature/ZEL-464
#   feature/ZEL-466
#   feature/ZEL-467
# * master

La rama feature/455 tiene nuevos cambios, mientras que el resto de ramas ya fueron fusionadas con master y develop. Si hacemos git branch --merged desde la rama master obtendremos todas las ramas que ya se fusionaron en ella y que podrían borrarse con tranquilidad. Es decir, todas menos la 455.

gestión de ramas

$ git branch --no-merged
#   feature/ZEL-455

Podemos tener el resultado contrario con:

git branch --no-merged

git pull <remote> <branch>

$ git pull origin master
#   remote: Counting objects: 7, done.        
#   remote: Compressing objects: 100% (4/4), done.        
#   remote: Total 4 (delta 2), reused 0 (delta 0)        
#   Updating 361303d..f2cd831
#   Fast forward
#    _layouts/default.html |    1 +
#     1 files changed, 1 insertions(+), 0 deletions(-)

Para obtener los cambios de un repositorio remoto utilizaremos git pull, al realizar la descarga se producirá una fusión con el código actual, que como vimos anteriormente con merge ocasionalmente puede provocar conflictos.

git push <remote> <branch>

$ git push origin serverfix
#  Counting objects: 20, done.
#  Compressing objects: 100% (14/14), done.
#  Writing objects: 100% (15/15), 1.74 KiB, done.
#  Total 15 (delta 5), reused 0 (delta 0)
#  To git@github.com:schacon/simplegit.git
#   * [new branch]      serverfix -> serverfix

Para publicar nuestros cambios en un repositorio remoto utilizaremos git push. 

Si un colaborador ha hecho cambios, git rechazará tu subida para que en primer lugar bajes sus cambios, los fusiones y entonces ya puedes realizar la subida.

git rebase

En lugar de mezclar los cambios, podemos reorganizarlos con git rebase en una sóla rama. 

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

git rebase

Vuelve al commit común y empiezan a aplicarse los cambios de una rama a otra, teniendo las siguientes opciones en caso de conflicto:

  • --continue
  • --skip
  • --abort
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

En este caso se aplicarían los commits de la rama experiment encima de los de la rama master, a partir del commit común.

git en un servidor

Igual que BitBucket o GitHub, podemos utilizar un servidor como repositorio remoto y de esta manera evitar el uso de guardar claves ssh con permisos incorrectos en dicho servidor si lo consideramos oportuno.

$ cd /opt/git/my_project.git
$ git init --bare

Creación del Repo
SERVER:~             > cd /opt
SERVER:/opt            > mkdir git
SERVER:/opt            > cd git
SERVER:/opt/git        > mkdir youdrim.git
SERVER:/opt/git         > cd youdrim.git
SERVER:/opt/git/youdrim.git    > git --bare init
PC:/var/www/local.youdrim     > git remote add server ssh://root@5.135.184.143:22022/opt/git/youdrim.git
PC:/var/www/local.youdrim     > git push server master
SERVER:~            > cd /var/www/vhosts
SERVER:/var/www/vhosts > git clone /opt/git/youdrim.git youdrim.com
 

Flujo de trabajo normal de cambios
PC > git commit -am ‘Cambios’ #Haces cambios en tu PC
PC > git push origin master #subir cambios a master repo origen
PC > git push server master #subir cambios al servidor, pedirá clave ssh
SERVER > git pull origin master #en el server es origin

Tip: Puedes añadir claves SSH para evitar meter la contraseña

git en un servidor

Hooks y deploys automáticos

Git también tiene hooks (.git/hooks):

  • pre-commit
  • pre-push
  • pre-rebase
  • update
  • post-update
  • ...

Podemos utilizar comandos al dispararse dichos eventos, como por ejemplo, con post-update si tuviésemos un remote "devel", podríamos automatizar que con cada push a dicho remote, en devel hiciese git pull ahorrando tiempo en el proceso.

ahora vuelvo!

Necesitas rápidamente un cambio de rama cuando tienes algo a mitad de hacer.

 

Ejemplo: Estás a mitad de un desarrollo, tienes algo a medio y ocurre una incidencia rápida en producción que tienes que abordar.

 

git stash

git stash

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#

$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")

$ git status
# On branch master
nothing to commit (working directory clean)

listar la pila de guardado

Podemos consultar todos los cambios guardados en stash:

git stash list

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

recuperando los cambios

Podemos recuperar tanto el último cambio como cualquiera de los anteriores.

git stash apply

$ git stash apply
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   index.html
#      modified:   lib/simplegit.rb
#

# Recupera un stash con el estado de los files
$ git stash apply --index 

# Recupera un stash determinado
$ git stash apply stash@{2} 

eliminar del stash

Podemos eliminar los cambios temporales de la pila de guardado con

git stash drop <stash>

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"
stash@{2}: WIP on master: 21d80a5... added number to log

$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

creando una rama a partir del stash

$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)

consultar los cambios del stash

$ git stash show -p stash@{0}

Para consultar las diferencias de un stash y poder identificar el que buscamos.

Devuelve un diff de ese stash.

alternativa a git stash

git checkout -b rama_nueva
git add .
git commit -m 'Temporal commit'
git reset --soft commit

git stash sólo actua sobre los archivos que se encuentran trackeados, es posible que en alguna ocasión necesitemos guardar todo en un commit temporal

viajando al pasado:

git reset

Con git reset podemos volver a commits anteriores o bien para desechar los commits que queden por el camino, o para continuar desde el punto en el que se cometió un error manteniendo todos los cambios actuales.

git reset --soft <commit>

De esta manera podemos volver a un commit anterior, manteniendo todos los cambios que se hicieron hasta dicho commit en nuesto área de preparación. 

git status
En la rama master
nothing to commit, working directory clean

$ git log
commit 0bef7ddd058c408d0d0ebd68bedcff4c04cc9b44
Author: Juanen <jbernal@murdock.es>
    Add kitkat for Juanen

commit 14563bab48595a829d5e469afc458d94f3e66f05
Author: Juanen <jbernal@murdock.es>
    First commit.

$ git reset --soft 14563bab48595a829d5e469afc458d94f3e66f05
$ git status
En la rama master
Cambios para hacer commit:
  (use «git reset HEAD <archivo>...«para eliminar stage)

	modified:   despensa/kitkat/juanen
	new file:   parche.patch

git reset --hard <commit>

Queremos definitivamente volver a un commit y no mirar atrás, perdiendo los cambios de los commits intermedios en la línea actual de trabajo.

git status
En la rama master
nothing to commit, working directory clean

$ git log
commit 0bef7ddd058c408d0d0ebd68bedcff4c04cc9b44
Author: Juanen <jbernal@murdock.es>
    Add kitkat for Juanen

commit 14563bab48595a829d5e469afc458d94f3e66f05
Author: Juanen <jbernal@murdock.es>
    First commit.

$ git reset --hard 14563bab48595a829d5e469afc458d94f3e66f05
$ git status
En la rama master
$ git log
commit 14563bab48595a829d5e469afc458d94f3e66f05
Author: Juanen <jbernal@murdock.es>
    First commit.

No todo está perdido!

Para restaurar un git reset --hard equivocado tenemos diferentes formas:

$ git fsck --lost-found

Si conocemos el commit en el que estábamos:

$ git reset --hard commit

Si no lo conocemos:

Este comando nos mostrará commits huérfanos. Por lo tanto podemos comprobar con el commit que devuelve haciendo git checkout commit, si es el commit que buscamos y luego:

$ git checkout <rama>
$ git reset --hard <commit>

reescribiendo la historia

Con git podemos reescribir por completo toda la historia de nuestros commits:

  • Modificar la última confirmación de cambios (git commit --amend)
  • Reorganizar las ramas (git rebase)
  • Combinar varios commits en uno
  • Dividir un commit en varios

depuración

No sabemos exactamente donde está nuestro fallo pero tenemos una idea aproximada desde cuando empezó a petar:

git bisect

$ git bisect start
$ git bisect bad
$ git bisect good
$ git bisect reset

Vuelve al commit intermedio del intervalo, una vez probemos si se sigue replicando el error o no, usaremos bad o good para navegar entre los commits restantes.

submódulos

Repositorios dentro de repositorios:

¿por qué actualizar de forma manual el mismo módulo que utilizo en diferentes repositorios?

git submodule add git@github.com:jansete/message_nodejs_rules.git 
sites/all/modules/message_nodejs_rules

Añadimos nuestro submódulo una vez situados en el repositorio padre

submódulos

Una vez que nos situemos dentro del submodule, git sólo actuará dentro de él. Es decir podemos hacer cambios y realizar commits que pueden ser recuperados en otros sitios donde se encuentre este repo.

git submodule update

Podemos actualizar el submódulo desde el repositorio padre.

política de ramas

Evita trabajar en master, usa una política de ramas que te facilite el trabajo en equipo y cambiar rápidamente en casos de emergencia, como git flow:

  • master
  • develop
  • feature
  • release
  • hotfix

y más y más y más

git no acaba aquí, hay más comandos y posibilidades muy útiles.

 

  • --force
  • git blame
  • git grep
  • git cherry-pick
  • etc, etc

Bibliografía

Otros enlaces de Interés:

¿Preguntas?

Made with Slides.com