Capítulo 11 Git y GitHub

Git es un sistema de control de versiones. Su objetivo es registrar los cambios y guardar las versiones de los archivos que nos interesen de nuestro ordenador. Ayuda a coordinar el trabajo que varias personas realizan sobre archivos compartidos en un repositorio común, GitHub.

Los sistemas de control de versiones se usan frecuentemente para el desarrollo de código, sin embargo, son de utilidad en cualquier contexto donde se necesite realizar un control de cambios y trabajar colaborativamente sobre los mismos archivos.

Las actividades de este capítulo se basan en Chacon and Straub (2014) e Hinojosa-Gutiérrez and Merelo-Guervós (2017).

Objetivos del capítulo

  • Conocer un sistema de control de versiones.
  • Poner en práctica los conceptos sobre sistemas de control de versiones.
  • Utilizar una herramienta colaborativa de control de versiones.
  • Poder utilizar un sistema de control de versiones desde la línea de comandos.
  • Usar un repositorio en la Web para el control de versiones.

11.1 Introducción

Git fue diseñado en 2005 por Linus Torvalds, creador de Linux. Para el desarrollo del sistema operativo Linux usaban un sistema de control de versiones que dejó de ser gratuito para ellos en 2005. Como respuesta, desarrollaron su propia herramienta de control de versiones: Git. Actualmente es uno de los sistemas de control de versiones de más amplia difusión.

Github es un sitio web que implementa repositorios para Git que pueden compartirse. Fue adquirido por Microsoft en junio de 2018.

Se puede usar Git de muchas formas puesto que está integrado en muchas herramientas y existen entornos gráficos específicos para acceder a sus funciones (p.e., GitHub Desktop). Una manera de usarlo es desde la línea de comandos, tecleando los comandos de las operaciones que queramos hacer. Usar Git desde la línea de comandos tiene el inconveniente de que puede parecer más difícil, pero tiene tres ventajas:

  • Está disponible en cualquier instalación de Git.
  • Es el único lugar en donde se pueden ejecutar todos los comandos de Git (los entornos gráficos suelen tener limitaciones).
  • Si se conoce su uso desde la línea de comandos, es fácil usar cualquier herramienta gráfica.

Una vez instalado en nuestro sistema operativo, podemos abrir el intérprete de comandos de Git en cualquier carpeta, desde el explorador de archivos. Nos situamos en la carpeta de trabajo (p.e., siscd) y, en el menú contextual de la carpeta, seleccionamos la opción Git Bash Here (figura 11.1).

Abrir el intérprete de comandos de Git asociado a una carpeta.

Figura 11.1: Abrir el intérprete de comandos de Git asociado a una carpeta.

El resultado es que se abre una ventana del intérprete de comandos de Git situado en la carpeta de trabajo que contendrá los archivos cuyas versiones queremos controlar (figura 11.2).

Intérprete de comandos de Git asociado a una carpeta.

Figura 11.2: Intérprete de comandos de Git asociado a una carpeta.

Los comandos que se muestran en los apartados siguientes, podemos copiarlos y pegarlos sobre el intérprete de comandos22. Al ejecutarse, tendrán efecto sobre la carpeta de trabajo o bien sobre la instalación de Git, dependiendo de su ámbito.

11.2 Configuración

Para comenzar a usar Git en nuestro ordenador, debemos configurarlo con nuestros datos y preferencias.

En cuanto a nuestros datos, para identificar a cada persona que trabaja sobre Git se usa su nombre y dirección de correo electrónico. Si trabajamos solos, a nivel local, no sería estrictamente necesario configurar nuestra identidad. En el momento en que vayamos a trabajar colaborativamente, es imprescindible conocer quién realiza cada operación.

Lo configuraremos con nuestro nombre y dirección de correo de la asignatura. En mi caso, son los datos que se indican a continuación, sutitúyelos por tus propios datos.

git config --global user.name "José Samos Jiménez"
git config --global user.email jsamosj@siscd.es

En lo que se refiere a nuestras preferencias, para introducir comentarios asociados a los cambios que se registren, podemos usar cualquier editor. Los comentarios son sencillos, generalmente se trata de añadir una línea de texto que incluso se puede incorporar en el propio comando. Por este motivo el editor elegido no necesita ser muy sofisticado. Para usar notepad (el bloc de notas), el comando de configuración es el siguiente.

git config --global core.editor notepad

Si prefieres otro editor que esté instalado en tu ordenador, sustituye “notepad” por su nombre. Si no está incluido en el sistema operativo, también hay que introducir su ubicación (p.e., C:/Program Files/TeXnicCenter/TeXnicCenter.exe).

Podemos comprobar que se han realizado los cambios indicados en los comandos anteriores mediante el siguiente comando.

git config --list

El resultado es una lista de variables de configuración de la herramienta entre las que tienen que aparecer las que hemos definido:

...
user.name=José Samos Jiménez
user.email=jsamosj@siscd.es
core.editor=notepad

Para configurar las opciones y consultarlas hemos usado un comando de Git, el comando config, con distintos parámetros según lo que queríamos hacer. Este comando ofrece muchas más posibilidades. Podemos consultar la ayuda asociada a cualquier comando de Git mediante otro comando, en este caso help, pasándole como parámetro el comando que queremos consultar, como se muestra a continuación.

git help config

El resultado es que abre una ventana del navegador con la página de ayuda del comando que se pasa como parámetro, en este caso nos mostrará la página de ayuda de config.

11.3 Operaciones básicas a nivel local

Los archivos controlados por Git que modificamos en nuestra carpeta de trabajo tienen tres estados, como se representa en la figura 11.3.

Estados de los cambios en Git.

Figura 11.3: Estados de los cambios en Git.

  • Pueden estar modificados (modified) en la carpeta de trabajo.

  • Pueden pasarse desde la carpeta de trabajo al área de almacenamiento de Git, entonces están preparados (staged) para ser confirmados.

  • Si se confirman, pasan desde el área de trabajo a estar confirmados (committed) en el repositorio Git.

11.3.1 Crear un repositorio

Tanto el área de almacenamiento como el repositorio son estructuras de Git, que se crean asociadas a la carpeta de trabajo, de hecho se crean dentro de la carpeta de trabajo.

Para crearlas, debemos ejecutar el comando init en nuestra carpeta de trabajo (el intérprete de comandos de Git está abierto y situado en la carpeta de trabajo).

git init

En la figura 11.4, se muestra el resultado de la ejecución del comando init. Nos avisa que ha inicializado un repositorio vacío en la carpeta .git, ubicada en nuestra carpeta de trabajo.

Inicialización del repositorio Git.

Figura 11.4: Inicialización del repositorio Git.

Con la configuración por defecto del navegador de archivos, esa carpeta no es visible (podemos cambiar la configuración para verla, pero no es necesario). Solo tenemos que saber que nuestra carpeta de trabajo está controlada por Git y que podremos pasar los archivos que modifiquemos por los estados representados en la figura 11.3, utilizando la estructura creada por Git.

Añadimos a nuestra carpeta de trabajo un archivo de ejemplo cualquiera23. Por el simple hecho de añadirlos, Git los detecta, aunque no los controla. Si ejecutamos el comando status, nos muestra la situación de nuestra carpeta de trabajo respecto al repositorio.

git status

El resultado se muestra en la figura 11.5. Nos indica que hay unos archivos sin seguimiento, también que usemos el comando add para seguirlos.

Situación de la carpeta de trabajo controlada por Git.

Figura 11.5: Situación de la carpeta de trabajo controlada por Git.

Para hacer el seguimiento de todos los archivos de la carpeta, ejecutamos el comando add con la lista de archivos a seguir o bien con comodines para obtenerla.

git add *.*

Para ver el efecto de este comando, consultamos otra vez el estado. Los comandos y el resultado se muestran en la figura 11.6.

