¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Commits
Sección perteneciente al curso Control de versiones con Git Avanzado.
Introducción
Una de las unidades más importantes. Veremos cómo preparar un commit. Un commit no es un backup sino un momento concreto en la historia de cambios de nuestro proyecto. Una de las características más potentes de Git es que nos permite preparar el commit, qué ficheros van a ir a un commit y cuáles no.
También veremos cómo ver commits del pasado y cómo deshacerlos.
Preparación de un commit por etapas
Trabajando con el stage
Tanto para añadir nuevos archivos al repositorio (empezar a versionar) como para añadir modificaciones en archivos ya existentes, tendremos que “subirlos al stage”:
git add <RUTA>
Para inicializar un repositorio, es decir, que Git pueda empezar a trabajar con él, ejecutamos dentro del directorio el comando git init. A partir de entonces ya podremos usar git.
Cuando queremos “subir al stage” un archivo:
git add archivo
Si queremos añadir más de un archivo:
git add archivo1 archivo2 archivo3
Si queremos añadir un tipo de ficheros:
git add *.html
Para subir todos los archivos y modificaciones pendientes de pasar al stage y que estén en la carpeta actual (y todas las carpetas hijas):
git add .
Para ver información sobre las 3 zonas que usamos en Git, usamos el siguiente comando:
''git status''
Podemos ver un resumen de los ficheros que están en el stage y los que no están siendo controlados (versionados) por git. Los primeros aparecen en color verde y los segundos en color rojo. Otra forma de decirlo sería que lo que está en verde es lo que está en el stage y lo que está en rojo es lo que está en el working directory.
Poner captura con ejemplo de lo anterior
git status es un comando muy útil y es recomendable lanzar cada vez que ejecutemos algún comando de git. También ofrece “pistas”.
Si queremos quitar modificaciones del stage (por algún error):
git reset HEAD <RUTA_FICHERO>
Por ejemplo, si queremos quitar el fichero fichero1:
git reset HEAD archivo1
Si queremos quitar todos los cambios que haya en el stage:
git reset HEAD .
En realidad, el comando git reset sirve para otra cosa que se verá más adelante.
Para deshacer cambios en el working directory, es decir, para que Git deje los archivos modificados como estaban en el último commit:
git checkout -- <RUTA_FICHERO>
Por ejemplo, si queremos volver al estado anterior de todos los archivos del working directory:
git checkout -- .
Esta operación es irreversible, no se puede deshacer.
Finalmente, si queremos borrar un archivo tenemos dos opciones. Si el borrado lo hacemos mediante las operaciones del sistema operativo, Git lo entiende como una modificación del proyecto y podremos subirlo al stage para luego hacer un commit con ese borrado.
Si usamos el método Git:
git rm <RUTA_FICHERO>
Git lo borra del sistema de ficheros y añada esa modificación al stage, ahorrándonos un paso respecto a la versión usando el sistema operativo.
Si queremos quitar un archivo del repositorio sin borrarlo del working directory:
git rm --cached <RUTA_FICHERO>
Esto es útil cuando llegado un momento queremos empezar a ignorar un fichero que antes estábamos siguiendo (el .gitignore aquí no serviría).
Tras “desversionar” lo que queremos, ahora sí podremos modificar el .gitignore para añadir ese fichero o ficheros que no queremos que Git versione.
Realizando el commit
Un commit siempre necesita un mensaje descriptivo (es obligatorio):
git commit -m "Mensaje"
Si queremos que abra el editor por defecto para que luego añadamos el comentario:
git commit
El commit siempre se hace sobre lo que hay en el stage
Como recomendación, en los mensajes de commit habría que evitar genéricos como “Cambios”, “Nuevo archivo”, “Correcciones”, “CSS”, “Merge”… A la hora de escribir un mensaje, tenemos que explicar bien qué modificaciones sufre el proyecto y de forma muy breve. El propósito es que cuando se quiera ver el log, se pueda entender perfectamente los cambios que ha sufri oel proyecto:
git log --oneline --branches --graph
Si queremos modificar el último commit (solo el último) que hemos hecho:
git commit --amend
Esto lo haremos tras añadir cambios al stage.
Al ejecutar el comando anterior, se abrirá el mensaje del último commit (el que queremos modificar) dándonos la posibilidad de modificarlo, si queremos.
Si el commit ya se había subido al repositorio remoto, no se debe hacer --amend. Las correcciones en los commits hay que hacerlas en el repositorio local.
Otra cosa que suele pasar mucho es que hayamos hecho un commit con un mensaje incorrecto o incompleto. Si queremos corregir este mensaje, pero no tenemos más cambios, no hace falta subir nada al stage, basta con ejecutar el siguiente comando:
git commit --amend -m "Nuevo mensaje"
Si no le pasamos el mensaje por línea de comandos, git abrirá el editor por defecto.
Esta modificación cambia el hash del commit. Esto es normal porque este hash se genera a partir del contenido del título y otras cosas.
Ejemplos de commits por etapas
Añadir capturas de pantalla con las zonas de git y cómo se mueven los archivos cuando se preparan los commits.
Iniciamos un repositorio git:
git init
git status
Subiremos al stage el fichero despedidas-en.json:
git add despedidas-en.json
git status
Hacemos commit:
git commit -m "Commit inicial"
Es práctica habitual incluir el mensaje “Commit inicial” en el primer commit de un proyecto
git log --oneline --branches
git status
Subimos el fichero saludos-en.json al stage:
git add saludos-en.json
Hacemos el commit:
git commit -m "Añadidas traducciones de saludos"
git log --oneline --branches
Modificamos el fichero saludos-en.json. Ahora git reconocerá que hay un cambio en el working directory:
git status
Subimos el fichero al stage:
git add saludos-en.json
Hacemos el commit:
git commit -m "Añadida despedida"
Vemos el log:
git log --oneline --branches
Creamos un nuevo fichero en el working directory: lugares-en.json. También hacemos modificaciones en el fichero saludos-en.json. Git nos avisará de estos cambios.
git status
Añadiremos al stage solo dos ficheros:
git add lugares-en.json despedidas-en.json
Hacemos commit:
git commit -m "Añadido fichero de lugares y añadido saludo"
Vemos el log:
git log --oneline --branches
Subimos al stage saludos-en.json modificado.
git add saludos-en.json
Pero nos arrepentimos, y lo quitamos del stage:
git reset HEAD saludos-en.json
Git nos dirá que aún está pendiente el cambio de ese fichero en el working directory:
git status
Pero si queremos volver a la versión del último commit del fichero saludos-en.json:
git checkout -- .
Recordad que este último comando es irreversible
Partes de un commit
Hasta ahora hemos visto qué es un commit. Ahora veremos los datos que llevan asociados los commits:
- Autor / “committer”: nombre y correo electrónico de quien realiza el commit.
- Fecha y hora
- Mensaje
- Padre/s: un commit puede tener un padre o 2 (es raro que haya más).
- Hash de 40 caracteres: se obtieen al aplicar SHA-1 al autor, fecha, mensaje y contenido del commit.
git log
Poner ejemplo de todo lo anterior
El log
El log es el listado de commits a lo largo del tiempo.
Comandos para trabajar con el log
Ver el histórico de commits:
git log [rama]
Si no se indica la rama, git log nos mostraría el nombre de la rama en la que nos encontremos.
Para ver el log de forma compacta:
git log --oneline
Así veremos un commit por línea. No mostrará autor ni fecha.
Ver el log de todas las ramas:
git log --branches
Ahora podemos mezclar los modificadores para ver el log en formato compacto y de todas las ramas:
git log --oneline --branches
Al trabajar con ramas, es útil tener una representación gráfica de las divergencias, cómo se ha bifurcado el código:
git log --graph --branches
Podemos crear alias para comandos largos que usemos habitualmente:
git config --global alias.milog "log --oneline --branches --graph"
Habremos creado un alias llamado milog, y para usarlo:
git milog
Para ver el contenido de un commit:
git show <HASH_COMMIT>
Poner ejemplo del comando anterior
Con el comando anterior podremos ver las diferencias con el commit anterior. El formato que es usa es el de los parches (patch)
Podemos referenciar un commit de varias maneras:
- Por su identificador hash SHA-1 (lo que vimos anteriormente)
- Su posición respecto al HEAD
- Por el nombre de una rama
- Por su posición en el listado de reflog:
HEAD@{n}
git show HEAD
Commit anterior al commit apuntado por HEAD:
git show HEAD~1
Es lo mismo que
git show HEAD~
Dos commits antes:
git show HEAD~2
Es lo mismo que
git show HEAD~~
Esto es muy útil cuando queremos deshacer commits.
Si un commit tiene más de un padre, usamos la notación siguiente:
git show HEAD^1
Haremos referencia al primer padre.
git show HEAD^2
Haremos referencia al segundo padre.
Referenciando un commit por la rama que apunta:
git show nombre_rama
git reflog nos enseña una secuencia de movimientos de la referencia HEAD. Esto es útil si hemos “perdido” un commit.
git checkout HEAD@{1}
Nos habremos ido al commit al que apuntaba HEAD en cierto momento.
Poner gráfico con detached HEAD
Saltos entre commits, reset y reflog
Saltar a otro commit o rama:
git checkout <COMMIT o RAMA>
Para el nombre el commit podemos usar las referencias que vimos en el apartado anterior.
El checkout hará dos cosas: moverá el HEAD de donde esté al que estamos indicando ; la segunda cosa es que va a coger el working directory tal cual está y lo va a transformar al estado en el que estaba en el commit al que nos movemos.
Para “borrar” commits:
git reset <COMMIT>
Realmente no se borran, sencillamente desaparecen de nuestra vista. Esto permite que podamos recuperarlos en cualquier momento (si no ha pasado demasiado tiempo y ha pasado el recolector de basura de Git).
Por ejemplo, si quremos deshacer los últimos 3 commits:
git reset HEAD~3
El comando reset tiene 3 modificadores:
--soft: los cambios hechos en los commits que borramos, git los coloca en el stage. Este método se suele usar para comprimir commits.--mixed: los cambios hechos en los commits que borramos, git los coloca en el working directorio. Es la opción por defecto.--hard: los cambios hechos en los commits que borramos, desaparecen (de la vista).
Cuando desarrollamos en un equipo y queremos ver quién fue la última persona que hizo cada cambio:
git blame <RUTA>
Es útil para seguir una traza y poder encontrar quién hizo qué cosa.
Apartar cambios con stash
stash sirve para apartar cambios (en el working directory o en el stage) temporalmente.
Esto es muy útil cuando Git no nos deja movernos de rama (checkout) porque esos cambios machacarían nuestros ficheros.
stash es una pila, lo que entra queda en la parte superior.
git stash siempre va acompañado de un comando.
Para coger unos cambios y meterlos en la pila de “stashes”:
git stash [push -m "Mensaje"]
Listar todo lo que hay en el stash:
git stash list
Poner ejemplos del comando anterior
Si queremos ver el contenido de cierto stash:
git stash show [stash@{n}] [-p]
Para sacar los cambios del stash y colocarlos en el working directory o stage:
git stash apply [stash@{n}]
El comando anterior no quita el stash de la pila. Si además queremos quitarlo de la pila, usaremos este otro comando:
git stash pop [stash@{n}]
Si queremos borrar de la pila un stash sin aplicarlo:
git stash drop [stash@{n}]
Cómo deshacer
Conclusión
Recursos
- Capítulo del libro Pro Git con una explicación sobre el comando git reset:
- Capítulo del libro Pro Git con una explicación sobre el Working Directory, el stage y el repositorio local:
- Capítulo del libro Pro Git con un resumen sobre cómo deshacer cosas en el Working Directory y en el stage:
