Herramientas de usuario

Herramientas del sitio


informatica:software:git

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:

  1. Modificar archivos en el directorio de trabajo
  2. Preparar los archivos añadiéndolos a la zona de preparación
  3. 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

informatica/software/git.txt · Última modificación: por tempwin