Nueva situación del repositorio después de add.

Figura 11.6: Nueva situación del repositorio después de add.

Nos muestra que los archivos están preparados (staged), están en el área de almacenamiento (figura 11.3). También nos indica el comando para devolver un archivo a la situación anterior: git rm --cached <file>.

Para pasar los archivos preparados al repositorio, empleamos el comando commit, al que podemos añadir directamente un comentario que describa el motivo de los cambios realizados.

git commit -m 'Versión inicial de los archivos'

Volvemos a consultar el estado del repositorio. Los comandos y el resultado se muestran en la figura 11.7.

Nueva situación del repositorio después de commit.

Figura 11.7: Nueva situación del repositorio después de commit.

Cuando se añaden los archivos al repositorio, nos indica que no hay nada pendiente. Si miramos en nuestra carpeta, con el explorador de archivos, nada ha cambiado en ningún momento pero, internamente, Git tiene una copia de nuestros archivos en su repositorio.

Como resultado, la situación en este momento es que tenemos lo siguiente:

  • Una carpeta de trabajo con unos archivos controlados por Git.
  • Aunque no lo vemos, un repositorio Git en la carpeta de trabajo con una copia de los archivos.

A partir del contenido de este repositorio he creado un repositorio en la Web, que podemos obtener directamente siguiendo las indicaciones del siguiente apartado.

11.3.2 Clonar un repositorio

Para trabajar exactamente con los mismos archivos que se usan en este capítulo, podemos obtener el mismo resultado descrito al final del apartado anterior clonando un repositorio que está en la Web, en concreto, el que está disponible en https://github.com/josesamos/siscd-jsamos.

Para obtenerlo hacemos lo siguiente:

  • Con el navegador de archivos, nos situamos en la carpeta donde deseemos ubicar nuestra carpeta de trabajo. Por ejemplo, yo la voy a ubicar en la carpeta Documentos.

  • Abrimos el intérprete de comandos de Git asociado a la carpeta, seleccionando la opción Git Bash Here en el menú contextual (figura 11.1).

  • Ejecutamos el comando clone, indicando el repositorio a clonar y la carpeta de trabajo donde queremos que haga la clonación.

Como criterio para nombrar la carpeta de trabajo utilizaremos nuestro usuario de la asignatura con “siscd-” como prefijo, en mi caso el comando a ejecutar será el siguiente (utiliza tu nombre de usuario solo para la carpeta, no para el repositorio Web).

git clone https://github.com/josesamos/siscd-jsamos siscd-jsamos

Consultamos el estado de nuestro repositorio (antes, mediante cd, change directory, nos situamos en la carpeta de trabajo). Los comandos y el resultado se muestran en la figura 11.8.

Situación del repositorio después de clone.

Figura 11.8: Situación del repositorio después de clone.

Es decir, clone ha creado una carpeta llamada siscd-jsamos, con un repositorio .git en su interior, ha descargado toda la información del repositorio Web y ha sacado una copia de trabajo de la última versión de los archivos.

11.3.3 Guardar cambios en el repositorio

Vamos a realizar algunos cambios en la carpeta de trabajo para ver cómo actúa Git respecto a ellos. Los cambios son los siguientes:

  • Creamos un nuevo archivo de texto (puede estar vacío) cuyo nombre sea nuestro nombre de usuario. En mi caso, creo el archivo jsamos.txt en la carpeta siscd-jsamos.

  • Abrimos el archivo texto.txt, añadimos en una nueva línea nuestro nombre de usuario, lo guardamos y cerramos.

Si consultamos el estado del repositorio después de estos cambios, el resultado se muestran en la figura 11.9.

Situación del repositorio después de modificar y añadir archivos.

Figura 11.9: Situación del repositorio después de modificar y añadir archivos.

  • Por un lado, tenemos el archivo modificado, que podemos añadir al área de almacenamiento mediante el comando add o descartar los cambios mediante el comando restore (recuperaría la versión que tiene en el repositorio).

  • Por otro, tenemos el nuevo archivo, que todavía no está bajo el control de Git y que podemos añadir al área de almacenamiento mediante el comando add.

Añadimos los dos archivos al área de almacenamiento mediante el comando siguiente.

git add texto.txt jsamos.txt

La operación y el resultado se muestran en la figura 11.10.

Archivos en el área de almacenamiento.

Figura 11.10: Archivos en el área de almacenamiento.

Los dos archivos se han situado en el área de almacenamiento. Nos indica que uno de ellos es nuevo, el otro es un archivo modificado (respecto a la versión del repositorio).

Supongamos que tenemos que modificar de nuevo ambos archivos y crear un nuevo archivo:

  • Añadimos a texto.txt y jsamos.txt la fecha de hoy en una nueva línea.

  • Creamos un nuevo archivo error.txt.

El resultado de consultar el estado de repositorio se muestra en la figura 11.11.

Archivos nuevos, modificados y en el área de almacenamiento.

Figura 11.11: Archivos nuevos, modificados y en el área de almacenamiento.

Tenemos archivos en el área de almacenamiento, preparados para pasar al repositorio, que también tienen cambios pendientes. Si ahora ejecutamos el comando commit solo pasarán al repositorio los cambios preparados en el área de almacenamiento. Si queremos pasar las últimas modificaciones de estos archivos al repositorio, debemos ejecutar de nuevo el comando add para esos archivos.

Por otra parte, tenemos el archivo error.txt que supongamos que es un archivo generado automáticamente y no queremos controlar los cambios que se producen en él.

Por tanto, ejecutamos de nuevo el comando add con los archivos modificados que nos interesan.

git add texto.txt jsamos.txt
git commit -m 'Modificaciones de prueba'

El resultado es que el área de almacenamiento se actualiza con la última versión de estos archivos (se pierde la versión intermedia que no habíamos guardado en el repositorio).

Respecto a los comentarios que se incluyen en el comando commit, se pueden encontrar varias guías de estilo. Simplificando mucho, se trataría de explicar brevemente el porqué y el qué más que cómo de los cambios; debe empezar con mayúscula y no acabar con “.”.

Si no se incluye -m y el comentario en el comando commit, al ejecutarlo se abre el editor que hayamos configurado asociado a Git para introducir en él el comentario y, al cerrar la ventana del editor, se ejecuta el comando.

11.3.4 Ignorar archivos

Si hemos hecho las operaciones anteriores, el resultado de consultar el estado de repositorio se muestra en la figura 11.12.

Archivo no controlado pero que no queremos controlar.

Figura 11.12: Archivo no controlado pero que no queremos controlar.

Es decir, todos los archivos que nos interesan están controlados y actualizados en el repositorio. Hay un archivo fuera de control que no nos interesa controlar.

Se puede crear un archivo llamado .gitignore en la carpeta de trabajo que contenga los nombres de archivos o carpetas que Git debe ignorar. Cuando se incluye una carpeta, se ignora todo su contenido (p.e., para incluir una carpeta llamada tmp hay que incluir una línea con tmp/). Se pueden utilizar comodines para definir los nombres de los archivos. Cada nombre debe estar situado en una línea del archivo.

Así, si solo queremos ignorar el archivo error.txt y nuestro editor es el bloc de notas, creamos un nuevo archivo con esa línea. El archivo se ha de llamar .gitignore (sin otra extensión). Para guardarlo con ese nombre, en la ventana Guardar como del bloc de notas, en el campo Tipo, seleccionamos la opción Todos los archivos (*.*) y, en el campo nombre, introducimos el nombre .gitignore (figura 11.13).

Crear el archivo .gitignore.

Figura 11.13: Crear el archivo .gitignore.

Si volvemos a consultar el estado de repositorio (sin hacer ninguna otra operación), el resultado que obtenemos se muestra en la figura 11.14.

Estado del repositorio incluyendo el archivo .gitignore.

Figura 11.14: Estado del repositorio incluyendo el archivo .gitignore.

