0% encontró este documento útil (0 votos)
14 vistas28 páginas

Introducción a Git y Control de Versiones

El documento aborda la importancia del control de versiones en programación, destacando la paranoia que sienten los programadores al modificar código funcional. Se presentan diferentes tipos de sistemas de control de versiones, como los locales, centralizados y distribuidos, siendo git un ejemplo de este último. Además, se ofrece una introducción práctica al uso de git en un proyecto de PHP, incluyendo la configuración y gestión de cambios en el código.
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
14 vistas28 páginas

Introducción a Git y Control de Versiones

El documento aborda la importancia del control de versiones en programación, destacando la paranoia que sienten los programadores al modificar código funcional. Se presentan diferentes tipos de sistemas de control de versiones, como los locales, centralizados y distribuidos, siendo git un ejemplo de este último. Además, se ofrece una introducción práctica al uso de git en un proyecto de PHP, incluyendo la configuración y gestión de cambios en el código.
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

1

Curso PHP Medio Escuela de Administración Pública

git
1.1. La paranoia del programador
Si hay algo que los programadores aprendemos a lo largo del tiempo es lo valioso que es el código que funciona y
lo peligroso que puede llegar a ser modificarlo. No pretendemos defender con esta afirmación que una vez que el
código funcione no es necesario ajustarlo u optimizarlo. No es así. También hemos aprendido que el código que
hacemos funcionar suele ser necesario modificarlo para usar de forma más óptima los recursos o, al menos, para que
sea más entendible para nosotros mismos o para cualquiera que tenga que pelearse con nuestras líneas de código.
Este aprendizaje a base de prueba y error hace que, desde que aprendemos a programar, vivamos en la tensión
continua de que el código que funciona deje de funcionar. Para evitar ese desasosiego hemos inventado todo tipo de
estratagemas, desde la más simple de copiar y comentar el código que se va a modificar (por si las moscas), otras
como copiar archivos y proyectos completos y hasta la más sofisticada de mantener dieciocho copias del mismo
código diseminadas por varias aplicaciones en disco, en la nube, en el correo electrónico, en papel (?!) y, si hace
falta, esculpidos en piedra con símbolos cuneiformes.
Si a esa psicosis añadimos la montaña rusa que suponía trabajar en equipo desarrollando software, mezclando el
código de diferentes personas, de diferentes lugares y que podían afectar a piezas críticas de aplicaciones, el resultado
eran horas y horas de tratamiento psicológico.
Esa paranoia provocó que apareciesen herramientas que permitiesen controlar los cambios que se producían en
los ficheros de código y al mismo tiempo, que estableciesen un sistema para poder trabajar en equipo, evitando en lo
posible las dificultades que implicaba. Se trata de los Sistemas de Control de Versiones (VCS, pos sus siglas en
inglés) que también se conoce como Gestión de la Configuración del Software o SCM.
Uno de esos sistemas es git. En la siguiente sección conoceremos algunos más, qué es git y cómo funciona.
Después lo veremos funcionar en la práctica.
NOTA: Para estos ejemplos se supone que existe instalada una versión de git en su
sistema. En el anexo A se describe la forma de instalar git en sistemas Windows, macOs
y Linux.

1.2. Control de Versiones


El control de versiones es un sistema que registra los cambios realizados sobre un archivo o conjunto de archivos
a lo largo del tiempo, de modo que usted pueda recuperar versiones específicas más adelante.
Un sistema de control de versiones le permite revertir archivos a un estado anterior, revertir el proyecto entero a
un estado anterior, comparar cambios a lo largo del tiempo, ver quién modificó por última vez algo que puede estar
causando un problema, quién introdujo un error y cuándo, y mucho más. Usar un VCS también significa
generalmente que si destroza o pierde archivos, puede recuperarlos fácilmente.

1
Curso PHP Medio Escuela de Administración Pública

1.2.1. Sistemas de control de versiones locales


Para hacer frente a este problema, los programadores desarrollaron hace tiempo VCSs locales que contenían una
simple base de datos en la que se llevaba registro de todos los cambios realizados sobre los archivos (véase Figura
1.1).

Figura 1.1. Diagrama de control de versiones local.

Una de las herramientas de control de versiones más popular fue un sistema llamado rcs, que todavía podemos
encontrar en muchos de los ordenadores actuales. Esta herramienta funciona básicamente guardando conjuntos de
parches (es decir, las diferencias entre archivos) de una versión a otra en un formato especial en disco; puede
entonces recrear cómo era un archivo en cualquier momento sumando los distintos parches.

1.2.2. Sistemas de control de versiones centralizados


Como ya hemos mencionado, otro problema surgía en el momento en el que se necesita colaborar con
desarrolladores en otros sistemas. Para solventar este problema, se desarrollaron los sistemas de control de versiones
centralizados (Centralized Version Control Systems o CVCSs en inglés). Estos sistemas, como CVS, Subversion, y
Perforce, tienen un único servidor que contiene todos los archivos versionados, y varios clientes que descargan los
archivos desde ese lugar central. Durante muchos años éste ha sido el estándar para el control de versiones (véase
Figura 1.2).

Figura 1.2. Diagrama de control de versiones centralizado.

Esta configuración ofrece muchas ventajas, especialmente frente a VCSs locales. Por ejemplo, todo el mundo
puede saber (hasta cierto punto) en qué están trabajando los otros colaboradores del proyecto. Los administradores
tienen control detallado de qué puede hacer cada uno; y es mucho más fácil administrar un CVCS que tener que
lidiar con bases de datos locales en cada cliente.
Sin embargo, esta configuración también tiene serias desventajas. La más obvia es el punto único de fallo que
representa el servidor centralizado. Si ese servidor se cae, entonces durante ese tiempo nadie puede colaborar o
guardar cambios versionados de aquello en que está trabajando. Si el disco duro en el que se encuentra la base de
datos central se corrompe, y no se han llevado copias de seguridad adecuadamente, se pierde absolutamente todo

2
Curso PHP Medio Escuela de Administración Pública

(toda la historia del proyecto salvo aquellas instantáneas que la gente pueda tener en sus máquinas locales). Los
VCSs locales sufren de este mismo problema, cuando tienes toda la historia del proyecto en un único lugar, te
arriesgas a perderlo todo.

1.2.3. Sistemas de control de versiones distribuidos


Los sistemas de control de versiones distribuidos (Distributed Version Control Systems o DVCSs en inglés) surgen
para solventar o al menos paliar estos problemas. git es un DVCS. En un DVCS (como git, Mercurial, Bazaar o
Darcs), los clientes no sólo descargan la última instantánea de los archivos: replican completamente el repositorio.
Así, si un servidor muere, y estos sistemas estaban colaborando a través de él, cualquiera de los repositorios de los
clientes puede copiarse en el servidor para restaurarlo. Cada vez que se descarga una instantánea, en realidad se hace
una copia de seguridad completa de todos los datos (véase Figura 1.3).

Figura 1.3. Diagrama de control de versiones distribuido.

Es más, muchos de estos sistemas se las arreglan bastante bien teniendo varios repositorios con los que trabajar,
por lo que puede colaborar con distintos grupos de gente simultáneamente dentro del mismo proyecto. Esto le
permite establecer varios flujos de trabajo que no son posibles en sistemas centralizados, como pueden ser los
modelos jerárquicos.

1.2.4. Los tres estados


