Git

Git es un software de control de versiones. Resulta muy difícil trabajar en la actualidad sin usar control de versiones.

Para este tema introductorio a Git, vamos a utilizar el libro de Pro Git escrito por Scott Chacon y Ben Straub

Introducción al control de versiones

Instalación y configuración inicial de Git

Actividades básicas de Git

Eliminar archivos

Borrar archivos con Git requiere ciertas consideraciones. ¿Deseamos borrar el archivo del directorio y del repositorio? ¿Deseamos borrar el archivo solamente del repositorio?

Borrar un archivo del proyecto y del repositorio

El borrado completo del repositorio se puede hacer de dos maneras:

  • Opción a) Borrar usando Git
  • git rm nombre_archivo
  • Opción b) Borrar primero el archivo del proyecto y luego con Git
  • rm nombre_archivo git add nombre_archivo

Para hacer efectivos los cambios, debemos hacer un commit

Borrar un archivo solamente del repositorio

Supongamos que olvidamos meter un archivo en .gitignore, por ejemplo. Entonces haremos lo siguiente:

git rm --cached nombre_archivo

Mover archivos

Supongamos que ya hemos hecho git add, pero queremos renombrar un cierto archivo. Entonces podemos renombrar el archivo de dos maneras:

  • Método 1. Renombrar el archivo en el directorio y en el repositorio.
  • git mv nombre_original nombre_nuevo
  • Método 2. Cambiar por separado el archivo en el directorio y en el repositorio
  • mv nombre_original nombre_nuevo git rm nombre_original git add nombre_nuevo

Ramificaciones

Para este tema, vamos a seguir los siguientes enlaces:

Hay mucho más que tratar sobre Git, ramas y entornos distribuidos. Pero eso lo vamos a dejar para el capítulo de GitHub y flujos de trabajo.

Reorganizaciones

Git permite realizar reorganizaciones entre ramas. El resultado es similar a realizar fusiones, aunque la estructura de ramas resultante es más sencilla. Si no queremos mantener la estructura de las ramas, es una alternativa interesante. Un ejemplo. Supongamos que tenemos la siguiente estructura de confirmaciones:

C1 --> C2 --> C3 (master) \---> C4 --> C5 (rama_x)

Ahora, vamos a hacer una reorganización:

$ git checkout rama_x $ git rebase master

El resultado es similar a hacer una fusión. Pero en este caso, la primera confirmación de la rama rama_x termina apuntando a la rama master:

C1 --> C2 --> C3 (master) --> C4' --> C5' (rama_x)

Una vez hecho el rebase, fusionamos la rama master con la rama rama_x.

$ git checkout master $ git merge rama_x

Con lo que el árbol de confirmaciones queda como sigue:

C1 --> C2 --> C3 --> C4' --> C5' (rama_x, master)

Finalmente, podemos eliminar la rama "rama_x" sin perder ninguna confirmación:

$ git branch -d rama_x

Quedando el árbol de confirmaciones así:

C1 --> C2 --> C3 --> C4' --> C5' (master)

Hay un caso en que no debemos hacer reorganizaciones. Nunca se debe reorganizar sobre cambios que ya han sido confirmados en un repositorio remoto. Podemos encontrar más información sobre este tema en el apartado Los peligros de la reorganización en https://git-scm.com/book/es/v1/Ramificaciones-en-Git-Reorganizando-el-trabajo-realizado

Otras reorganizaciones

Se pueden hacer otros tipos de reorganizaciones más específicas:

  • Combinar varias confirmaciones en una sola
  • Cambiar de base una subrama a otra
  • Eliminar un commit intermedio
  • Eliminar el último commit

Combinar varias confirmaciones en una sola

Podemos combinar varios commits en uno solo. Por ejemplo, supongamos que tenemos el siguiente árbol de confirmaciones:

c1 --> c2 --> c3 --> c4 (master, HEAD)

Supongamos que queremos que c2, c3 y c4 aparezcan como una única confirmación. Entonces haremos lo siguiente:

$ git rebase -i HEAD~3

Donde en HEAD~n, n indica el número de confirmaciones que queremos unir. Cuando ejecutamos este comando, se nos abrirá un archivo donde aparecerán las acciones a llevar a cabo. Por ejemplo, para el ejercicio anterior, aparecerá algo como lo siguiente:

pick 7d50158 mensaje sobre cambios hechos en c2 pick 65c5d1a mensaje sobre cambios hechos en c3 pick 329f936 mensaje sobre cambios hechos en c4 [...]

Nosotros debermos cambiar el comando pick por squash cuando queramos que sea unido a otra confirmación. Por ejemplo, en el caso anterior, podríamos hacer:

pick 7d50158 mensaje sobre cambios hechos en c2 squash 65c5d1a mensaje sobre cambios hechos en c3 squash 329f936 mensaje sobre cambios hechos en c4 [...]

El árbol de confirmaciones resultante incluirá una confirmación c2' con todos los cambios de c2, c3 y c4:

c1 --> c2' (master, HEAD)

Cambiar una subrama de base a otra subrama

Supongamos que tenemos el siguiente árbol de confirmaciones:

A -- B -- C -- D -- E (master) \ -- F -- G -- H (topicA) \ \-- I -- J -- K (topicB) \--N -- O (topicC)

Y supongamos que queremos cambiar la rama "topicB" de base, para que derive de la rama "topicC". En tal caso, podemos usar el comando rebase del siguiente modo:

$ git rebase --onto topicC topicA topicB

Donde los parámetros son los siguientes:

  • topicC nueva rama base
  • topicA anterior rama base
  • topicB rama a cambiar de base

El resultado será el siguiente árbol de confirmaciones:

A -- B -- C -- D -- E (master) \ -- F -- G -- H (topicA) \ \--N -- O (topicC) -- I' -- J' -- K' (topicB)

Después, siempre podemos fusionar "topicC" y "topicB" si fuese necesario.

Eliminar un commit intermedio

Supongamos que tenemos el siguiente árbol de confirmaciones:

A -- B -- C -- D -- E (master)

Y nos damos cuenta de que en el commit C cometimos un error que no queremos conservar. Para eliminar dicho commit, haremos lo siguiente:

$ git checkout master $ git rebase --onto B HEAD~2

Donde HEAD~2 hace referencia al commit "D". En realidad estamos diciendo que ahora el commit "D" ahora apuntará a "B" en lugar de a "C", de modo que "C" se pierde.

Eliminar el último commit

Si lo que queremos es eliminar el último commit, tenemos dos alternativas: conservar o no conserar los cambios.

Elminar el último commit conservando los cambios

Si quiero eliminar el último commit pero quiero que los cambios se sigan manteniendo como cambios pendientes, debemos hacer lo siguiente:

$ git reset --soft HEAD~1

Eliminar el último commit descartando los cambios

Si quiero eliminar el último commit y no mantener ningún los cambios, entonces el comando a realizar es el siguiente:

$ git reset --hard HEAD~1

Actividad 1. Crea un repositorio local en una carpeta llamada Act1-git. Supongamos que el dueño de dicha carpeta se llama Juan. La historia de dicha carpeta es la siguiente:

  1. Juan crea un archivo llamado README.md y escribe en su interior algunas líneas describiendo el proyecto
  2. Hace una primera confirmación con el nombre "Inicio del proyecto"
  3. Continúa agregando el archivo index.php que contiene una página html básica, con el nombre del proyecto, y el archivo mostrar.php, un archivo php vacío.
  4. Después hace otra confirmación más, con el nombre "Esqueleto básico"
  5. Añade un formulario a index.php que envía una variable nombre al script mostrar.php. En mostrar.php escribe el código necesario para mostrar por pantalla el nombre de la variable.
  6. Después hace una confirmación con el texto "Se muestra el mensaje por pantalla".
  7. A Juan le llama un compañero, diciéndole que es urgente resolver un problema del código fuente creado: el archvio mostrar.php debe mostrar el texto "El nombre enviado desde el formulario es: " antes del nombre recibido desde index.php. Por ello, Juan crea una rama llamada hotfix. Resolverá el problema en dicha rama.
  8. Una vez resuelto el problema, Juan vuelve a la rama master y añade un título <h1> en mostrar.php con el texto "Variable recibida desde un formulario. Después de esto, confirma el cambio con la descripción "Título añadido en mostrar.php".
  9. Al hacer esto, Juan crea un conflicto con la rama hotfix

  10. Juan hace una fusión de la rama hotfix con la rama master resolviendo los conflictos. La nueva confirmación se llamará "Problema crítico con texto en mostrar.php resuelto". Juan decide además etiquetar esta versión como la "0.0"
  11. Después de esto, Juan añade a README.md por error un fragmento de Lorem Ipsum, y hace una confirmación llamada "Más detalles en README.md"
  12. Tras hacer la confirmación crea un nuevo archivo llamado INSTALL.txt, donde introduce las instrucciones instalación de composer.
  13. Ahora se acaba de dar cuenta de que el archivo README.md está mal y por eso desea descartar el commit llamado "Más detalles en README.md".

Una vez que termines la actividad, dentro de la carpeta Act1-git ejecuta el siguiente comando:

history > history.txt

Comprime el directorio en un archivo llamado Act1-git.zip