Ya no aparece el archivo que queríamos ignorar, en su lugar aparece el archivo .gitignore que nos interesa controlar. Lo incluimos mediante los comandos siguientes.

git add .gitignore
git commit -m 'Excluir archivo de error'

Con esto ya tenemos todos los archivos que queremos controlar actualizados en el repositorio.

Los cambios que se produzcan en los archivos listados en .gitignore serán transparentes para Git. Si incluimos en la lista de .gitignore algún archivo que estaba incluido en el repositorio, seguirá en el repositorio pero, a partir de ese momento, dejará de controlarlo.

11.3.5 Consultar diferencias

En el archivo de texto cuyo nombre es nuestro usuario de correo, incluimos las siglas de la asignatura (“siscd”) y añadimos el archivo al área de almacenamiento, mediante el comando add.

git add jsamos.txt

A continuación, volvemos a editar el mismo archivo y añadimos el nombre completo de la asignatura (“Sistemas Informáticos de Soporte a la Colaboración y la Decisión”).

Cambios preparados y no-preparados

Si miramos el estado del repositorio, el archivo aparece con cambios preparados y con otros cambios no preparados, también está incluido en el repositorio.

Si ejecutamos el comando diff, el resultado que obtenemos se muestra en la figura 11.15

git diff
Resultado de diff con cambios preparados.

Figura 11.15: Resultado de diff con cambios preparados.

Obtiene la diferencia entre el archivo que está en la carpeta de trabajo y el archivo en el área de almacenamiento (cambios preparados).

Si ejecutamos el comando diff --staged, el resultado que obtenemos se muestra en la figura 11.16

git diff --staged
Resultado de diff --staged con cambios preparados.

Figura 11.16: Resultado de diff --staged con cambios preparados.

Obtiene la diferencia entre el archivo que está en el área de almacenamiento (cambios preparados) y la última versión del archivo en el repositorio.

Solo cambios no-preparados

A continuación confirmamos los cambios preparados.

git commit -m 'Mostrar funcionamiento de diff'

Tenemos el archivo modificado en la carpeta de trabajo y la versión que acabamos de confirmar es la última almacenada en el repositorio.

Si ejecutamos el comando diff, el resultado que obtenemos se muestra en la figura 11.17

git diff
Resultado de diff sin cambios preparados.

Figura 11.17: Resultado de diff sin cambios preparados.

En este caso, obtiene la diferencia entre el archivo que está en la carpeta de trabajo y el archivo en el repositorio.

Es decir, el comando diff obtiene la diferencia entre el archivo en la carpeta de trabajo y el archivo cuyos cambios se han preparado o, si no está en esa situación, los obtiene respecto al archivo del repositorio.

En el caso de diff --staged, no devolvería ningún cambio ya que el área de almacenamiento se encuentra vacía.

Para el archivo modificado, preparamos los cambios.

git add jsamos.txt

Si ahora ejecutamos el comando diff no devuelve ningún cambio porque no hay ningún cambio pendiente en la carpeta de trabajo.

Por tanto:

  • diff devuelve los cambios de lo que está pendiente de preparar.
  • diff --staged devuelve los cambios entre lo que está preparado y confirmado.

Para acabar, confirmamos los cambios.

git commit -m 'Mostrar funcionamiento de diff --staged'

Cambios en otros tipos de archivos

El comando diff nos muestra las diferencias entre los archivos en distintas situaciones. Lo hemos probado con archivos de texto. Vamos a modificar los otros archivos disponibles para ver cómo se comporta este comando.

Editamos y modificamos los archivos hoja-calculo-open-office.ods, presentacion-open-office.odp, texto-open-office.odt. En todos los casos, añadimos nuestro nombre de usuario en la primera línea libre.

Si ejecutamos el comando diff, el resultado que obtenemos se muestra en la figura 11.18

git diff
Resultado de diff con otros tipos de archivos.

Figura 11.18: Resultado de diff con otros tipos de archivos.

En el caso de los archivos hoja-calculo-open-office.ods y texto-open-office.odt, nos muestra los cambios. En el caso del archivo presentacion-open-office.odp nos indica Binary files a/… and b/… differ; es decir, los archivos son distintos pero, por su formato, al ser binarios (no se almacena texto), no muestra las diferencias. Solo obtiene las diferencias si los archivos se guardan en formato de texto.

Esto nos ocurrirá en más casos, con más tipos de archivos: no podrá obtener las diferencias concretas pero podremos controlar las versiones sin problema. Cuando se dé esta situación, nos interesará incluir en los comentarios del comando commit detalle de las modificaciones llevadas a cabo.

Mediante los siguientes comandos, actualizamos en el repositorio los archivos modificados.

git add *.od?
git commit -m 'Funcionamiento de diff con otros tipos de archivos'

Para añadirlos, utilizamos el comodín “?” que sirve para reemplazar a cualquier carácter.

11.3.6 Borrar archivos

Si borramos un archivo cualquiera desde el explorador de archivos, por ejemplo, el archivo texto.txt, y consultamos el estado del repositorio (figura 11.19), los cambios no están preparados para añadirlos al repositorio. Este aviso lo tendremos permanentemente porque el archivo sigue siendo controlado por Git.

Resultado de status con un archivo borrado.

Figura 11.19: Resultado de status con un archivo borrado.

Borrar un archivo de la carpeta de trabajo

Para que Git deje de controlarlo, lo tenemos que borrar con el comando rm.

Para poder borrarlo con ese comando, antes tenemos que recuperarlo. Podemos recuperarlo de la papelera de reciclaje o bien mediante el comando restore, desde el repositorio de Git.

git restore texto.txt

git rm texto.txt

El comando rm borra el archivo y envía la operación al área de almacenamiento. Si consultamos el estado (figura 11.20), observamos que la operación de borrado está preparada para ser confirmada.

Resultado del comando rm sobre un archivo.

Figura 11.20: Resultado del comando rm sobre un archivo.

Confirmamos la operación mediante el comando siguiente.

git commit -m 'Eliminar un archivo con rm'

Como resultado, el archivo está borrado de la carpeta de trabajo y deja de estar controlado por Git. El archivo no se incluye en la última versión del repositorio, pero está incluido en las versiones previas.

Borrar un archivo del área de almacenamiento

Vamos a crear un nuevo archivo llamado tmp.txt. Lo añadimos al área de almacenamiento.

git add tmp.txt

Una vez en el área de almacenamiento, pensamos que es mejor que Git no lo controle pero no queremos borrarlo de la carpeta de trabajo. Es decir, tenemos que borrarlo solo del área de almacenamiento. Esta operación se realiza mediante el comando rm --cached siguiente.

git rm --cached tmp.txt

Para que Git no lo controle, tenemos que añadirlo en una nueva línea al archivo .gitignore. Además, actualizamos este archivo en el área de almacenamiento y en el repositorio, mediante los comandos siguientes.

git add .gitignore
git commit -m 'Ignorar el archivo tmp.txt'

11.3.7 Renombrar archivos

La manera más sencilla de renombrar archivos es mediante el comando mv.

Vamos a renombrar el archivo con nuestro nombre de usuario para añadirle el prefijo “siscd-”. Realizaremos la operación mediante el comando siguiente.

git mv jsamos.txt siscd-jsamos.txt

Si observamos el estado del repositorio (figura 11.21), observamos que la operación de cambio de nombre está preparada para ser confirmada.

Resultado del comando mv sobre un archivo.

Figura 11.21: Resultado del comando mv sobre un archivo.

Confirmamos la operación mediante el comando siguiente.

git commit -m 'Renombrar un archivo con mv'

11.3.8 Actualizar y deshacer cambios

En este apartado vamos a ver cómo actualizar un commit y cómo deshacer cambios de las distintas áreas.

Modificar un commit