Git tiene tres estados principales en los que se pueden encontrar sus archivos: confirmado (committed),
modificado (modified), y preparado (staged). Confirmado significa que los datos están almacenados de manera
segura en su base de datos local. Modificado significa que ha modificado el archivo pero todavía no lo ha confirmado
a su base de datos. Preparado significa que ha marcado un archivo modificado en su versión actual para que vaya en
su próxima confirmación.
Esto nos lleva a las tres secciones principales de un proyecto de git: el directorio de git ( git directory), el directorio
de trabajo (working directory), y el área de preparación (staging area).

3
Curso PHP Medio Escuela de Administración Pública

1.3. git práctico


Vamos a aprender el funcionamiento básico e imprescindible de git de forma práctica, mediante el desarrollo de
una pequeña aplicación en PHP. Se tratra de una gestión típica de la información contenida en una tabla de base de
datos MySQL, en este caso de recetas. A medida que lo creamos, veremos cómo git nos ayuda con el trabajo del día
a día y nos permite superar, de forma notable, la paranoia del programador.
Antes de empezar es necesario tener la tabla disponible en nuestra base de datos. Para ello es necesario crear una
nueva base de datos en MySQL e importar el contenido del fichero que se incluye como contenido en esta sesión,
con el nombre [Link]. Una vez lo importes, bien con MySQL Workbench o phpMyAdmin la estructura de la
tabla resultante será como el de la Figura 1.4. Si no tienes acceso al fichero, simplemente crea una base de datos con
el nombre 'recetas' y, en ella, una tabla 'recetas' con los campos de la Figura 1.4.

Figura 1.4. Estructura de la tabla 'recetas'

Como puede observar, se trata de una tabla muy simple. Nuestra aplicación se ha de conectar a la base de datos y
mostrar inicialmente una lista de recetas. Para ello, abrimos Eclipse y creamos un nuevo proyecto en PHP con el
nombre ‘Recetas’. Antes de empezar a generar código vamos a preparar nuestro proyecto para utilizar git.
Nota: aunque Eclipse permite trabajar de forma visual con git, para su aprendizaje es
recomendable utilizar la línea de comandos. De esta forma, aprenderá a utilizar todas las
opciones de git que suelen venir disponibles en la herramienta, independientemente de
las que ponga a su disposición el IDE o editor de código que escoga para desarrollar.
Abrimos un terminal y accedemos a la carpeta del proyecto que acabamos de crear. En esa carpeta escriba el
comando:

4
Curso PHP Medio Escuela de Administración Pública

$git --version

Si git está instalado correctamente debería mostrarle la versión instalada en su sistema, similar a:

git version 1.9.1

Con esto nos aseguramos que tenemos disponible git para trabajar.

1.3.1 Configuración
A continuación, realizamos un par de acciones para configurar git de forma global en nuestro sistema y dejarlo
listo para su uso.

Configurar Nombre y Correo


Siempre que use git por primera vez es muy recomendable establecer su nombre de usuario y su correo para que
git incluya esa información cada vez que incluya algún cambio en cualquier repositorio. Tenga en cuenta que si en
su proyecto trabaja alguien más, el identificar quién hace cada cambio es una característica muy útil.
Ejecute los siguientes comandos para que git lo identifique en los cambios de su proyecto:

$git config --global [Link] "[Link]"


$git config --global [Link] "[Link]@[Link]"

Configurar las preferencias de fin de linea


Esta configuración es necesaria para solucionar los problemas que puedan surgir como consecuencia de las
diferencias que existen entre el carácter utilizado como fin de linea en sistemas Windows y Linux/macOS.
Para usuarios de Linux/macOS:

$git config --global [Link] input


$git config --global [Link] true

Y para Windows:

$git config --global [Link] true


$git config --global [Link] true

1.3.2. Crear el repositorio


Veamos cómo crear el repositorio git de nuestro proyecto de recetas. Para ello solo es necesario inicializarlo con el
siguiente comando desde el directorio del proyecto:

$ cd /var/www/Recetas
$ git init
Initialized empty Git repository in /var/www/Recetas/.git/

Nuestro proyecto está aun vacío y, obviamente, nuestro repositorio también. Vamos a crear algo de contenido. La
idea es mostrar la lista de recetas de la tabla de la base de datos. Para iniciar el proyecto vamos a crear un fichero
[Link] que lo primero que ha de hacer es conectar a la base de datos. Creamos el fichero en Eclipse y escribimos
el siguiente código:
<?php
$servidor = "localhost";
$usuario = "root";

5
Curso PHP Medio Escuela de Administración Pública

$pass = "root";
$base_datos = "recetas";

//Conexión al servidor de bases de datos


$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)
or die("Imposible conectar");
?>
Conexión establecida

Comprobamos que todo funciona correctamente y pasamos a incluir este primer archivo de nuestro proyecto en el
repositorio. Para ello escribe el siguiente comando en el terminal:

$git add [Link]


$git commit -m "Primer commit"
[master (root-commit) 939416a] Primer commit
1 file changed, 13 insertions(+)
create mode 100644 [Link]

Más adelante veremos qué significan y por qué usamos estos dos comandos para incluir nuestros cambios en el
repositorio.

1.3.3. Comprobando el estado

Para comprobar el estado del repositorio utilizamos el siguiente comando:

$git status
On branch master
nothing to commit, working directory clean

En la salida nos informa que actualmente no hay nada que incluir en el repositorio. Esto significa que el
repositorio tiene controlado el directorio actual, que no hay cambios pendientes para añadir. Este es uno de los
comandos de git que más utilizaremos durante el desarrollo de una aplicación para monitorizar continuamente el
estado del repositorio y del directorio de trabajo.

1.3.4. Haciendo cambios


Cuando hacemos cambios en cualquier fichero de código en ocasiones necesitamos saber qué ficheros hemos
tocado e incluso cuáles son esos cambios. El uso de un repositorio nos permite monitorizar o hacer un seguimiento
de estos cambios y obtener información muy valiosa.
Hagamos un cambio muy simple en el único fichero que tenemos en PHP y veamos cómo git nos informa de que
algo ha cambiado en nuestro directorio de trabajo.
En el fichero [Link] elimina el mensaje de ‘Conexión establecida’ e incluye una cabecera que sea bastante
visible con el título ‘Recetas’ al final del código:
...
?>
<h1>Recetas</h1>

Consultamos el estado del directorio de trabajo como hemos aprendido en la sección anterior:
$git status
En la rama master
Cambios no preparados para el commit:
(use «git add <archivo>...» para actualizar lo que se ejecutará)
(use «git checkout -- <archivo>...« para descartar cambios en el directorio de trabajo)

modificado: [Link]

no hay cambios agregados al commit (use «git add» o «git commit -a»)

6
Curso PHP Medio Escuela de Administración Pública

Lo primero que se observa es que git sabe que se ha modificado el fichero [Link], pero que aun no se le han
notificado estos cambios.
El mensaje también da algunas pistas sobre lo que hay que hacer a continuación. De hecho nos da dos opciones:
añadir los cambios al repositorio o deshacerlos. Nos explica que si queremos añadir estos cambios al repositorio
tenemos que usar el comando git add y que si queremos eliminar los cambios realizados podemos ejecutar el
comando git checkout.
Vamos a preparar (stage) el cambio.

1.3.5. Preparando los cambios


Para ello ordenamos a git que haga esa preparación:

$git add [Link]

Consultamos de nuevo el estado para ver qué nos muestra git:


$git status
En la rama master
Cambios para hacer commit:
(use «git reset HEAD <archivo>...«para eliminar stage)

modificado: [Link]

