Introducción a Git y Control de Versiones
Introducción a Git y Control de Versiones
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
Curso PHP Medio Escuela de Administración Pública
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.
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.
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.
3
Curso PHP Medio Escuela de Administración Pública
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:
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.
Y para Windows:
$ 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";
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:
Más adelante veremos qué significan y por qué usamos estos dos comandos para incluir nuestros cambios en el
repositorio.
$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.
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.
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.
Separando la preparación de la confirmación tiene la habilidad de ajustar fácilmente lo que va en cada commit.
7
Curso PHP Medio Escuela de Administración Pública
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:
$ git status
On branch master
nothing to commit, working directory clean
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>
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: [Link]
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 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).
1.3.9. Histórico
Para ver la lista de cambios que se han registrado en el repositorio utilizamos el comando:
$ git log
Incluido un comentario
commit e0c1026a59ae2ec9656d3f81a396f2ea10ccc9ca
Author: [Link] <[Link]@[Link]>
Date: Thu Jun 9 11:45:08 2017 +0100
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
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]:
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
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>
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].
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:
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!
$ 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”.
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:
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:
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 tag
v1
v1-beta
También es posible ver información de la etiqueta desde el histórico o log. Pruebe el siguiente comando:
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).
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";
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>
15
Curso PHP Medio Escuela de Administración Pública
$ 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:
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.
modificado: [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:
Ahora nuestro directorio de trabajo está limpio de nuevo. Vamos a etiquetar esta nueva version como v2:
$ git tag v2
Para deshacer el cambio confirmado necesitamos generar un commit, que se realiza como resultado del siguiente
comando:
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:
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
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.
$ 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.
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 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
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.
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.
<?php
$servidor = "localhost";
$usuario = "root";
$pass = "root";
$base_datos = "recetas";
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.
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:
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.
$ git status
On branch receta
nothing to commit, working tree clean
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";
21
Curso PHP Medio Escuela de Administración Pública
Ahora es necesario modificar el fichero [Link]. Elimine la parte que hemos trasladado a [Link] y
confirme ese cambio:
Finalmente incluya la conexión desde el archivo [Link] con el siguiente código al principio del fichero:
<?php require_once '[Link]';?>
<!DOCTYPE html>
...
Ahora tenemos una nueva rama llamada receta con tres nuevos commits en ella.
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:
22
Curso PHP Medio Escuela de Administración Pública
En este momento tenemos dos ramas divergentes en el repositorio. Utilice el siguiente comando para ver las
ramas y sus divergencias:
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.
23
Curso PHP Medio Escuela de Administración Pública
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?
…
// 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:
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.
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";
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.
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:
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.
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:
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:
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