Actualizamos el archivo cuyo nombre está compuesto por las siglas de la asignatura y nuestro usuario (en mi caso, siscd-jsamos.txt), incluimos una línea con nuestro nombre de usuario. A continuación, añadimos el archivo al área de almacenamiento y confirmamos el cambio.

git add siscd-jsamos.txt
git commit -m 'Incluir usuario'

Creamos un nuevo archivo llamado siscd.txt y pensamos que habría sido adecuado incluirlo en la última actualización del repositorio. Podemos hacerlo mediante commit --amend. Primero añadimos el archivo al área de almacenamiento y, mediante el comando commit --amend, se actualiza el último commit realizado.

git add siscd.txt
git commit --amend

En la figura 11.22, se muestra el resultado de la ejecución de estos comandos.

Ejecución del comando commit --amend.

Figura 11.22: Ejecución del comando commit --amend.

Como no indicamos el comentario para commit --amend, abre el editor con el comentario que habíamos añadido al commit original y nos permite modificarlo. Es decir, con esta operación modificamos el commit anterior con los archivos que están en el área de almacenamiento y con el comentario que indiquemos (no se hace un nuevo commit).

Eliminar archivos del área de almacenamiento

Actualizamos los archivos siscd*.txt (en mi caso siscd.txt y siscd-jsamos.txt), incluyendo nuestra dirección de correo electrónico de la asignatura, y añadimos los archivos al área de almacenamiento.

git add siscd*.txt

Si consultamos el estado del repositorio, el resultado se muestra en la figura 11.23.

Estado del repositorio con archivos en el área de almacenamiento.

Figura 11.23: Estado del repositorio con archivos en el área de almacenamiento.

En el apartado Changes to be committed aparecen los dos archivos que acabamos de añadir y también nos indica la operación que podemos hacer para eliminar un archivo del área de almacenamiento (restore --staged).

Supongamos que no queremos confirmar los cambios del archivo cuyo nombre está basado en nuestro usuario (en mi caso siscd-jsamos.txt). Podemos eliminarlo del área de almacenamiento mediante el comando siguiente.

git restore --staged siscd-jsamos.txt

En la figura 11.24, se muestra el resultado de la operación. El archivo vuelve a estar modificado en la carpeta de trabajo.

Estado del repositorio después del comando restore --staged.

Figura 11.24: Estado del repositorio después del comando restore --staged.

Esta operación solo elimina el archivo del área de almacenamiento, no modifica el archivo de la carpeta de trabajo. Es decir, si antes de ejecutar el comando restore --staged modificamos el archivo, al ejecutarlo no perdemos las modificaciones.

Deshacer cambios de archivos en la carpeta de trabajo

Si hemos modificado un archivo y queremos recuperar su estado antes de las modificaciones, podemos hacerlo mediante el comando restore. Por ejemplo, lo ejecutamos para el archivo con el que estamos trabajando.

git restore siscd-jsamos.txt

Si consultamos el estado después de esta operación, el resultado se muestra en la figura 11.25, el archivo ya no aparece como modificado en la carpeta de trabajo, hemos perdido los cambios.

Estado del repositorio después del comando restore --staged.

Figura 11.25: Estado del repositorio después del comando restore --staged.

Mediante este comando, hemos sustituido el archivo en la carpeta de trabajo por la última versión confirmada del mismo, que estaba en el repositorio.

11.3.9 Consultar el historial de confirmaciones

Mediante el comando log podemos ver el historial de confirmaciones, aparecen primero las más recientes (figura 11.26).

git log
Historial de confirmaciones del repositorio.

Figura 11.26: Historial de confirmaciones del repositorio.

Cada comando commit tiene asociado un número en hexadecimal que se usa para comprobar la integridad de los datos, se llama checksum. Por ejemplo, para el último commit (el primero de la lista) es 731e350505b3bbed64e808763c66991375b0a766.

Mediante el modificador -p, para cada confirmación, muestra las diferencias con la versión anterior. El comando sería como se muestra a continuación.

git log -p

11.3.10 Etiquetado

Hay dos tipos de etiquetas:

  • Ligeras: son punteros a commit concretos.

  • Anotadas: se almacenan en el repositorio como objetos y se les puede asociar nombre, correo, fecha y mensaje, como a un commit.

Etiquetas anotadas

Las etiquetas anotadas se crean mediante el comando tag -a, se les asigna un número de versión, con el formato que se considere oportuno (en algunos casos recomiendan que empiece por “v”), y con -m se puede incluir el comentario asociado.

git tag -a v1.0.0 -m 'Versión inicial'

Podemos ver las versiones definidas y el detalle de una versión concreta mediante los comandos siguientes.

git tag

git show v1.0.0

Si no se indica la versión, el comando show muestra la información del último commit. Al indicar la etiqueta, muestra la información de la etiqueta y, a continuación, la del commit asociado. El resultado de estos comandos se presenta en la figura 11.27.

Resultado de los comando tag y show.

Figura 11.27: Resultado de los comando tag y show.

Etiquetas ligeras

Para asignar una etiqueta ligera a un commit, solo hay que indicar el nombre de la versión, sin ningún modificador del comando tag.

git tag v1.0.0.ligera

Vemos las versiones definidas y el detalle de la versión que acabamos de definir mediante los comandos siguientes.

git tag

git show v1.0.0.ligera

Tal y como se puede apreciar en la figura 11.28, la etiqueta ligera se muestra como una etiqueta más al consultar las etiquetas mediante tag. Sin embargo, al mostrar la versión de la etiqueta ligera, no muestra ninguna información de la etiqueta, solo la información del commit asociado.

Resultado de los comandos tag y show para una etiqueta ligera.

Figura 11.28: Resultado de los comandos tag y show para una etiqueta ligera.

Etiquetar un commit concreto

En los ejemplos anteriores, hemos etiquetado el último commit realizado. También podemos etiquetar un commit concreto indicado su checksum o, al menos, parte de él.

Mediante el siguiente comando, obtenemos un resumen de los commit llevados a cabo en el repositorio.

git log --pretty=oneline

El resultado se muestra en la figura 11.29. Para cada cheksum se indica el comentario incluido en el commit.

Resultado del comando log --pretty.

Figura 11.29: Resultado del comando log --pretty.

Una vez localizamos el commit que queremos etiquetar, podemos añadir al comando el inicio del checksum para identificarlo.

git tag -a v0.0.1 cdb7817 -m 'Pruebas de diff'

Si consultamos las etiquetas definidas, la que acabamos de definir es una más y podemos consultar la situación del repositorio asociada a ella.

git tag

git show v0.0.1

El resultado de las operaciones anteriores se muestra en la figura 11.30.

Resultado de los comandos tag y show para la etiqueta de un commit concreto.

Figura 11.30: Resultado de los comandos tag y show para la etiqueta de un commit concreto.

En el ejemplo se ha definido una etiqueta anotada. También se pueden definir etiquetas ligeras de la misma forma, como se muestra a continuación.

git tag v0.0.1.ligera 31432d6

Como al usar el comando show con una etiqueta ligera solo devuelve la información del commit asociado, obtenemos el mismo resultado utilizando la etiqueta o el cheksum para hacer la consulta. Es decir, las dos consultas siguientes devuelven el mismo resultado.

git show v0.0.1.ligera

git show 31432d6

11.3.11 Recuperar una versión concreta

La situación actual se muestra en la figura 11.31.

Situación actual.

Figura 11.31: Situación actual.

El archivo siscd.txt está en el área de almacenamiento, pendiente de confirmar, y no tenemos ningún archivo modificado en la carpeta de trabajo.

En cuanto a la información sobre los commit llevados a cabo en el repositorio, es la que se muestra en la figura 11.29.

En este apartado vamos a recuperar archivos o estados concretos indicando su checksum, también se puede llevar a cabo esta operación indicando su etiqueta, si se ha definido.

Recuperar un archivo