Esto nos indica que el cambio realizado en [Link] ha sido preparado. Esto significa que git ahora conoce ese
cambio pero que aun no ha sido registrado de forma permanente en el repositorio. La siguiente operación de
confirmación incluirá esos cambios en el repositorio.
Si por cualquier motivo decide que no quiere confirmar los cambios, el comando status le recuerda que puede
utilizar git reset para deshacer el estado preparado.

1.3.6. Preparando y confirmando


El tener una fase de preparación en git está en línea con la filosofía de mantener el código apartado hasta que
necesitemos tratar con el control del código fuente. Puede continuar haciendo cambios en el directorio de trabajo y
en el momento en el que quiera interactuar con el control de código fuente, git permite registrar sus cambios
mediante pequeñas confirmaciones o commits que registran exactamente lo que haga.
Por ejemplo, suponga que ha editado tres ficheros ([Link], [Link] y [Link]). Ahora imagine que quiere confirmar los
cambios pero que vayan los de [Link] y [Link] en un único commit, mientras que los de [Link], al no estar
relacionado lógicamente con los otros dos, deben ir en un commit separado. Podría hacer lo siguiente:

$git add [Link]


$git add [Link]
$git commit -m "Cambios de a y b"
$git add [Link]
$git commit -m "Cambios no relacionados en c"

Separando la preparación de la confirmación tiene la habilidad de ajustar fácilmente lo que va en cada commit.

1.3.7. Confirmando los Cambios


Ha llegado el momento de aprender a confirmar en el repositorio los cambios que tenemos preparados.
Cuando al principio usamos git commit para confirmar la versión inicial de [Link] en el repositorio,
incluimos la opción -m para escribir un comentario en la linea de comandos. El comando commit le permite
añadir interactivamente un comentario para la confirmación.
Si, por el contrario, omite la opción -m de la linea de comandos, git abrirá el editor de su elección. Ese editor es
escogido de la siguiente lista (en orden de prioridad):

7
Curso PHP Medio Escuela de Administración Pública

1. La variable de entorno GIT_EDITOR.


2. La opción de configuración de git [Link].
3. La variable de entorno VISUAL.
4. La variable de entorno EDITOR.

En nuestro caso tenemos como valor de la variable de entorno EDITOR al editor nano, en un sistema con Linux.
En otros sistemas Linux, Windows o macOS es posible que se abra otro editor distinto.
Veamos cómo funciona esta última opción. Tenemos preparado un cambio para confirmar en el repositorio.
Haga commit sin parámetros:

$git commit

A continuación, se abrirá el editor de texto mostrando su contenido y colocando el cursor al principio del fichero
para que incluya el mensaje que habitualmente colocaríamos con la opción -m:

|
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: [Link]
#

En la primera linea, escriba el comentario “Nuevo título”. Guarde el fichero con las opción correspondiente del
editor. Después de guardar, debería ver los mensajes estándar para los commits en la línea de comandos:

[master 569aa96] Nuevo título


1 files changed, 1 insertions(+), 1 deletions(-)

Ahora consulte el estado de nuevo:

$ git status
On branch master
nothing to commit, working directory clean

El directorio de trabajo está limpio y preparado para que continue.

1.3.8. Cambios, no ficheros


git trabaja con cambios, no con ficheros. La mayoría de sistemas de control de código trabajan con archivos.
Añadimos un fichero al control de código y el sistema hará un seguimiento de los cambios del fichero desde ese
momento.
La estrategia de git es diferente, se centra en los cambios realizados en el fichero más que en el fichero en sí
mismo. Cuando le decimos a git que añada un fichero, no le estamos diciendo a git que añada el fichero al
repositorio. Estás diciendo que git debería tomar nota del estado actual de ese archivo para confirmarlo más tarde
Vamos a ver más detenidamente esa diferencia.

8
Curso PHP Medio Escuela de Administración Pública

Cambie el fichero [Link] para que muestre una lista de las recetas en formato de tabla HTML:
...
<h1>Recetas</h1>
<?php
$consulta = mysqli_query($descriptor, "SELECT * FROM recetas");
$recetas = mysqli_fetch_all($consulta, MYSQLI_ASSOC);
?>
<table>
<tr>
<th>Titulo</th>
<th>Fecha</th>
</tr>
<?php foreach($recetas as $receta):?>
<tr>
<td><?=$receta['titulo']?></td>
<td><?=$receta['fecha']?></td>
</tr>
<?php endforeach;?>
</table>

Preparamos ese cambio:

$git add [Link]

Ahora incluimos un comentario en el código:


...
<h1>Recetas</h1>
<?php
// Obtenemos la lista de recetas
$consulta = mysqli_query($descriptor, "SELECT * FROM recetas");
$recetas = mysqli_fetch_all($consulta, MYSQLI_ASSOC);
?>

Si ahora comprobamos el estado, git nos muestra lo siguiente:

$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: [Link]

Changes not staged for commit:


