Tabla de Contenidos
Git
Herramienta para el control de versiones de ficheros. Convierte nuestro ordenador en una máquina del tiempo.
Características
- Trabajo en equipo
- Listado y fecha de cambios (commits)
- Volver atrás en el tiempo para restablecer cambios
- Ramas de desarrollo
- Mezclar cambios entre compañeros
- Repositorio distribuido (cada integrante del equipo tiene una copia del repositorio)
Terminlogía
- HEAD: último commit en la rama actual o la línea del tiempo en la que estamos trabajando.
- Commit
- stage
- branch (rama)
- tag (etiqueta): referencia a un commit específico.
El repositorio local esta compuesto por tres “árboles” administrados por git:
- Working directory (directorio de trabajo): donde están los archivos en los que trabajamos
- Staging area / Index (zona de preparación): fase en la que los ficheros esperan a ser confirmados sus cambios.
- Repositorio Git / Head: se guardan los cambios confirmados y se crea un punto.
Por lo tanto, el flujo de trabajo en Git consiste:
- Modificar archivos en el directorio de trabajo
- Preparar los archivos añadiéndolos a la zona de preparación
- Confirmar los cambios
Acciones:
- De working directory a staging: stage
- De staging a head: commit
- De HEAD a working dir: checkout
Ayuda
git help <comando-git>
Configuración
Usuario
git config --global user.name "Nombre usuario"
git config --global user.email "email@contacto.es"
Para comprobarlo:
git config user.name -> Nombre usuario git config user.email -> email@contacto.es
O podemos verlo todo junto con:
git config --global --list
La opción list se puede abreviar como l
Editor
Por defecto, Git usa el editor que se haya definido en alguna de las variables de entorno VISUAL o EDITOR o el editor vi para crear mensajes de commit o etiqueta (tag). Para modificar este comportamiento:
git config --global core.editor vim
Alias
git config --global alias.lg "log --oneline --decorate --all --graph"
Acabamos de crear el alias lg de tal que manera que al escribir git lg se ejecutará git log --oneline --decorate --all --graph
Podemos ver los alias que tenemos definidos en la configuración:
git config --global -l
Repositorios
Creación
Dentro del directorio donde queramos crear un repositorio Git, ejecutamos:
git init
Esto creará un directorio oculto llamado .git. En ese directorio se guardarán los commits, las ramas, etc. todo lo relacionado con el repositorio actual.
Estado
git status
Mostrará lo que existe en un directorio y si están siendo registradas o no por Git:
On branch master
No commits yet
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)
Si los archivos aparecen en rojo, no están siendo registrados por Git. Si están en verde quiere decir que están en STAGE y listos para incluirlos en un commit.
Si queremos añadir todos los archivos del directorio para que Git los gestione:
git add .
Si queremos mostrar solo los ficheros que se han modificado:
git status -s
Para saber en qué rama estamos trabajando:
git status -b
Renombrar y eliminar archivos
Con Git
Para cambiar el nombre:
git mv nombre-antiguo nombre-nuevo
Para eliminar archivos:
git rm nombre-archivo
Al renombrar y borrar mediante Git, estas operaciones quedarán reflejadas en su histórico.
Sin Git
Cuando hacemos cambios a nivel de sistema de ficheros (renombrar ficheros o borrarlos), Git se da cuenta de que hay cambios no registrados.
Actualizamos el repositorio para que esos cambios pasen al STAGE:
git add -u
Y luego ya podríamos realizar el commit.
Ignorar archivos
Si tenemos ficheros que no queremos que Git registre, debemos crear un fichero llamado .gitignore (lleva un punto inicial):
fichero-excluir.txt *.log node_modules
Con ese fichero le diremos a Git que no haga el seguimiento de fichero-excluir.txt, los que terminen en .log y la carpeta node_modules.
Commits
Para añadir los ficheros a stage y crear el commit con un mensaje en un único paso:
git commit -am "Mensaje de commit"
Corregir mensajes
git commit -m "Mensaje de commit"
Si no añadimos la opción m, Git abrirá el editor de texto que se haya definido para escribir el mensaje de commit.
Corregir commit
Si queremos hacer algún cambio en cierto commit, identificado como 4e809d4, por ejemplo:
git reset --soft 4e809d4
En ese momento tendremos en nuestro directorio los ficheros tal cual estaban en ese punto.
Por defecto, al hacer un reset Git aplica la opción mixed avisando de los ficheros que cambiaron en el futuro, es decir, los ficheros que se modificaron después del commit al que hayamos hecho reset. Esos ficheros tendrán los cambios, pero no estarán añadidos al STAGE. Si queremos hacer un reset y descartar los futuros cambios, utilizaremos la opción hard:
git reset --hard 4e809d4
Recuperarse de reset
Aunque hayamos hecho reset sobre ciertos commits, Git internamente guarda todo lo que va sucediendo en el repositorio. Podemos verlo con:
git reflog
Como aparecerán todos los hashs de los commits, podremos recuperarlo con reset:
git reset --hard 4e809d4
Esto nos traerá todos los commits hasta ese indicado
Diferencias entre commits
Si queremos ver las diferencias entre el último commit y lo que tengamos en nuestro directorio:
git diff
Si queremos ver las diferencias entre lo que dejamos en STAGE y lo que había en el último commit:
git diff --staged
Ver cambios
Listado completo de commits del repositorio
git log
Ejemplo:
commit d6fc8b73db822cb4f8b755e7be31d55741f2512c (HEAD -> master)
Author: Rodríguez, Fulanito <frodriguez@example.com>
Date: Thu Jul 8 11:32:17 2021 +0200
Creado archivo README.md
Mostrar versión corta:
git log --oneline
Mostrar versión corta y decorada:
git log --oneline --decorate --all --graph
Deshacer cambios
Si queremos dejar todo como estaba en el último commit, es decir, recuperar el último commit:
git checkout -- .
Esto es muy útil cuando por error borramos algunos archivos o guardamos modificaciones que no queríamos. Utilizando el comando anterior podremos volver al estado del último commit.
Podemos seleccionar solo un archivo a revertir:
git checkout -- archivo.ext
Corregir commits
Si queremos modificar el mensaje del último commit:
git commit --amend -m "Nuevo mensaje de commit"
Si queremos modificar el mensaje y ficheros del último commit:
git reset --soft HEAD^
Hacemos los cambios que nos interesen y finalmente añadimos todo y corregimos:
git commit -am "Commit corregido"
Añadir ficheros a seguimiento
Añadir un fichero o lista de ellos:
git add fichero.ext [<fichero2.ext> <ficheroN.ext>]
Añadir grupo de ficheros por extensión del directorio actual:
git add *.ext
Añadir grupo de ficheros por extensión en todo el directorio (recursivo):
git add "*.ext"
Añadir directorio:
git add css/
Añadir todos menos y descartar alguno. Para ello tenemos que hacerlo en dos fases. Primero añadimos todos a STAGE:
git add .
Y ahora lo excluiríamos:
git reset archivo.txt
Clonación
Snippets
Log con nombre de ficheros
Para mostrar el nombre de los ficheros por commit:
git log --name-only
Ejemplo de salida:
Author: Rodríguez, Fulanito <frodriguez@email.com>
Date: Tue Nov 24 13:24:41 2020 +0100
Modificado actualizador de datos
Correcciones en la actualización de la información a través de la API
que provocaba un desbordamiento.
informes/proyecto/application/controllers/update.php
informes/proyecto/application/models/bd_model.php
Ramas
Introducción
Línea de tiempo de commits. Podremos hacer cambios en ellas sin afectar a la rama principal (normalmente master). Estas ramas, finalmente, podrán incorporarse a la rama maestra.
Utilizamos las ramas para desarrollar nuevas funcionalidades. Estos cambios pueden unirse después a la rama principal o solo para hacer pruebas sobre la rama principal y acabar descartando la nueva rama.
Por defecto solo existe la rama master.
Cuando queremos unir una rama a otra realizamos un merge. Git lo hará por nosotros. Nos encontraremos con 3 escenarios:
- Fast-forward: Git detecta que no hay cambios en la rama principal (master) y la nueva rama se puede incorporar directamente, sin problemas ni intervención del usuario.
- Unión automática: Git detecta que en la rama principal hubo algún cambio que las otras ramas desconocen, pero dichos cambios no supone ningún conflicto y realiza la unión anotándolo en el historial.
- Unión manual: Git no puede resolver el conflicto de forma automática y deja la responsabilidad al usuario. Una vez solucionado se creará un merge commit y se podrá seguir trabajando sin problema.
Creación
git branch minuevafuncionalidad
Si queremos ver las ramas que hay en el repositorio:
git branch
Si queremos ver las ramas locales y remotas:
git branch -a
Nos movemos a la rama:
git checkout minuevafuncionalidad
Normalmente, cuando creamos una rama también queremos movernos a ella, así que para hacer todo en un paso: git checkout -b nombre-rama
Para subir esa rama al repositorio remoto:
git push -u origin minuevafuncionalidad
Eliminación
git branch -d nombre-rama
Comparar
Para ver diferencias entre ramas:
git diff rama1 master
Unión de ramas
Fast-forward
Debemos colocarnos en la rama master:
git checkout master
Para unir:
git merge rama1
Ejemplo de salida:
Updating 9391f7e..b605c52 Fast-forward villanos.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100755 villanos.md
Al revisar el historial, veremos algo así:
* b605c52 (HEAD -> master, villanos) Añadido Octopus * 0805ac7 Añadidos villanos * 9391f7e Actualización * 62c8a10 Agregando el gitignore * ac0d374 Borramos la historia de batman * b4c748c Cambiamos el nombre de la historia de superman * d877f01 Borrando archivo salvar mundo * c9ee153 Renombrando archivo a salvar-mundo * fa3cd3a Creando el archivo destruir el mundo * 4e809d4 Agregamos a Linterna verde y a Robin * 345d7de Editamos el readme.md * 860c6c2 Agregamos las historias de los heroes * bc1a1e5 Agregamos las ciudades * 6b8f60d Agregamos los heroes * da24862 Agregamos las misiones * 88a423d Se agrego el archivo readme
Unión automática
Cuando se fusiona una rama con la master y en la master ha habido cambios que no conoce la rama a unir, si no supone un conflicto, Git nos pedirá un mensaje de commit para que quede registrada la fusión. Git añade “Merge branch 'nombre rama'”, pero podemos poner lo que queramos. Tras guardar el commit, mostrará un mensaje así:
Merge made by the 'recursive' strategy. villanos.md | 1 + 1 file changed, 1 insertion(+)
Unión con conflictos
Cuando al unir dos ramas obtenemos este mensaje:
Auto-merging misiones.md CONFLICT (content): Merge conflict in misiones.md Automatic merge failed; fix conflicts and then commit the result.
Git nos informa de que existen conflictos que no puede solucionar de forma automática y requiere de nuestra intervención.
Para resolver, abrimos el fichero que tiene conflictos:
# Misiones 1. Acabar con el plan de Lex Luthor 2. Crear la liga de la justicia <<<<<<< HEAD 3. Buscar nuevos miembros que sean superhéroes 4. Necesitamos más comida ======= 3. Buscar nuevos miembros para la liga >>>>>>> rama-conflicto
Las nuevas líneas que aparecen en el fichero indican los conflictos. La línea ======= es el “centro” del conflicto. Todo el contenido entre el centro y la línea <<<<<<< HEAD es contenido que existe en la rama maestra actual a la que apunta la referencia HEAD. Por el contrario, todo el contenido entre el centro y >>>>>>> rama-conflicto es contenido que está presente en nuestra rama de fusión.
Etiquetas
Las etiquetas hacen referencia a un commit, el estado en que se encontraba un proyecto en un determinado momento.
Normalmente las etiquetas se usan en commits para marcar versiones o releases de los programas.
Creación
git tag nombre-tag
De una manera más completa:
git tag -a v1.0.0 -m "Versión inicial"
Esto asociará el tag al último commit. Si queremos especificar el commit:
git tag -a v0.1.0 345d7de -m "Versión alfa"
345d7de sería el identificar del commit.
Para borrarlo:
git tag -d nombre-tag
Para visualizar los que hay:
git tag
Listado
Para ver la lista de tags:
git tag
Para mostrar un tag:
git show nombre-tag
Repositorios remotos
Descargar repositorio
git clone direccion-repositorio
Por ejemplo, para descargar un repositorio de GitHub por HTTPS:
git clone https://github.com/laravel/laravel.git
Obtener últimos cambios
git pull origin master
Subir cambios
git push origin master
Publicar en varios repositorios remotos
Se añaden todos los que queramos:
git remote add repo1 https://github.com/usuario1/proyecto.git git remote add repo2 https://github.com/usuario2/proyecto.git git remote add repo3 https://github.com/usuario3/proyecto.git
Cada vez que queramos subir los cambios, decidimos a cuál. Por ejemplo, para subirlo solo al repo2:
git push repo2 master
Trabajando en equipo
El flujo de trabajo cuando se trabaja con más gente es crear una rama (branch) y trabajar sobre ella. La rama master no se debe tocar para evitar tocar los mismos archivos.
Partimos de la rama master:
git checkout master
Descargamos la versión más actualizada:
git pull origin master
Creamos una rama:
git branch minuevafuncionalidad
Nos movemos a esa rama:
git checkout minuevafuncionalidad
Haríamos nuestros desarrollos y commits.
Cada vez que queramos subir los cambios de la rama:
git push -u origin minuevafuncionalidad
Finalmente, para unir esa rama con la master, primero debemos cambiarnos a la rama master:
git checkout master
Asegurarnos de tener la última versión de master:
git pull origin master
Fusionamos las ramas:
git merge minuevafuncionalidad
Estos cambios están en local. Debemos subirlos al repositorio remoto:
git push origin master
Una vez fusionada, es una buena práctica eliminar las ramas que ya no vamos a usar más:
git push origin --delete minuevafuncionalidad
Y también (si queremos) la borramos de local:
git branch -d minuevafuncionalidad
Resumen
git init: creación de repositorio git local.git add: añade ficheros a STAGE.git commit: se registran los cambios de los ficheros que estén en STAGE (se hace una “instantánea”/snapshot).git status: lista los ficheros que sufrieron algún cambio desde el último commit y lista de ficheros que no está siguiendo Git.
Resolución de errores
Si al añadir ficheros a STAGE nos aparecen las siguientes advertencias:
warning: LF will be replaced by CRLF in archivo.txt. The file will have its original line endings in your working directory
Se debe a que está configurado core.autocrlf = true. Lo que hace esa opción es indicar si quieres que en el repositorio se guarden los saltos de línea de los ficheros en formato Unix (LF) pese a tener tus ficheros en tu entorno local con saltos de línea al formato Windows (CRLF). Al hacer commmit, tus ficheros se transformarán automáticamente a LF, y cuando hagas checkout de un fichero, se convertirá automáticamente a CRLF
Podemos solucionarlo con:
git config core.autocrlf false
Recursos
- Git Básico (Gist de GitHub)