La última modificación que hicimos sobre el archivo cuyo nombre está formado por las siglas de la asignatura y nuestro usuario fue precisamente incluir nuestro usuario: se corresponde al comentario “Incluir usuario” (figura 11.29).

Si queremos recuperar la versión que había justo antes de esa modificación, en la lista de commit (figura 11.29), nos fijamos en el cheksum del commit anterior: c9a1d2d. El comando para obtener esa versión concreta del archivo es el siguiente.

git checkout c9a1d2d -- siscd-jsamos.txt

Si consultamos la nueva situación, el archivo que hemos recuperado se encuentra en el área de almacenamiento. Mediante el comando diff --staged obtenemos las diferencias entre el archivo en el área de almacenamiento y la última versión del repositorio.

El resultado de estos comandos se muestra en la figura 11.32.

Resultado de recuperar una versión anterior de un archivo.

Figura 11.32: Resultado de recuperar una versión anterior de un archivo.

Se puede observar que la diferencia entre las dos versiones del archivo recuperado que indica es que la nueva versión no incluye el usuario.

Recuperar los archivos de un estado

Podemos recuperar los archivos de un estado concreto: volver a tener en nuestra carpeta de trabajo los archivos que teníamos en ese commit. Esta operación se puede realizar de varias formas. La que vamos a utilizar aquí es la considero más segura, ya que no se pierden los estados intermedios, ni tampoco los archivos nuevos que tengamos en nuestra carpeta de trabajo.

Por ejemplo, mediante el siguiente comando obtenemos los archivos del estado cuyo comentario es “Modificaciones de prueba”, cuyo checksum es 1f716f8.

git checkout 1f716f8 .

El “.” al final del comando es importante, indica que se use la carpeta actual para obtener los archivos. Así, los archivos de nuestra carpeta de trabajo son sustituidos por los del estado indicado. Los archivos que no estaban en el estado que hemos recuperado, no se borran.

El resultado de este comando se muestra en la figura 11.33.

Resultado de recuperar los archivos de un estado anterior.

Figura 11.33: Resultado de recuperar los archivos de un estado anterior.

Los commit del repositorio no se han modificado. Si hacemos esta misma operación utilizando el checksum del último commit realizado, obtenemos el resultado que se muestra en la figura 11.34.

git checkout 731e350 .
Resultado de recuperar los archivos del último commit.

Figura 11.34: Resultado de recuperar los archivos del último commit.

Recuperamos las últimas versiones almacenadas de los archivos y tampoco se elimina ningún archivo. Han quedado en el área de almacenamiento los archivos jsamos.txt y texto.txt, marcados como nuevos ya que no están incluidos en el último commit (los hemos obtenido al recuperar el estado “Modificaciones de prueba”, en operaciones posteriores se habían eliminado o renombrado).

Vamos a eliminar los archivos que no estaban incluidos en el último commit. Podemos hacerlo mediante el comando rm -f que los elimina del área de almacenamiento y de la carpeta de trabajo.

git rm -f jsamos.txt texto.txt

11.4 Ramificaciones

Una de las principales funcionalidades que ofrecen los sistemas de control de versiones es la posibilidad de usar ramificaciones para poder trabajar con varias versiones a la vez.

11.4.1 Rama master

Si consultamos la situación actual del repositorio (figura 11.35), mediante el literal On branch master, nos informa que estamos en la rama llamada master. También nos dice Your branch is ahead of ‘origin/master’ by 9 commits, es decir, tomando como punto de partida el momento en que clonamos el repositorio web, hemos hecho 9 operaciones commit que nos separan de él.

Situación actual del repositorio y rama master.

Figura 11.35: Situación actual del repositorio y rama master.

Cada commit almacena un estado de los archivos de nuestra carpeta de trabajo controlados por Git y está identificado por un cheksum. Cada estado se obtiene a partir del estado anterior, cuando se confirman las modificaciones con commit. La secuencia de estados forma una rama que, en este caso, se llama master. master es el nombre por defecto que se le da a la rama que se crea con el comando init (usando un parámetro de init se le puede asignar el nombre que queramos pero generalmente se no se cambia el nombre asignado por defecto).

Tomando los estados de la figura 11.29, la figura 11.36 representa la rama master: el nombre master apunta al último estado almacenado en el repositorio que, a su vez, apunta al estado siguiente. Aunque no se sigue representando, así sería hasta llegar al estado inicial, origin/master (Your branch is ahead of ‘origin/master’ by 9 commits).

Rama master.

Figura 11.36: Rama master.

11.4.2 Crear una rama nueva

Supongamos que queremos hacer modificaciones de prueba sobre nuestro trabajo pero conservando la versión actual, por si acaso nos interesase desecharlas. Si no tuviéramos Git, lo que haríamos sería hacer una copia de seguridad de todos los archivos de la carpeta de trabajo. Con Git lo que hacemos es crear una rama nueva.

En un repositorio puede haber más de una rama, es decir, puede haber varios caminos de operaciones commit que reflejan la evolución de nuestra carpeta de trabajo. Para evitar problemas, cuando vayamos a crear una nueva rama, es recomendable tener el repositorio actualizado: que no haya cambios pendientes de confirmar ni en la carpeta de trabajo ni en el área de almacenamiento.

Creamos una rama nueva llamada pruebas mediante el comando siguiente.

git branch pruebas

Para ver las ramas podemos usar el comando log con modificadores, de la forma siguiente.

git log --oneline --decorate

El resultado de estos comandos se muestra en la figura 11.37.

Ramas definidas y estados.

Figura 11.37: Ramas definidas y estados.

Tenemos dos ramas con los mismos estados pero la rama sobre la que estamos trabajando es master: se distingue porque HEAD apunta hacia ella (además aparece su nombre en el prompt del intérprete de comandos para indicar la rama de activa).

La figura 11.38 representa esta situación (la misma de la figura 11.37).

Ramas master y pruebas.

Figura 11.38: Ramas master y pruebas.

11.4.3 Cambiar de rama

Podemos tener tantas ramas como necesitemos y trabajar con la que consideremos oportuno en cada momento. Seleccionamos la rama de trabajo mediante el comando checkout. Para seleccionar la rama pruebas, ejecutamos el comando siguiente.

git checkout pruebas

En la figura 11.39, se muestra la operación de cambio de rama y el resultado al ejecutar el comando para ver la situación de las ramas.

Cambiar a la rama pruebas.

Figura 11.39: Cambiar a la rama pruebas.

Ahora HEAD apunta a la rama pruebas (también aparece su nombre en el prompt).

La figura 11.40 representa gráficamente la nueva situación (la misma de la figura 11.39).

Rama pruebas activa.

Figura 11.40: Rama pruebas activa.

Esto significa que cualquier cambio que hagamos en el repositorio afectará exclusivamente a la rama pruebas (la rama master no se verá afectada, juega el papel de la copia de seguridad).

11.4.4 Actualizar el repositorio

Una vez que estamos situados en la rama pruebas, modificamos nuestros archivos como necesitemos. En este caso, vamos a crear un nuevo archivo con el nombre de nuestro usuario y el prefijo “prueba-” (en mi caso prueba-jsamos.txt). Lo añadimos al área de almacenamiento y confirmamos los cambios añadiendo un comentario. A continuación, obtenemos una representación del estado del repositorio, con los comandos siguientes.

git add prueba-jsamos.txt

git commit -m 'Incluir archivo de prueba'

git log --oneline --decorate

En la figura 11.41, se muestra el resultado de las operaciones realizadas.

Operaciones de modificación de la rama pruebas y estado de las ramas.

Figura 11.41: Operaciones de modificación de la rama pruebas y estado de las ramas.

Se ha creado un nuevo estado en el repositorio (bbe18c4) pero solo forma parte de la rama pruebas. Los cambios no han afectado a la rama master.