(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: [Link]

Como puede ver [Link] aparece dos veces en la información del estado. El primer cambio (mostrar lista de
recetas) está preparado y listo para ser confirmado. El segundo cambio (incluir un comentario) no está preparado. Si
hace el commit en este momento, el comentario no será guardado en el repositorio.
Compruébelo confirmando el cambio preparado (el valor por defecto), y muestre el estado de nuevo:

$ git commit -m "Se muestra la lista de recetas"


[master e0c1026] Se muestra la lista de recetas
1 file changed, 19 insertions(+), 1 deletion(-)

$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: [Link]

9
Curso PHP Medio Escuela de Administración Pública

no changes added to commit (use "git add" and/or "git commit -a")

El comando de estado le informa que [Link] tiene cambios no registrados y que ya no está en el área de
preparación (staging area).
Ahora incluimos el segundo cambio en el area de preparación y comprobamos el estado:

$ git add .
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: [Link]

Nota: Hemos usado el directorio actual ('.') como fichero a añadir. Se trata de un atajo
muy conveniente que nos permite añadir todos los cambios realizados en los ficheros
tanto del directorio actual como de sus subdirectorios. Aun así, como añade todos los
cambios, es siempre una buena idea comprobar el estado antes de hacerlo para
asegurarnos que añadimos los cambios que realmente queremos añadir.

Así el segundo cambio ha sido preparado y está listo para ser confirmado ( commit).

$ git commit -m "Incluido un comentario"

1.3.9. Histórico
Para ver la lista de cambios que se han registrado en el repositorio utilizamos el comando:

$ git log

La salida que obtiene es similar a esta:


$ git log
commit 4627ebaebc297800351c244968bbbf8d660353a0
Author: [Link] <[Link]@[Link]>
Date: Thu Jun 9 11:46:41 2017 +0100

Incluido un comentario

commit e0c1026a59ae2ec9656d3f81a396f2ea10ccc9ca
Author: [Link] <[Link]@[Link]>
Date: Thu Jun 9 11:45:08 2017 +0100

Se muestra la lista de recetas

commit b1ffe65cf498504a9b755900c27854f2a5d1c231
Author: [Link] <[Link]@[Link]>
Date: Thu Jun 9 11:22:05 2017 +0100

Nuevo título

commit fb7d8d313c676e8bd5499b541e8a285cdc7d1fd3
Author: [Link] <[Link]@[Link]>
Date: Thu Jun 9 11:21:25 2017 +0100

Primer commit

Es la lista de los cuatro commits que hemos hecho en el repositorio hasta ahora. Esta información puede
formatearse con las opciones que nos proporciona git log dandonos mucho control sobre lo que queremos obtener.
Por ejemplo, con la siguiente opción puede ver cada commit en una línea:

10
Curso PHP Medio Escuela de Administración Pública

$ git log --pretty=oneline


4627ebaebc297800351c244968bbbf8d660353a0 Incluido un comentario
e0c1026a59ae2ec9656d3f81a396f2ea10ccc9ca Se muestra la lista de recetas
b1ffe65cf498504a9b755900c27854f2a5d1c231 Nuevo título
fb7d8d313c676e8bd5499b541e8a285cdc7d1fd3 Primer commit

También hay muchas opciones que nos permiten seleccionar qué campos de información van a ser mostrados en
la salida. Pruebe con estos comandos:
$ git log --pretty=oneline --max-count=2
$ git log --pretty=oneline --since='5 minutes ago'
$ git log --pretty=oneline --until='5 minutes ago'
$ git log --pretty=oneline --author=<tu nombre>
$ git log --pretty=oneline --all

En este otro ejemplo, podemos revisar los cambios hechos durante la semana pasada. Incluso puede filtrar por
autor para ver sus propios cambios con --author=[Link]:

$ git log --all --pretty=format:'%h %cd %s (%an)' --since='7 days ago'

Para el trabajo diario la siguiente formula es tremendamente útil:

$ git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short


* 4627eba 2017-06-09 | Incluido un comentario (HEAD, master)[[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Veamos el significado de los parámetros:


--pretty="..." define el formato de la salida.
%h es la cadena hash del commit en formato abreviado
%d es cualquier decoración en ese commit ([Link]. rama, cabecera o etiqueta)
%ad es la fecha de creación
%s es el comentario
%an es el nombre del autor
--graph pide a git que muestre el árbol de commits en una salida gráfica en ASCII
--date=short mantiene el formato corto de fecha

Afortunadamente los desarrolladores de git nos permiten crear alias sobre estos comandos.
Tanto en macOs ([Link]. gitx) como en otra cualquier plataforma ([Link]. gitk) existen multitud de herramientas que
permiten explorar el histórico o log de nuestro repositorio.

1.3.10. Alias
git permite crear alias y atajos para sus comandos.
Instrucciones como git status, git add, git commit y git checkout son tan comunes que es muy
útil disponer de abreviaturas que nos faciliten su uso.
Para crear esos alias de comandos es necesario modificar un fichero de configuración de git que se genera al
instalar git en el directorio personal del usuario y cuyo nombre es .gitconfig.

11
Curso PHP Medio Escuela de Administración Pública

Abra ese archivo y escriba el siguiente texto:


[alias]
co = checkout
ci = commit
st = status
br = branch
hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
type = cat-file -t
dump = cat-file -p

Con esta configuración disponemos de alias para los comandos de git vistos hasta ahora y algunos más que
trataremos más adelante. Así podemos escribir git st en lugar de git status y git ci para git commit.
Ni qué decir tiene la utilidad que tiene en este caso git hist que nos evita el tener que recordar la ristra de
parámetros de log que vimos anteriormente.
Pruebe los diferentes alias para ver que realmente muestran la misma información que hemos visto hasta ahora.
En las secciones siguientes seguiremos usando los comandos completos, sin alias. La única excepción la haremos
con git hist, ya que será el comando que usaremos para ver la salida de git log. Asegúrese de que tiene bien
definido ese alias antes de continuar.
Alias para la línea de comandos posix
Nota: Este apartado se refiere a usuarios de linea de comandos posix como Linux o
macOs. Los usuarios de Windows u otros sistemas no posix pueden pasar al siguiente
apartado. Aun así, al instalar git en sistemas Windows la instalación le permite
seleccionar como shell para git una aplicación que se incluye con el instalador llamada
GIT Bash que a efectos prácticos es como tener un sistema Linux.
Si su linea de comandos o shell soporta alias y atajos, también es muy útil usar alias para git en este nivel. Le
mostramos algunos ejemplos que puede utilizar alterando el fichero .profile de su directorio de usuario:
alias gs='git status '
alias ga='git add '
alias gb='git branch '
alias gc='git commit'
alias gd='git diff'
alias go='git checkout '
alias gk='gitk --all&'
alias gx='gitx --all'

Un atajo particularmente práctico es la abreviatura para el comando git checkout para saltar a una rama ( branch)
en particular:

$ go <rama>

1.3.11. Recuperando viejas versiones


Con git los viajes en el tiempo son reales. Obviamente estamos exagerando. Podemos viajar hacia atrás en la
historia, sí, pero la del repositorio. Para ello, utilizando el comando checkout, git copiará cualquier instantanea
desde el repositorio al directorio de trabajo.
En primer lugar necesitamos identificar de alguna manera cada una de esas instantaneas o commits. Si recuerda la
información que muestra el alias git hist que hemos configurado en la sección anterior, en cada linea, existe una
cadena hash única. La cadena completa la hemos visto al ejecutar algunos ejemplos de git log. En git hist se
ven solo los últimos siete caracteres de la cadena, longitud suficiente para poder identificar cada uno de los commits.
Haga git hist de nuevo para ver la lista de commits con sus correspondientes hashes;
$ git hist
* 4627eba 2017-06-09 | Incluido un comentario (HEAD, master)[[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

12
Curso PHP Medio Escuela de Administración Pública

Examine la salida de log y encuentre el hash para el primer commit. Se trata de la última línea de la lista. Utilice
ese código hash (con esos siete caracteres es suficiente) en el comando que usaremos a continuación ($ git
checkout <hash>). Después revise el contenido del fichero [Link].

$ git checkout fb7d8d3

Nota: Muchos comandos dependen de los valores hash del repositorio. Como sus valores
hash serán distintos de los usados en los ejemplos, siempre que vea algo como <hash>
o <arbolhash> en los ejemplos de comandos, sustituyalos con el valor hash
correspondiente de su repositorio.

La salida será:
Note: checking out 'fb7d8d3'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD se encuentra en fb7d8d3... Primer commit

La salida de esta instrucción explica muy bien la situación. Examine el contenido del fichero [Link], se
encuentra con el contenido original, el del primer commit. No se preocupe, no ha perdido su trabajo, tiene solución.
Antes de maldecir a git, vamos a retornar a la última version de la rama master, la rama actual en la que nos
encontramos y, de hecho, la única rama que tenemos. Para ello ejecute el comando siguiente:
$ git checkout master
Previous HEAD position was fb7d8d3... Primer commit
Switched to branch 'master'

‘master’ es el nombre de la rama por defecto. Haciendo checkout sobre una rama por su nombre, le lleva a la
última versión de esa rama.
Revise de nuevo el código de [Link]. ¡Ya puede respirar aliviado!

1.3.12. Etiquetando versiones


Aunque el etiquetado en git es muy simple, aplicado al concepto de versiones le da mucha potencia y nos permite
trabajar de forma muy sencilla con las distintas versiones de nuestras aplicaciones. Esta utilidad nos permite poner
etiquetas a un cojunto de commits, identificando un instante en el repositorio que hemos determinado que
constituye una versión (desarrollo, pruebas, release candidate, release, producción, etc.) en su totalidad.
Por ejemplo, podemos nombrar la versión actual de nuestra aplicación de recetas como la versión 1:

$ git tag v1

Desde ese momento podemos referenciar la versión actual de nuestro programa como v1.
Pero eso no es todo, git también nos permite etiquetar las versiones previas. En nuestro caso vamos a etiquetar la
versión inmediatamente anterior a la actual versión como v1-beta.
Antes de hacerlo necesitamos acceder a la version previa. En esta ocasión, en lugar de usar códigos hash,
utilizaremos la notación ^ para indicar que queremos acceder al “padre o antecesor de v1”. Si la notación v1^ le da

13
Curso PHP Medio Escuela de Administración Pública

algún problema, también puede utilizar v1~1, que hace referencia a la misma versión. Esta notación significa “el
primer ancestro de v1”.

$ git checkout v1^


Note: checking out 'v1^'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD se encuentra en e0c1026... Se muestra la lista de recetas

Si revisa el archivo [Link] puede comprobar que esta versión en la que mostrabamos la tabla con la lista de
recetas antes de incluir un comentario. Etiquétela como v1-beta:

$ git tag v1-beta

Ahora puede ir hacia delante y hacia atrás entre las dos versiones etiquetadas.

$ git checkout v1
Previous HEAD position was e0c1026... Se muestra la lista de recetas
HEAD se encuentra en 4627eba... Incluido un comentario

$ git checkout v1-beta


Previous HEAD position was 4627eba... Incluido un comentario
HEAD se encuentra en e0c1026... Se muestra la lista de recetas

Para ver la lista de etiquetas disponibles utilice el siguiente comando:

$ git tag
v1
v1-beta

También es posible ver información de la etiqueta desde el histórico o log. Pruebe el siguiente comando:

$ git hist master --all


* 4627eba 2017-06-09 | Incluido un comentario (tag: v1, master) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (HEAD, tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Ahora puede ver ambas etiquetas listadas en la salida del log, junto con el nombre de la rama (master). También
el literal HEAD muestra el commit en el que se encuentra en ese momento (en este caso v1-beta).

1.3.13. Deshaciendo cambios locales (antes de la preparación o staging)


En este apartado practicaremos cómo revertir cambios en el directorio de trabajo.
Antes de nada, vamos a asegurarnos que estamos en el último commit antes de proceder. ¿Recuerda qué
comando era?:

$ git checkout master

14
Curso PHP Medio Escuela de Administración Pública

Una vez situados en el lugar correcto, mejoremos un poco el aspecto de nuestra lista de recetas. Le vamos a
agregar varios estilos y darle algo de vistosidad. Para ello, incluya las etiquetas HTML que faltan. Agregue también el
campo descripción a la tabla. El codigo resultante debe ser parecido a este:
<?php
$servidor = "localhost";
$usuario = "root";
$pass = "root";
$base_datos = "recetas";

// Conexión al servidor de bases de datos


$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)
or die("Imposible conectar");
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recetas</title>
</head>
<body>
<h1>Recetas</h1>
<?php
$consulta = mysqli_query($descriptor, "SELECT * FROM recetas");
$recetas = mysqli_fetch_all($consulta, MYSQLI_ASSOC);
?>
<table>
<tr>
<th>Título</th>
<th>Descripción</th>
<th>Fecha</th>
</tr>
<?php foreach($recetas as $receta):?>
<tr>
<td><?=$receta['titulo']?></td>
<td><?=$receta['descripcion']?></td>
<td><?=$receta['fecha']?></td>
</tr>
<?php endforeach;?>
</table>
</body>
</html>

EJERCICIO: Antes de continuar, prepare este cambio y añadalo al repositorio. ¿Recuerda cómo se hace?
$ git add .
$ git commit -m “Incluyendo formato correcto para HTML”
[master 9d17dfd] Incluyendo formato correcto para HTML
2 files changed, 25 insertions(+), 12 deletions(-)

Para continuar, en la sección head incluya algunos estilos que muestren más atractiva la página web. Puede
utilizar estos estilos como ejemplo:
<style type="text/css">
h1{ color: red; padding: 5px; border: 2px yellow solid;}
table{ border: 2px green solid; }
th { background-color: red; font-weight:bold;}
td {padding: 5px;}
</style>

Compruebe el resultado. Nefasto. El infierno del daltónico.


En algunas ocasiones, como en esta, modificamos uno o varios archivos del directorio de trabajo y deseamos (o
suplicamos) deshacer todos los cambios que acabamos de hacer. Al menos, no hemos añadido nada al repositorio.
Pero como git hace un seguimiento de todo lo que pasa, nos permite deshacer los posibles destrozos con el comando
checkout.

15
Curso PHP Medio Escuela de Administración Pública

Antes de volver comprobamos el estado:

$ git status
En la rama master
Cambios no preparados para el commit:
(use «git add <archivo>...» para actualizar lo que se ejecutará)
(use «git checkout -- <archivo>...« para descartar cambios en le directorio de trabajo)

modificado: [Link]

no hay cambios agregados al commit (use «git add» o «git commit -a»)

Nos informa que el fichero [Link] ha sido modificado pero aun no ha sido preparado ( staged).
Vamos a revertir los cambios en el directorio de trabajo. Use el comando checkout para restaurar el fichero
[Link] a la versión del repositorio:

$ git checkout [Link]


$ git status
On branch master
nothing to commit, working directory clean

Revise el código para asegurarnos que el estilo ochentero ha desaparecido de nuestra página de recetas.
Aunque este ha sido un cambio muy pequeño, tanto que el mismo IDE le permitiría deshacerlo, este comando es
muy útil cuando hemos modificado por completo un archivo de código, un método o alguna clase en PHP de tal
manera que la aplicación deja de funcionar correctamente.

1.3.14. Deshaciendo los cambios preparados (antes de confirmar)


Puede suceder que los cambios que realizamos y deseamos deshacer se encuentren ya preparados, antes de hacer
un commit. Git permite tmabién deshacer esos cambios.
Cambie de nuevo el archivo [Link] y añada los estilos desagradables del último ejemplo. Ahora prepare ese
cambio en el repositorio:

$ git add [Link]

Comprueba el estado del cambio no deseado.


$ git status
En la rama master
Cambios para hacer commit:
(use «git reset HEAD <archivo>...«para eliminar stage)

modificado: [Link]

El estado informa que ya se ha preparado el cambio y esta listo para el commit.


Afortunadamente, también nos explica qué necesitamos para quitar el cambio de la preparación o stage.

$ git reset HEAD [Link]


Unstaged changes after reset:
M [Link]

El comando reset restaura el área de preparación para estar como está en el HEAD. Esto limpia ese área de los
cambios que hemos preparado.

16
Curso PHP Medio Escuela de Administración Pública

Este comando (por defecto) no cambia el directorio de trabajo. La sección <style> continua estando en el
archivo [Link]. Si queremos eliminar ese cambio definitivamente del directorio de trabajo podemos usar el
comando checkout descrito en la sección anterior:

$ git checkout [Link]


$ git status
On branch master
nothing to commit, working directory clean

Ahora nuestro directorio de trabajo está limpio de nuevo. Vamos a etiquetar esta nueva version como v2:
$ git tag v2

1.3.15. Deshaciendo cambios ya confirmados


En ocasiones necesitamos revertir cambios que ya tenemos hechos y confirmados en el repositorio. De hecho es la
acción que nos permitirá estar más seguro cuando realicemos cualquier tipo de despliegue de las versiones de
nuestras aplicaciones, sobre todo en producción. Aunque, como ya hemos visto, el versionado con etiquetas junto
con el despliegue basado en versiones es la forma más eficiente y segura de gestionar los despliegues.
Cuando ya tenemos nuestros cambios en un repositorio es que estamos bastantes seguros que ese código funciona
correctamente. Sin embargo, también es habitual que el código que ya tenemos en repositorio falle y debamos
revertir esos cambios a una versión que sabemos a ciencia cierta que carece de errores.
Una aproximación inicial, sin tratar el tema de versiones, consistiría en deshacer un commit que provoca un error
en la aplicación. Existen diversas formas de manejar esta situación, y la manera en la que vamos a usarla en este
apartado es siempre segura.
Esencialmente vamos a deshacer el commit creando un nuevo commit que revierta los cambios no deseados.
Vuelva a introducir de nuevo los estilos indeseables que hemos usado en las secciones anteriores y confirme ese
cambio en el repositorio.

$ git add [Link]


$ git commit -m "Ops, no queremos este commit"
[master 1622209] Ops, no queremos este commit
1 file changed, 6 insertions(+)

Para deshacer el cambio confirmado necesitamos generar un commit, que se realiza como resultado del siguiente
comando:

$ git revert HEAD

Esto le llevará al editor de texto por defecto. Puede editar el mensaje de commit por defecto o dejarlo como está.
Guarde el fichero y cierrelo. La salida le mostrará lo siguiente:

[master b076849] Revert "Ops, no queremos este commit"


1 file changed, 6 deletions(-)

Como estamos deshaciendo el último commit que hicimos, podemos usar HEAD como argumento. Podemos
revertir cualquier otro commit anterior simplemente especificando su valor hash.
Si comprueba el log le mostrará tanto los cambios realizados como los revertidos del repositorio.

$ git hist
* b076849 2017-06-09 | Revert "Ops, no queremos este commit" (HEAD, origin/master, master)
[[Link]]
* 1622209 2017-06-09 | Ops, no queremos este commit [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]

17
Curso PHP Medio Escuela de Administración Pública

* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]


* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Esta técnica funcionará con cualquier commit (aunque es posible que tengasque resolver conflictos). Es segura
utilizarla incluso en ramas que estan públicamente compartidas en repositorios remotos.

1.3.16. Eliminando commits de una rama


El comando revert de la sección anterior es una herramienta potente que nos permite deshacer los efectos de
cualquier commit en el repositorio. Sin embargo, tanto el commit original como el que hemos deshecho son visibles
en la historia de la rama.
Suele suceder que al hacer un commit nos damos cuenta que es un error. Sería genial tener una forma de volver
atrás, como si ese commit incorrecto nunca hubiese sucedido. Ese comando también debería prevenir que el commit
incorrecto no aparezca en el histórico. Sería como si el commit nunca se hubiese producido.
Ese comando es reset, que ya hemos visto antes cuando lo hemos usado para que el área de preparación sea
consistente con un commit dado.
Cuando le damos una referencia de commit (un hash, una rama o una etiqueta) al comando reset:
• Reescribe la rama actual para apuntar al commit especificado
• Opcionalmente reestablece el área de preparación para coincidir con el commit especificado
• Opcionalmente reestablece el directorio de trabajo para coincidir con el commit especificado

Vamos a examinar el histórico de commits:

$ git hist
* b076849 2017-06-09 | Revert "Ops, no queremos este commit" (HEAD -> master, origin/master,
origin/HEAD) [[Link]]
* 1622209 2017-06-09 | Ops, no queremos este commit [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Podemos ver el commit “Ops” y el commit Revert “Ops” como los dos últimos commits que hemos hecho en la
rama. Vamos a eliminarlos usando reset.
Antes de eliminar los commits vamos a marcar el último commit con una etiqueta para que podamos encontrarlo
de nuevo.

$ git tag ops

Si observa detenidamente el histórico anterior puede advertir que el commit etiquetado como 'v2' es justo el
commit anterior al commit incorrecto. Vamos a resetear la rama hasta ese punto. Como el commit está etiquetado,
podemos usar la etiqueta en el comando reset (sino siempre podemos usar el valor hash).

$ git reset --hard v2


HEAD is now at 4627eba Incluido un comentario

$ git hist
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (HEAD -> master, tag: v2)
[[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]

18
Curso PHP Medio Escuela de Administración Pública

* b1ffe65 2017-06-09 | Nuevo título [[Link]]


* fb7d8d3 2017-06-09 | Primer commit [[Link]]

La rama master apunta ahora al commit v2 y los commits Ops y Revert Ops ya no están en la rama. El parámetro
--hard indica que el directorio de trabajo debe ser actualizado para que sea consistente con la nueva cabecera de la
rama.
Aun así, nada se pierde en git. ¿Qué ha pasado con los commits incorrectos? Pues resulta que esos commits aun
están en el repositorio. De hecho, todavía podemos referenciarlos.

$ git hist --all


* b076849 2017-06-09 | Revert "Ops, no queremos este commit" (tag: ops, origin/master, origin/HEAD)
[[Link]]
* 1622209 2017-06-09 | Ops, no queremos este commit [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (HEAD -> master, tag: v2)
[[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Como puede ver los commits incorrectos no han desaparecido. Todavía están en el repositorio. Solo sucede que
no se listarán en la rama master. Si no los hubiésemos etiquetado, seguirían en el repositorio pero tendríamos que
identificarlos por sus valores hash. Los commits que no están referenciados (etiquetados) permanecen en el
repositorio hasta que el sistema ejecuta el software de recolección de basura.
Los “reseteos” en ramas locales son por lo general seguros. Cualesquiera “accidentes” pueden usualmente ser
recuperados solamente reseteando de nuevo con el commit deseado.
Sin embargo, si la rama se comparte en repositorios remotos, los “reseteos” pueden confundir a los usuarios con
los que se comparte la rama.
La etiqueta ops ya ha cumplido con su propósito. Vamos a eliminarla para que el recolector de basura haga su
trabajo y la elimine definitivamente.

$ git tag -d ops


Deleted tag 'ops' (was b076849)

$ git hist --all


* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (HEAD -> master, tag: v2)
[[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

1.3.17. Modificar commits


¿Qué sucede si hemos confirmado los cambios pero recordamos que nos falta algún cambio simple?¿Creamos
otro commit?
No es necesario. Es posible modificar el commit actual. Para ver cómo funciona modifiquemos nuestro fichero
[Link]. Vamos a añadir Bootstrap para que tenga un aspecto visual más atractiva.

<?php
$servidor = "localhost";
$usuario = "root";
$pass = "root";
$base_datos = "recetas";

// Conexión al servidor de bases de datos


$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)
or die("Imposible conectar");

19
Curso PHP Medio Escuela de Administración Pública

?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Recetas</title>
</head>
<body>
<div class="container-fluid">
<h1>Recetas</h1>
<?php
$consulta = mysqli_query($descriptor, "SELECT * FROM recetas");
$recetas = mysqli_fetch_all($consulta, MYSQLI_ASSOC);
?>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Título</th>
<th>Descripción</th>
<th>Fecha</th>
</tr>
</thead>
<?php foreach($recetas as $receta):?>
<tr>
<td><?=$receta['titulo']?></td>
<td><?=$receta['descripcion']?></td>
<td><?=$receta['fecha']?></td>
</tr>
<?php endforeach;?>
</table>
</div>
</body>
</html>

Hemos añadido varias etiquetas y estilos para la tabla que muestra las recetas. Vamos a agregar esos cambios al
repositorio.

$ git add [Link]


$ git commit -m "Incluido Bootstrap y alterado el estilo de la lista de recetas"

Después de hacer el commit, recordamos que no hemos probado a ver si lo que hemos cambiado tiene el estilo
que queremos que tenga. Comprobamos que realmente no se ha modificado el aspecto. Nos faltan las librerias de
estilos y javascript de Bootstrap. Añada las siguientes líneas a la sección <head> del archivo:

<link rel="stylesheet"
href="[Link]
<script src="[Link]

Realmente no queremos separar ese cambio en otro commit por dos líneas. Vamos amodificar el commit anterior
para incluirlas:

$ git add [Link]


$ git commit --amend -m "Incluidas librerias de Bootstrap y algunos estilos"
[master 20e31ee] Incluidas librerias de Bootstrap y algunos estilos
Date: Fri Jun 10 22:36:11 2017 +0100
1 file changed, 10 insertions(+), 3 deletions(-)

20
Curso PHP Medio Escuela de Administración Pública

Comprobemos el histórico:

$ git hist
* 20e31ee 2017-06-10 | Incluidas librerias de Bootstrap y algunos estilos (HEAD -> master)
[[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Como puede ver el commit original ya no aparece, ha sido reemplazado por el último. Podría obtener el mismo
resultado reseteando la rama a un commit anterior y haciendo el commit de los nuevos cambios.

1.3.18. Creando un rama


Es hora de hacer un cambio mayor en nuestra aplicación de recetas. Como esto puede llevar tiempo, vamos a
poner estos cambios en una rama separada para aislarlos de los cambios de la rama master. El mayor cambio será el
de mostrar la información de una receta concreta. Por tanto, llame a esa rama nueva como “receta”.

$ git checkout -b receta


Switched to a new branch 'receta'

$ git status
On branch receta
nothing to commit, working tree clean

Nota: git checkout -b <nombre de rama> es un atajo para git branch


<nombre de rama> seguido de git checkout <nombre de rama>.

Advierta que el comando git status informa que ahora se encuentra en la rama 'receta'.
Si ejecuta el comando git branch puede ver la lista de las ramas del proyecto y algo mas:

$ git branch
master
* receta

Muestra las dos ramas que tenemos en este momento en el proyecto y, además, que la rama activa es receta,
utilizando un carácter asterisco delante de su nombre.
A modo de ejemplo vamos a hacer cambios menores que usaremos para hacer commits y así explicar la utilidad
de las ramas. Normalmente un commit supone un grupo de cambios significativos más que cambios menores.
En primer lugar vamos a extraer la configuración y la conexión a la base de datos en un fichero diferente e
incluirlo en nuestro archivo [Link]. También nos servirá para el fichero que utilizaremos para ver una receta en
particular.
Escriba en el fichero [Link] la parte de [Link] que configura y conecta con la base de datos:
<?php
$servidor = "localhost";
$usuario = "root";
$pass = "root";
$base_datos = "recetas";

// Conexión al servidor de bases de datos


$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)
or die("Imposible conectar");

21
Curso PHP Medio Escuela de Administración Pública

$ git add [Link]


$ git commit -m "Incluido archivo de conexion a base de datos"

Ahora es necesario modificar el fichero [Link]. Elimine la parte que hemos trasladado a [Link] y
confirme ese cambio:

$ git add [Link]


$ git commit -m "Eliminada la conexion de [Link]"

Finalmente incluya la conexión desde el archivo [Link] con el siguiente código al principio del fichero:
<?php require_once '[Link]';?>
<!DOCTYPE html>
...

Confirmamos ese cambio:

$ git add [Link]


$ git commit -m "Incluimos la conexion en [Link]"

Ahora tenemos una nueva rama llamada receta con tres nuevos commits en ella.

1.3.20. Navegando entre ramas


Nuestro proyecto tiene en este momento tres ramas:

$ git hist --all


* 8b910c2 2017-06-11 | Incluimos la conexion en [Link] (HEAD -> receta) [[Link]]
* ced691a 2017-06-11 | Eliminada la conexion de [Link] [[Link]]
* b404e3f 2017-06-11 | Incluido archivo de conexion a base de datos [[Link]]
* 20e31ee 2017-06-10 | Incluidas librerias de Bootstrap y algunos estilos (master)
[[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Para movernos a otra rama usamos el comando git checkout:

$ git checkout master


Switched to branch 'master'

Nota: Si tiene dudas de qué ramas tiene disponibles así como en cuál está antes de
moverse, recuerde utilizar git branch para informarse antes de actuar.
Ahora está en la rama master de nuevo. Eche un vistazo al proyecto para ver cómo ha cambiado todo al cambiar
de rama. git ha hecho su magia. Ha desaparecido el archivo [Link] e [Link] sigue apareciendo como
antes de crear la nueva rama.
Vuelva de nuevo a la rama receta y observe de nuevo los cambios:

$ git checkout receta


Switched to branch 'receta'

22
Curso PHP Medio Escuela de Administración Pública

1.3.21. Cambios en la rama master


Mientras que está cambiando la rama receta, imagine que alguien también decidió actualizar la rama master.
Simplemente esa persona ha añadido un archivo README. El típico archivo que nos proporciona información
importante acerca de la aplicación a la que acompaña y que, en ocasiones, constituyen todo un tutorial de uso de la
aplicación.
En primer lugar, regresamos a la rama master:

$ git checkout master

Ahora cree en el proyecto un fichero README e incluya este texto:

La mejor web de recetas de los alrededores de Bilbao, no apta para cocinillas.

Confirme el cambio en el repositorio:

$ git add README


$ git commit -m "Incluido README"
[receta 24e77a3] Incluido README
1 file changed, 1 insertion(+)
create mode 100644 README

En este momento tenemos dos ramas divergentes en el repositorio. Utilice el siguiente comando para ver las
ramas y sus divergencias:

$ git hist –all


* 6bce127 2017-06-11 | Incluido README (HEAD -> master) [[Link]]
| * 8b910c2 2017-06-11 | Incluimos la conexion en [Link] (receta) [[Link]]
| * ced691a 2017-06-11 | Eliminada la conexion de [Link] [[Link]]
| * b404e3f 2017-06-11 | Incluido archivo de conexion a base de datos [[Link]]
|/
* 20e31ee 2017-06-10 | Incluidas librerias de Bootstrap y algunos estilos [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Esta es la primera oportunidad que tenemos de ver la opción --graph de git hist en acción. Usando esta
opción con git log provoca que se dibuje el arbol de commits con caracteres ASCII. En ese árbol podemos ver ambas
ramas (receta y master) y que la rama master es la cabecera (HEAD) actual. El ancestro actual de ambas rama es el
commit “Incluidas librerias de Bootstrap y algunos estilos”. La opción --all asegura que vemos todas las ramas, ya
que por defecto solo se mostraría la rama actual.

1.3.22. Mezclar Ramas


En esta sección aprenderemos cómo mezclar dos ramas divergentes para llevar los cambios a una única rama.

$ git checkout receta


Switched to branch 'receta'

$ git merge master


Merge made by the 'recursive' strategy.
README | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README

23
Curso PHP Medio Escuela de Administración Pública

$ git hist –all


* 3d6d5e0 2017-06-11 | Merge branch 'master' into receta (HEAD -> receta) [[Link]]
|\
| * 6bce127 2017-06-11 | Incluido README (master) [[Link]]
* | 8b910c2 2017-06-11 | Incluimos la conexion en [Link] [[Link]]
* | ced691a 2017-06-11 | Eliminada la conexion de [Link] [[Link]]
* | b404e3f 2017-06-11 | Incluido archivo de conexion a base de datos [[Link]]
|/
* 20e31ee 2017-06-10 | Incluidas librerias de Bootstrap y algunos estilos [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

Mezclando la rama master en la rama receta periódicamente puedes obtener los cambios en master y mantener
sus cambios en receta compatibles con los cambios en la línea principal.
Pero, ¿qué pasaría si los cambios en master provocasen algún conflicto con los cambios en receta?

1.3.23. Crear un conflicto

Vuelva a la rama master:

$ git checkout master

En el fichero [Link] haga este cambio:


// Conexión al servidor de bases de datos
$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)

or die("Imposible conectar");
?>

Simplemente es un salto de línea entre la conexión y el die(). Confirme ese cambio simple:

$ git add [Link]


$ git commit -m "Lineas mas legibles"

Veamos qué nos muestra el histórico:

$ git hist --all


* fdb9b46 2017-06-11 | Lineas mas legibles (HEAD -> master) [[Link]]
| * 3d6d5e0 2017-11-11 | Merge branch 'master' into receta (receta) [[Link]]
| |\
| |/
|/|
* | 6bce127 2017-06-11 | Incluido README [[Link]]
| * 8b910c2 2017-06-11 | Incluimos la conexion en [Link] [[Link]]
| * ced691a 2017-06-11 | Eliminada la conexion de [Link] [[Link]]
| * b404e3f 2017-06-11 | Incluido archivo de conexion a base de datos [[Link]]
|/
* 20e31ee 2017-06-10 | Incluidas librerias de Bootstrap y algunos estilos [[Link]]
* 9d17dfd 2017-06-09 | Incluyendo formato correcto para HTML (tag: v2) [[Link]]
* 4627eba 2017-06-09 | Incluido un comentario (tag: v1) [[Link]]
* e0c1026 2017-06-09 | Se muestra la lista de recetas (tag: v1-beta) [[Link]]
* b1ffe65 2017-06-09 | Nuevo título [[Link]]
* fb7d8d3 2017-06-09 | Primer commit [[Link]]

24
Curso PHP Medio Escuela de Administración Pública

La rama master con el commit “Incluido README” se ha mezclado con la rama receta, pero ahora hay un
commit adicional en master que aun no ha sido mezclado en receta.
Ese último cambio en master entra en conflicto con los existentes en receta. Veamos cómo resolver esos cambios.

1.3.24. Resolviendo conflictos


Vuelva de regreso a la rama receta e intente mezclar con master de nuevo.

$ git checkout receta


Switched to branch 'receta'

$ git merge master


Auto-merging [Link]
CONFLICT (content): Merge conflict in [Link]
Automatic merge failed; fix conflicts and then commit the result.

Se ha detectado un conflicto en el fichero [Link] entre las versiones de cada rama. Si examina el fichero
[Link] puede ver algo así:

<<<<<<< HEAD
<?php require_once '[Link]';?>
=======
<?php
$servidor = "localhost";
$usuario = "root";
$pass = "root";
$base_datos = "recetas";

// Conexión al servidor de bases de datos


$descriptor = mysqli_connect($servidor, $usuario, $pass, $base_datos)

or die("Imposible conectar");
?>
>>>>>>> master
<!DOCTYPE html>
...

Puede identificar dos secciones dividas por una doble linea. La primera sección es la versión de la cabecera de la
rama actual (receta). La segunda sección es la versión de la rama master.
Esto indica que en esa sección existe un conflicto entre ambas versiones y es necesario resolverlo manualmente.
Modifique el archivo [Link] eliminando la sección de la rama master y confirme el cambio indicando que ese
commit es para arreglar ese conflicto.

$ git add [Link]


$ git commit -m "Arreglado conflicto al mezclar con master"
[receta 9c2f134] Arreglado conflicto al mezclar con master

1.4. Múltiples repositorios


Hasta ahora solo hemos visto cómo trabajar con un único repositorio en local. Lo normal es que exista un
repositorio compartido en el que se mezclen los cambios de varios desarrolladores, y se resuelvan los conflictos
derivados de trabajo colaborativo.

25
Curso PHP Medio Escuela de Administración Pública

Con git podemos trabajar con varios repositorios situados local o remotamente. Lo más usual será tener un
repositorio local sincronizado con uno remoto, en el que otros desarrolladores puedan subir sus cambios.
En Internet existen multitud de plataformas para albergar repositorios de proyectos de desarrollo de software
siendo las más famosas Github ([Link] y Bitbucket ([Link] Ambos permiten crear de
forma gratuita una cuenta de acceso y repositorios. La diferencia principal entre ambos es que Github no permite
crear repositorios totalmente privados y Bitbucket sí. Acceda a la página web de Bitbucket y creese una nueva cuenta
de acceso. Una vez acceda cree un nuevo repositorio llamado Recetas. La página resultante debe ser similar a la
Figura 1.5:

Figura 1.5. Página de nuevo repositorio de Bitbucket.

Seleccione la opción “I have an existing project” para ver las siguientes opciones:

Como
puede ver, le indica los pasos a seguir para sincronizar su repositorio local con esta plataforma. Esos pasos son,
inicialmente, que acceda al directorio de su repositorio; a continuación, añada un repositorio remoto con el
comando git remote. En su caso, en lugar de cursophpmedio aparecerá el nombre de usuario que haya indicado al
darse de alta en la plataforma y la ruta que haya escogido también en ese momento.

$ git remote add origin [Link]

Ese comando está añadiendo (add) a nuestro repositorio un enlace a un repositorio remoto con esa URL y con el
nombre origin. Puede añadir tantos repositorios remotos como desee con los nombre y rutas que desee, incluso
repositorios en el mismo sistema, en otros ordenadores en la red local, etc.
Despúes de añadir ese repositorio remoto, puede ver la lista de repositorios con el comando git remote -v:

$ git remote -v
origin [Link] (fetch)
origin [Link] (push)

26
Curso PHP Medio Escuela de Administración Pública

Estas líneas nos indican que tenemos un enlace a ese repositorio remoto. El que aparezca dos veces hace
referencia a qué repositorio accedemos cuando traemos los cambios a nuestro repositorio ( fetch) y a qué repositorio
remoto proporciona ( push) nuestro repositorio sus cambios.
El siguiente paso a seguir es el de subir todos nuestros cambios al repositorio remoto. Para ello ejecutamos el
comando siguiente:

$ git push origin master


Password for '[Link]
Counting objects: 31, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (21/21), done.
Writing objects: 100% (31/31), 3.62 KiB | 0 bytes/s, done.
Total 31 (delta 13), reused 19 (delta 8)
To [Link]
* [new branch] master -> master

Con esta instrucción indicamos que queremos llevar nuestros cambios (push) al repositorio con el nombre origin
desde la rama master. Antes de realizar la subida y mezcla en la plataforma solicita la contraseña de usuario que
utilizó para darse de alta en Bitbucket. Finalmente muestra información sobre las acciones que lleva a cabo en el
repositorio remoto. La última de esas acciones es la de crear la rama master como una nueva rama.
Si accede de nuevo a la página del repositorio Recetas en Bitbucket ya muestra información normal de un
repositorio git:

Puede ver en el resumen del proyecto los commits realizados así como la información del README
directamente.
Al trabajar en equipo, si en un mismo repositorio hacemos varios pushes es posible que se produzcan conflictos.
Bitbucket informará inmediatamente de esas situaciones e incluso permitirá resolverlos desde la misma página web.
Pero una de las estrategias más útiles es la de obtener los cambios que existen en el repositorio remoto antes de
hacer cualquier subida. De esa forma, si existen conflictos con su código, aparecerán en su sistema local y podrá
resolverlos antes de subir los suyos, reduciendo drásticamente que se produzcan más conflictos.
Para obtener los cambios del repositorio se utiliza el comando git pull:

$ git pull origin master

Existen más estrategias, como la de que una persona sea la encargada de mezclar los cambios de varios
repositorios remotos, uno por cada desarrollador, en uno central y, de camino, sea el responsable de resolver los
conflictos.

27
Curso PHP Medio Escuela de Administración Pública

En proyectos de software libre, con cientos e incluso miles de desarrolladores, la estrategia es la de aceptar cada
subida como un pull request, de forma que a criterio de la persona responsable, esa petición sea aprobada o
denegada.

28

También podría gustarte