La figura 11.42 representa gráficamente la nueva situación (la misma de la figura 11.41).

Actualización de la rama pruebas.

Figura 11.42: Actualización de la rama pruebas.

11.4.5 Volver a la rama inicial

En cualquier momento podemos cambiar de rama y seguir trabajando. Git ofrece herramientas para integrar los cambios producidos en varias ramas.

Para cambiar de rama, usamos el comando checkout. Comprobamos el estado mediante el comando log, con los modificadores que venimos usando, como se muestra a continuación.

git checkout master

git log --oneline --decorate

Los comandos y el resultado obtenido se muestran en la figura 11.43.

Operaciones de modificación de la rama pruebas y estado de las ramas.

Figura 11.43: Operaciones de modificación de la rama pruebas y estado de las ramas.

Solo aparece la rama master. Como la rama pruebas, con la modificación que hemos hecho, va por delante, no aparece en el resultado de la consulta.

Para que aparezcan todas las ramas, tenemos que añadir otros modificadores al comando log, como se muestra a continuación.

git log --oneline --decorate --graph --all

El nuevo comando y el resultado obtenido se muestran en la figura 11.44.

Estado de las ramas.

Figura 11.44: Estado de las ramas.

La figura 11.45 representa gráficamente la nueva situación (la misma de la figura 11.44).

Rama master activa.

Figura 11.45: Rama master activa.

Por otra parte, si comprobamos los archivos de nuestra carpeta de trabajo, el nuevo archivo que habíamos creado y añadido a la rama pruebas ha desaparecido: al cambiar de rama, los archivos de la carpeta de trabajo son los de la rama activa. De manera que, si ahora hacemos algún cambio, solo se verá afectada la rama activa, en este caso la rama master. Al cambiar de rama, Git se encarga de devolver la carpeta de trabajo a la situación de la rama seleccionada.

Para evitar problemas, antes de cambiar de rama, se recomienda tener todos los cambios confirmados en el repositorio.

11.4.6 Fusionar ramas

Una vez estamos seguros de que los cambios que hemos hecho en la rama pruebas son adecuados, podemos fusionar ambas ramas para llevarlos a la rama master.

Para hacer esta operación de fusión, tenemos que estar situados en la rama a la que queremos llevar los cambios, en este caso la rama master mediante el comando checkout (ya estamos situados en la rama master). Mediante el comando merge se lleva a cabo la fusión.

git merge pruebas

El comando merge y el resultado obtenido tras consultar el estado de las ramas se muestran en la figura 11.46.

Operación de fusión y estado de las ramas.

Figura 11.46: Operación de fusión y estado de las ramas.

La figura 11.47 representa gráficamente la nueva situación (la misma de la figura 11.46).

Fusión de las ramas master y pruebas.

Figura 11.47: Fusión de las ramas master y pruebas.

La fusión ha sido inmediata: solo ha habido que cambiar el estado al que apunta la rama master, pasa a apuntar al estado al que apuntaba la rama pruebas.

11.4.7 Eliminar una rama

Si consideramos que una rama no nos hace falta, podemos borrarla mediante el comando branch -d. Por ejemplo, para el caso de la rama pruebas, una vez fusionada con la rama master, no contiene ninguna información adicional. Con el comando siguiente la eliminamos.

git branch -d pruebas

A veces es recomendable trabajar como lo hemos hecho en estos ejemplos: tener una rama master con la versión estable de nuestro trabajo y una rama temporal pruebas (o como queramos llamarla) para ir avanzando. Cuando se llega a una situación estable en la rama temporal, la fusionamos a la rama estable. Si esta es nuestra forma de trabajo, no necesitamos borrar cada vez la rama temporal.

11.4.8 Fusionar dos ramas modificadas

La fusión de ramas, cuando las modificaciones están en solo una de ellas, tal y como la hemos hecho en el ejemplo anterior, es muy sencilla.

A veces necesitamos modificar ambas ramas antes de fusionarlas. En este caso, la fusión nos puede parecer más compleja, sobre todo si en ambas se modifican los mismos archivos. Para que no sea compleja, en este apartado vamos a suponer que en cada rama se modifican archivos distintos.

Si habíamos eliminado la rama pruebas volvemos a crearla y nos situamos en ella, mediante los comandos siguientes.

git branch pruebas
git checkout pruebas

En la rama pruebas creamos un nuevo archivo cuyo nombre sea nuestro nombre de usuario seguido del sufijo “-pruebas” (en mi caso jsamos-pruebas.txt). Añadimos el archivo al área de almacenamiento, confirmamos los cambios y mostramos la situación de las ramas mediante los siguientes comandos.

git add jsamos-pruebas.txt

git commit -m 'Incluir archivo en pruebas'

git log --oneline --decorate --graph --all

En la figura 11.48, se muestra la situación de ambas ramas.

Modificación en la rama pruebas.

Figura 11.48: Modificación en la rama pruebas.

La figura 11.49 representa gráficamente la nueva situación (la misma de la figura 11.48).

Representación de la modificación en la rama pruebas.

Figura 11.49: Representación de la modificación en la rama pruebas.

Supongamos que antes de acabar de hacer los cambios o comprobaciones necesarias en la rama pruebas, tenemos que hacer una modificación urgente en la rama master. Nos situamos en ella mediante el comando checkout.

git checkout master

La modificación consiste en crear un nuevo archivo cuyo nombre sea nuestro nombre de usuario seguido del sufijo “-master” (en mi caso jsamos-master.txt). Añadimos el archivo al área de almacenamiento, confirmamos los cambios y mostramos la situación de las ramas mediante los siguientes comandos.

git add jsamos-master.txt

git commit -m 'Incluir archivo en master'

git log --oneline --decorate --graph --all

En la figura 11.50, se muestra la situación de ambas ramas.

Modificación en la rama master.

Figura 11.50: Modificación en la rama master.

La figura 11.51 representa gráficamente la nueva situación (la misma de la figura 11.50).

Representación de la modificación en la rama master.

Figura 11.51: Representación de la modificación en la rama master.

Cuando acabamos los cambios en la rama pruebas, podemos llevar a cabo la fusión de ambas ramas. Como queremos conservar la rama master, esta debe ser la rama activa (en nuestro ejemplo ya lo es). La fusión se lleva a cabo mediante el comando merge.

git merge pruebas

Como el resultado de la fusión no es ninguno de los estados previamente existentes, se necesita generar un nuevo estado, podemos añadir un comentario (como lo añadimos a commit). Como no lo hemos indicado en el comando merge, se abre el editor con una propuesta de comentario (figura 11.52). Lo podemos modificar pero, en principio, es adecuado, describe la operación que se está llevando a cabo. Si cerramos el editor, se ejecuta el comando.

Fusión de las ramas master y pruebas, ambas modificadas.

Figura 11.52: Fusión de las ramas master y pruebas, ambas modificadas.

En la figura 11.53, se muestra la situación de ambas ramas después de la fusión.

Fusión de las ramas master y pruebas, ambas modificadas.

Figura 11.53: Fusión de las ramas master y pruebas, ambas modificadas.

La figura 11.54 representa gráficamente la nueva situación (la misma de la figura 11.53).

Representación de la fusión de las ramas master y pruebas.

Figura 11.54: Representación de la fusión de las ramas master y pruebas.

En este caso, la rama pruebas (figuras 11.53 y 11.54) apunta a un estado intermedio ya que se ha generado un nuevo estado para poder realizar la fusión. Si reutilizamos la rama pruebas para seguir haciendo cambios, estaremos trabajando con ese estado, en lugar de con el último estado almacenado en el repositorio. Por esta razón, después de una fusión, si se han modificado ambas ramas, debemos borrar la rama secundaria.

Mediante los comandos siguientes borramos la rama pruebas y presentamos la nueva situación del repositorio.

git branch -d pruebas

git log --oneline --decorate --graph --all

En la figura 11.55, se muestra la situación del repositorio.

Resultado de eliminar la rama pruebas.

Figura 11.55: Resultado de eliminar la rama pruebas.

La figura 11.56 representa gráficamente la nueva situación (la misma de la figura 11.55).

Representación del resultado de eliminar la rama pruebas.

Figura 11.56: Representación del resultado de eliminar la rama pruebas.

En las figuras 11.55 y 11.56, se puede observar que ha desaparecido la rama pruebas pero no el estado generado por las modificaciones llevadas a cabo en ella. Es adecuado que sea así, porque las modificaciones de ese estado forman parte de la historia de nuestro repositorio, aunque no tenga asociado el nombre de la rama.

11.5 GitHub

Si queremos trabajar en equipo con un sistema de control de versiones, necesitamos disponer de un repositorio común, en un servidor web.

Hay muchas posibilidades, desde tener un servidor propio, hasta contratar un hosting que soporte Git. En lo que se refiere a hosting, en https://git.wiki.kernel.org/index.php/GitHosting se comparan varias posibilidades. Uno de los proveedores de uso más extendido es GitHub: podemos usarlo gratuitamente y soporta la definición de repositorios públicos y privados. Si lo usamos gratuitamente, los repositorios privados tienen ciertas limitaciones que no tienen los repositorios públicos. Para nuestro ejemplo, usaremos un repositorio público de GitHub.

11.5.1 Registro

En primer lugar, tenemos que registrarnos en github.com. La pantalla principal cambia frecuentemente, pero suele aparecer un campo como el que se presenta en la figura 11.57, donde introducimos la dirección de correo que queremos utilizar (si queremos, posteriormente se puede cambiar24) y pulsamos sobre Sign up for GitHub.

Registrarse en github.com.

Figura 11.57: Registrarse en github.com.

Accedemos a la pantalla de registro (figura 11.58), donde introducimos el usuario que usaremos en GitHub, la dirección de correo y contraseña.

Registrarse en github.com.

Figura 11.58: Registrarse en github.com.

El usuario en este caso tiene más relevancia que en otras herramientas porque aparecerá en la URL de los repositorios que creemos y compartamos con otras personas. Se comprueba que esté disponible antes de asignárnoslo.

Cuando completamos nuestro perfil, pulsamos sobre el botón Complete setup, al final de la misma página (figura 11.59), para enviar los datos.

Registrarse en github.com.

Figura 11.59: Registrarse en github.com.

GitHub está pensado para desarrollar código, pero no es su único uso. No tenemos que ser desarrolladores de aplicaciones para usarlo. Por ejemplo, muchas personas lo usan como soporte para escribir libros.

Una vez registrados los datos, nos avisa de que nos han enviado un correo de verificación de nuestra dirección de correo electrónico. Para empezar a usar GitHub, tenemos que verificar nuestra dirección pulsando sobre el enlace que nos envían (o copiándolo en el navegador).

Accedemos a la pantalla de la figura 11.60, donde pulsamos sobre Create a repository para crear nuestro primer repositorio.

Crear un repositorio.

Figura 11.60: Crear un repositorio.

11.5.2 Crear un repositorio

Para crear un repositorio tenemos que introducir el nombre: le asignamos nuestro nombre de usuario con el prefijo “siscd-”. También determinamos si el repositorio es público (cualquiera lo puede ver) o privado (solo lo puede ver quien nosotros determinemos). En este caso, lo definimos como público (figura 11.61). Para crearlo, pulsamos sobre el botón Create repository.

Nombre y tipo del repositorio.

Figura 11.61: Nombre y tipo del repositorio.

El repositorio creado se muestra en la figura 11.62, donde se nos dan las instrucciones para enlazarlo con un repositorio local, dependiendo si es un repositorio nuevo o uno que ya tengamos.

Instrucciones para usar el repositorio.

Figura 11.62: Instrucciones para usar el repositorio.

En nuestro caso, el repositorio local ya lo tenemos. Por tanto, las instrucciones que se aplicarían serían las del segundo apartado. Las instrucciones para mi repositorio son las siguientes.

git remote add origin https://github.com/jsamosj/siscd-jsamos.git
git branch -M main
git push -u origin main

11.5.3 Enlazar el repositorio local y el remoto

Para enlazar nuestro repositorio local con el remoto la instrucción que nos indica es la siguiente.

git remote add origin https://github.com/jsamosj/siscd-jsamos.git

En la figura 11.63, se muestra el resultado de la ejecución de este comando.

Resultado de ejecutar el comando remote add.

Figura 11.63: Resultado de ejecutar el comando remote add.

Nos avisa de que ya existe origin. Existe porque nuestro repositorio local es el resultado de la clonación de otro repositorio remoto (en varios comandos nos ha informado sobre la distancia que había entre nuestro repositorio y el repositorio inicial origin). Si, en lugar de clonar un repositorio, hubiéramos partido de un repositorio creado por nosotros, este comando no habría dado error y ya estarían enlazados ambos repositorios.

En esta situación, lo que tenemos que hacer es redefinir origin, mediante el comando siguiente (adaptando el nombre de nuestro repositorio).

git remote set-url origin https://github.com/jsamosj/siscd-jsamos.git

Este comando se ejecuta correctamente (figura 11.64).

Resultado de ejecutar el comando remote set-url.

Figura 11.64: Resultado de ejecutar el comando remote set-url.

A partir de ahora, origin se refiere a nuestro repositorio remoto.

Desde octubre de 2020, GitHub llama a su rama por defecto main en lugar de master, como lo sigue haciendo Git. El siguiente comando lo que hace es renombrar la rama por defecto de nuestro repositorio local Git, para que pase a llamarse como la de GitHub: main. Podríamos considerar otras alternativas, pero vamos a seguir las recomendaciones que nos da GitHub.

git branch -M main

En la figura 11.65, se muestra la ejecución de este comando y el estado de las ramas que queda.

Resultado de ejecutar el comando branch -M.

Figura 11.65: Resultado de ejecutar el comando branch -M.

El único cambio que se observa es que ahora solo tenemos una rama llamada main (en lugar de master).

Por último, escribimos en el repositorio remoto origin el contenido de la rama local main, mediante el siguiente comando.

git push -u origin main

Al ejecutar este comando, se abre una ventana para que nos identifiquemos en GitHub25. En este comando se requiere que nos identifiquemos porque es el primero con el que vamos a acceder al repositorio remoto para escribir sobre él. Pulsamos sobre el botón Sign in with your browser (figura 11.66).

Ejecutar el primer comando requiere identificación.

Figura 11.66: Ejecutar el primer comando requiere identificación.

Se abre la ventana de la figura 11.67, donde tenemos que autorizar a Git a acceder a nuestra cuenta GitHub para realizar las operaciones que necesita. Las opciones por defecto son adecuadas. Pulsamos sobre Autorize GitCredentialManager.

Ejecutar el primer comando requiere identificación.

Figura 11.67: Ejecutar el primer comando requiere identificación.

Una vez consigue acceder, nos avisa que ha podido identificarse y ejecuta el comando. El resultado de la ejecución se muestra en la figura 11.68.

Resultado de la ejecución del comando push.

Figura 11.68: Resultado de la ejecución del comando push.

Como resultado, todos los archivos de nuestro repositorio local controlados por Git ahora se encuentran en nuestro repositorio remoto GitHub, como podemos ver refrescándolo en el navegador (figura 11.69).

Repositorio remoto actualizado.

Figura 11.69: Repositorio remoto actualizado.

En el aparatado Contributors (zona inferior derecha de la figura 11.69), además de la cuenta de la asignatura, aparece también mi cuenta personal, de donde tomamos el repositorio que clonamos, del que procede este.

11.5.4 Realizar cambios en el repositorio remoto

A continuación vamos a realizar cambios en el repositorio de GitHub. Los cambios los podría hacer alguna otra persona a la que le diéramos acceso. Para hacer el ejemplo más inmediato, los vamos a realizar nosotros mismos, editando uno de los archivos.

Para editar un archivo, pulsamos sobre el enlace asociado a su nombre (figura 11.70).

Editar un archivo en el repositorio remoto.

Figura 11.70: Editar un archivo en el repositorio remoto.

En concreto, vamos a editar el archivo cuyo nombre es nuestro usuario de correo con el prefijo “siscd-” (en mi caso, siscd-jsamos.txt).

Para modificar el contenido del archivo, pulsamos sobre el icono Edit this file en la barra de herramientas (figura 11.71).

Modificar un archivo en el repositorio remoto.

Figura 11.71: Modificar un archivo en el repositorio remoto.

Como modificación, en la última línea, añadimos nuestra dirección de correo electrónico. Al final de la página, pulsamos sobre el botón Commit changes (figura 11.72).

Confirmar los cambios del archivo en el repositorio remoto.

Figura 11.72: Confirmar los cambios del archivo en el repositorio remoto.

Tenemos la opción de crear una rama, pero dejamos seleccionada la opción de confirmar los cambios directamente en la rama main.

Los cambios aparecen en el archivo (ya cerrado) y, si miramos en el repositorio (pulsando sobre el enlace de su nombre en la parte superior de la ventana), observamos que se ha actualizado con un nuevo commit (figura 11.73).

Repositorio remoto actualizado.

Figura 11.73: Repositorio remoto actualizado.

11.5.5 Obtener los cambios en el repositorio local

Si vamos a trabajar con el repositorio local, para evitar posibles conflictos, debemos actualizarlo previamente con los posibles cambios que se hayan producido en el repositorio remoto. Podemos obtener los cambios mediante el comando pull.

git pull

El resultado de la ejecución se muestra en la figura 11.74.

Resultado de la ejecución del comando pull.

Figura 11.74: Resultado de la ejecución del comando pull.

En la figura 11.75, se muestra el estado de las ramas del repositorio local.

Ramas del repositorio local.

Figura 11.75: Ramas del repositorio local.

La figura 11.76 representa gráficamente la nueva situación (la misma de la figura 11.75).

Representación del estado del repositorio local.

Figura 11.76: Representación del estado del repositorio local.

Se ha obtenido el nuevo estado creado en el repositorio remoto y el repositorio local está actualizado (como si el cambio lo hubiéramos hecho localmente).

11.5.6 Trabajar con colaboradores

El repositorio remoto permite a varios colaboradores trabajar conjuntamente con los archivos que componen nuestro proyecto. Cada usuario trabaja localmente y comparten su trabajo en el repositorio común.

Podemos gestionar el acceso de otras personas para que puedan modificar el repositorio desde el apartado Settings > Manage access (figura 11.77).

Invitar a colaboradores para compartir nuestro repositorio.

Figura 11.77: Invitar a colaboradores para compartir nuestro repositorio.

11.6 Comandos utilizados

A continuación, se incluye una lista en orden alfabético de los comandos utilizados en este capítulo, junto con una breve descripción de su función.

  • add: añadir archivos al área de almacenamiento.

  • branch: crear una rama.

  • branch -d: borrar una rama.

  • branch -M: renombrar la rama por defecto.

  • checkout: recuperar archivos de una versión específica.

  • clone: clonar un repositorio que está en la Web.

  • commit: confirmar los cambios de los archivos en el área de almacenamiento.

  • commit --amend: modificar un commit hecho previamente.

  • commit -m: confirmar los cambios de los archivos en el área de almacenamiento, añadiendo un comentario.

  • config --global user.name: definir el nombre del usuario.

  • config --global user.email: definir el correo del usuario.

  • config --global core.editor: difinir el editor para comentarios.

  • config --list: listar las opciones definidas.

  • diff: devuelve los cambios de los archivos pendientes de preparar.

  • diff --staged: devuelve los cambios de los archivos preparados respecto a sus versiones confirmadas.

  • help: obtener ayuda.

  • init: crear e inicializar un repositorio.

  • log: consultar el historial de confirmaciones.

  • log -p: consultar el historial de confirmaciones y, para cada confirmación, mostrar las diferencias con la versión anterior.

  • mv: renombrar un archivo.

  • pull: obtener los cambios del repositorio remoto y actualizar el repositorio local.

  • push: actualizar el repositorio remoto a partir del repositorio local.

  • push -u: actualizar el repositorio remoto a partir del repositorio local añadiendo referencias.

  • remote add: definir un repositorio remoto asociado al repositorio local.

  • remote set-url: actualizar la url de un repositorio remoto asociado al repositorio local.

  • restore: recuperar un archivo del repositorio.

  • restore --staged: eliminar un archivo del área de almacenamiento

  • rm: borrar archivos de la carpeta de trabajo.

  • rm --cached: eliminar archivos del área de almacenamiento.

  • rm -f: eliminar archivos del área de almacenamiento y de la carpeta de trabajo.

  • show: mostrar una versión del repositorio.

  • status: muestra los archivos nuevos o modificados que se deben añadir o confirmar al repositorio.

  • tag: consultar las versiones etiquetadas en el repositorio o crear una etiqueta ligera.

  • tag -a: etiquetar una versión en el repositorio mediante una etiqueta anotada.

Ejercicio 11.1 Realiza sobre Git y GitHub las siguientes operaciones:

  1. Configura Git con tus datos: nombre y correo de la asignatura y, en una carpeta de trabajo llamada como tu usuario de correo con el prefijo “siscd-” (en mi caso, siscd-jsamos), clona el contenido del repositorio https://github.com/josesamos/siscd-jsamos. Este será tu repositorio Git de trabajo.
  2. Sobre tu repositorio Git, realiza operaciones equivalentes a las descritas en los apartados 11.3.3 a 11.3.11, adaptando las operaciones a tus datos y repositorio.
  3. Sobre tu repositorio Git, realiza operaciones equivalentes a las descritas en los apartados 11.4.1 a 11.4.7, adaptando las operaciones a tus datos y repositorio.
  4. Sobre tu repositorio Git, realiza operaciones equivalentes a las descritas en el apartado 11.4.8, adaptando las operaciones a tus datos y repositorio.
  5. Crea un repositorio GitHub y realiza operaciones equivalentes a las descritas en la sección 11.5.

Recuerda, cuando se indique un nombre de usuario (para nombres de archivos, carpetas, repositorios, contenido, etc.) usa el nombre de tu usuario de correo electrónico de la asignatura.

Para documentar la realización de este ejercicio, para cada apartado, captura una pantalla donde se muestre el estado de las ramas del repositorio (obtenida mediante el comando git log --oneline --decorate --graph --all) y otra del contenido de la carpeta de trabajo; para el último apartado, incluye también una captura donde se muestre el contenido del repositorio en GitHub.

Bibliografía

Chacon, Scott, and Ben Straub. 2014. Pro Git (2nd Edition). Apress. https://git-scm.com/book/es/v2.

Hinojosa-Gutiérrez, Angel P., and Juan J. Merelo-Guervós. 2017. Aprende Git: ... y, de camino, Github. Independently published.


  1. Con el objetivo de que sea más legible, para el resto de imágenes del intérprete de comandos, he cambiado la presentación de manera que el fondo sea blanco y el texto negro, respetando el resto de colores que usa Git.↩︎

  2. Yo he añadido varios archivos de distinto tipo que después podrás obtener, ahora es suficiente cualquier archivo de texto.↩︎

  3. Por ejemplo, ahora podemos registrarnos con el correo de la asignatura. Si queremos seguir usando la cuenta cuando acabe la asignatura, podemos cambiar nuestra dirección de correo.↩︎

  4. Hay otras maneras de identificarse pero, para no complicar más este ejemplo, vamos a usar este medio.↩︎