Leer XML con namspaces fácil en PHP

Introducción

Cuando manipulamos documentos XML [1] desde PHP [2] uno de los “quebraderos” de cabeza son los namespaces. Un namespace no es nada complicado ni rocambolesco como algunos opinan; no deja de ser un enriquecimiento semántico para dotar de más información a un documento XML.

Tradicionalmente los desarrolaldores PHP no se han complicado con este concepto. Pero hoy en día con la cantidad de mensajes y documentos XML que envían mediante REST, SOAP, APIs de terceros, etc. es inevitable y totalmente recomendable conocer como manipularlos de forma sencilla en PHP.

Caso de uso: Google shopping

Por lo general cualquier documento XML generado por y para Google tendrá en namespace http://base.google.com/ns/1.0, que simplemente añade algo de información adicional al documento XML (descripciones, items, ….) [4].

Cómo ejemplo vamos a manipular un documento para el servicio Google Shopping [3].

<?xml version="1.0"?>

<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
    <channel>
        <title>El nombre de tu feed de datos</title>
        <link>http://www.example.com</link>
        <description>Una descripción de tu contenido</description>
        <item>
            <title>Suéter de lana rojo</title>
            <link> http://www.example.com/página-información-producto1.html</link>
            <description>Suéter suave y cómodo que te abrigará en las frías noches de                         
            invierno</description>
            <g:image_link>http://www.example.com/imagen1.jpg</g:image_link>
            <g:price>25</g:price>
            <g:condition>nuevo</g:condition>
            <g:id>1a</g:id>
        </item>
    </channel>
</rss>

Si leyéramos este documento directamente con SimpleXML no entendería los namespaces ni sus elementos, quedan este documento:

<?xml version="1.0"?>

<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
    <channel>
        <title>El nombre de tu feed de datos</title>
        <link>http://www.example.com</link>
        <description>Una descripción de tu contenido</description>
        <item>
            <title>Suéter de lana rojo</title>
            <link> http://www.example.com/página-información-producto1.html</link>
            <description>Suéter suave y cómodo que te abrigará en las frías noches de                         
            invierno</description>

        </item>
    </channel>
</rss>

¿Cómo solucionarlo? Un ejemplo tonto sería la siguiente función que dado un elemento de un documento XML con SimpleXML busca los elementos del namespace http://base.google.com/ns/1.0. Obtenidos los elementos de este namespace en ese nodo, sólo debemos recoger la propiedad deseada (precio).

function xml_get_price(SimpleXMLElement $item)
{
    $googleSpace  = $item->children('http://base.google.com/ns/1.0');
    return $googleSpace->price; // para el ejemplo anterior: 25
}

¡Fin! Espero que sea útil.

Referencias

  1. XML 1.0 (w3c): http://www.w3.org/TR/REC-xml/
  2. PHP SimpleXML: http://php.net//manual/es/book.simplexml.php
  3. Google Shopping: https://www.google.es/shopping
  4. Google Merchants Expecificacion RSS 2.0: https://support.google.com/merchants/answer/160589?hl=es

SQL para sistema de reservas

Introducción

En un proyecto reciente he tenido que preparar un sistema de reservas para un hotel. La idea es sencilla poder reservar recursos (en este caso habitaciones) entre unas fechas determinadas.

Pero además, como es un hotel se da una condición especial. La fecha de inicio y de fin no son cerradas, quiero decir que una reserva puede terminar el mismo día que otra empieza y viceversa. Por todos es sabido, que normalmente en un hotel la hora de salida es hasta las 12:00am y la hora de entrada es a partir de las 14:00pm.

¿Cómo resolverlo? Sencillo,veamoslo.

Solución

Primero suponemos un esquema tan sencillo como el siguiente:

CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;

CREATE TABLE IF NOT EXISTS `mydb`.`habitaciones` (
  `numero` INT(11) NOT NULL,
  `nombre` VARCHAR(45) NULL DEFAULT NULL,
  `camas` INT(11) NULL DEFAULT NULL,
  `camagrande` TINYINT(1) NULL DEFAULT NULL,
  `disponible` TINYINT(1) NULL DEFAULT NULL,
  PRIMARY KEY (`numero`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci;

CREATE TABLE IF NOT EXISTS `mydb`.`reservas` (
  `reserva_id` INT(11) NOT NULL AUTO_INCREMENT,
  `habitaciones_numero` INT(11) NOT NULL,
  `entrada` DATE NULL DEFAULT NULL,
  `salida` DATE NULL DEFAULT NULL,
  `nombrecliente` VARCHAR(45) NULL DEFAULT NULL,
  `telefono` VARCHAR(45) NULL DEFAULT NULL,
  PRIMARY KEY (`reserva_id`),
  INDEX `fk_reservas_habitaciones_idx` (`habitaciones_numero` ASC),
  CONSTRAINT `fk_reservas_habitaciones`
    FOREIGN KEY (`habitaciones_numero`)
    REFERENCES `mydb`.`habitaciones` (`numero`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci;

El siguiente paso paso sería crear algún dato. Una vez hecho esto, podemos considerar muchos casos posbles, buscando en Internet seguro que hay muchas aproximaciones pero la solución final que yo he encontrado y funciona perfectamente para mi caso es la siguiente:

set @dstart = date_add('2014-03-15', interval 1 day);
set @dend   = date_sub('2014-04-01', interval 1 day);
select id, vivienda_id, arrival_date, departure_date, date_add(@dstart, interval 1 day) firstday, date_sub(@dend, interval 1 day) lastday
from espana_reservations r
where (arrival_date between @dstart and @dend)
   or (@dstart between arrival_date and departure_date)

Espero que haya sido de ayuda!

Referencias

Parametrizar consulta en MySQL usando @variables

Introducción

Hace poco en un proyecto personal he empezado a usar variables en mis consultas SQL para probarlas en mi cliente HeidiSQL. De esto modo puedo verificar el funcionamiento de las mismas como las construye mi framewoork codeigniter.

Por poner un ejemplo, en PHP plano se escribiría algo así:

$select = 'select * from cosas where precio > ', ($miprecio + $parametro) ' and precio < ', ($miprecio * 10) ;.

Pero claro, lo ideal es poder usar en MySQL una construcción con el mismo aspecto, ¿cómo? Usando las variables que nos ofrece en SQL.

Ejemplos

Supongamos una tabla de viviendas con su id, nombre y precio de mercado como la siguiente:

select id, nombre, precio_de_venta from kaza_viviendas
id nombre precio_de_venta
12 Villa Atlas 1470000
10 Villa Chronos 1350000
11 Villa Hermes 780000
6 Villa Marfil 1300000
8 Villa Eos 850000
9 Villa Pegasus 670000

Si queremos el precio más bonito y usando otro nombre:

select id, nombre, format(precio_de_venta, 2) as precio from viviendas 
id nombre precio
12 Villa Atlas 1,470,000.00
10 Villa Chronos 1,350,000.00
11 Villa Hermes 780,000.00
6 Villa Marfil 1,300,000.00
8 Villa Eos 850,000.00
9 Villa Pegasus 670,000.00

A continuación, vamos a crear dos parámetros “horquilla” y “precio_referencia”. El primero establece un límite sobre el que buscar precio “similares” al dado por “precio_referencia”:

set @precio_referencia=1470000;
set @horquilla=25000;
select id, nombre, format(precio_de_venta, 2) as recio
from viviendas
where precio_de_venta >= (@precio_referencia - @horquilla)
  and precio_de_venta <= (@precio_referencia + @horquilla);

Como vemos sólo nos devuelve una. Pero para generar y probar una lista de viviendas similares con este u otro criterio resulta muy útil y rápido

id nombre recio
12 Villa Atlas 1,470,000.00

Estos ejemplos son muy sencillo y tontos, pero creo que ilustran a grandes rasgos lo que quiero decir, además estoy seguro que para construir consultas más complejos con mayor cantidad de cruzas y condiciones podría ser de gran ayuda.

Conclusión

En desarrollo personalmente no me gusta usar variables de MySQL, aunque con ejemplos como el anterior si que veo muy claro lo que facilita la depuración del SQL y ayuda a la hora de construir consultas muy complejas con muchos datos cruzas y poder probar diferentes casos.

Desinstalar el plugin Subeclipse (svn) de Eclipse/Aptana Studio 3

Hace unos días, instalé el pluigin subeclipse para integrar SVN en Aptana Studio. Después de probarlo quedé contrariado al detectar que tiene un problema con el sistema de claves de gnome y no hacía más que darme problemas. Decidí seguir usando svn en consola y desinstalarlo. ¿Pero cómo hacerlo definitivo?

$ cd APTANA_INSTALL_DIR/plugins
$ ls |grep org.tigris.subversion
org.tigris.subversion.clientadapter_1.6.12.jar org.tigris.subversion.subclipse.doc_1.3.0.jar org.tigris.subversion.subclipse.tools.usage_1.0.1.jar
org.tigris.subversion.clientadapter.javahl_1.6.15.jar org.tigris.subversion.subclipse.graph_1.0.9.jar org.tigris.subversion.subclipse.ui_1.6.17.jar
org.tigris.subversion.subclipse.core_1.6.17.jar org.tigris.subversion.subclipse.mylyn_3.0.0.jar
$ ls |grep org.tigris.subversion|xargs rm

Solucionada, reiniciamos Aptana Studio y todo ok.

Referencias

  • Eclipse: http://www.eclipse.org/
  • Aptana Studio: http://www.aptana.com/
  • Subeclipse: http://subclipse.tigris.org/

Desactivar Javascript en Firefox

Hace poco tuve que realizar unas pruebas en un proyecto y necesitaba desactivar el javascript para hacer unas comprobaciones. ¿Cómo hacer esto en Firefox?

Muy fácil, en la barra de direcciones escribimos “about:config”, nos preguntará el navegador si de verdad queremos acceder. Le respondemos que sí. Ahora estamos en el núcleo de la configuración de firefox, debemos llevar cuidado.

Buscamos la clave “javascript.enabled”. La ponemos a FALSE e voilá! El navegador no interpretará Javascript.

Configurar un multihost con apache2 y en Debian/ubuntu [ACTUALIZADO]

Introducción

Como desarrollador Web en alguna ocasión he tenido que realizar algún proyecto sin disponibilidad de tener un servidor de desarrollo. Hasta este punto, existen tres opciones si queremos trabajar con un servidor de desarrollo en lugar de usar un WAMP o un XAMPP (que son cómodos pero poco profesionales).

  • Contratar un multihost a algún proveedor de servicios de hosting
  • Instalar una máquina servidor configurandola con multihost y su propio DNS, etc.
  • Instalar un servidor LAMP con multihost en el equipo de trabajo

En esta entrada me voy a decantar por esta última opción por comodidad y rapidez. Pero hay que tener en cuenta que esta solución sólo servirá para tener un entorno multihost para uno mismo, si se trabaja en grupo en un red no será un sistema válido.

Instalando apache2, php5, mysql5 … (lamp)

Lo primero, es instalar un sistema LAMP (Linux, Apache, Mysql, PHP). Esto en un sistema Debian/Ubuntu es tan sencillo cómo ejecutar en consola:

$ sudo apt-get install apache2 apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common libaprutil1-dbd-sqlite3 libaprutil1-ldap libhtml-template-perl mysql-server mysql-server-5.5 mysql-server-core-5.5 apache2-mpm-prefork libapache2-mod-php5 libtidy-0.99-0 php5 php5-cli php5-common php5-curl php5-gd php5-mysql php5-odbc php5-sqlite php5-tidy php5-xdebug php5-xmlrpc libapache2-mod-auth-mysql libphp-jpgraph dbconfig-common libmcrypt4 php-doc php5-mcrypt phpmyadmin

A continuación, como sana costumbre recomiendo cambiar la clave de root de MySQL.

mysql -u root
mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('yourpassword');

Y por último, si hemos instalado PHP, editar el fichero /etc/php5/apache2/php.ini y habilitar el uso de mysql, en la línea:

;extension=mysql.so

Cambiadla por: 

1extension=mysql.so

Un poco de DNS

Apache2 se configura de modo que se le indica al servidor en que interfaces de red y puertos debe funcionar. Tomemos la imagen siguiente:

Disponemos de varios nombres de dominio (reales o ficticios) y deseamos que apunten a la misma máquina, pero claro, no queremos que apache nos facilite las mismas Webs para cada uno, sino que sean proyectos diferentes (multihost), para ello debemos indicar el sistema DNS que esos nombres apuntan a la IP del servidor de trabajo.

Si estuviéramos en un entorno real y profesional, tendríamos un servidor DNS y un servidor LAMP dedicado con una IP W.X.Y.Z, e indicaríamos al servidor DNS que cada dominio apunte al servidor con IP W.X.Y.Z. Como estamos probando en un servidor “monopuesto” no necesitamos configurar ningún servidor DNS, sólo debemos editar el fichero /etc/hosts. Este fichero es una reminiscencia del origen de Internet y contiene parejas del tipo (nombre, ip).

De modo que si queremos añadir el dominio de prueba “midominio”, sólo debemos añadir al final del fichero /etc/hosts la sighuiente línea:

127.0.0.1    midominio

Una vez hecho esto, nuestro equipo sabe que la IP del dominio midominio es 127.0.0.1. Pero, sólo nuestro equipo, este fichero es local al equipo dónde lo hemos editado de ahí que este sistema sólo nos sirva para el equipo de trabajo no para trabajar en equipo.

Sistema multihost en apache2

Y por fin, vamos a ver los pasos para configurar un sistema multihost en nuestro apache2. Supongamos que los DocumentRoot de los diferentes dominios estan en la carpeta /home/usuario/www, debemos seguir estos pasos:

  1. Añadir el usuario al grupo WWW-DATA de apache2: Para que apache pueda leer/escribir sin problemas en sus carpetas (Cambiad USUARIO por vuestro usuario)
    $ sudo usermod -G www-data USUARIO
  2. Poner los permisos 775 para directorios y 664 para ficheros: Por lo mismo que en el apartado anterior ($PWD se evalúa como el directorio actual, se puede indicar el directorio correspondiente).
    $ find $PWD -type d -print -exec chmod 775 {} \;
    $ find $PWD -type f -print -exec chmod 664 {} \;
  3. Cambiar los permisos del directorio del vhost:
    $ sudo chown -R USUARIO:www-data *
  4. Edita el fichero del virtual host:
    
    <VirtualHost *:80>
    	ServerAdmin	info@miemail.com
    	Servername	midominio
    	DocumentRoot	/home/usuario/www/midominio
    	LogLevel	warn
    	ErrorLog 	${APACHE_LOG_DIR}/midominio_error.log
    	CustomLog	${APACHE_LOG_DIR}/midominio_access.log combined
    	<Directory />
    		Options FollowSymLinks
    		AllowOverride None
    	</Directory>
    	<Directory /home/usuario/www/midominio>
    		Options Indexes FollowSymLinks MultiViews
    		AllowOverride All
    		Order allow,deny
    		allow from all
    	</Directory>
    </VirtualHost>

    Debemos tener cuidado con lo siguiente, en Debian/Ubuntu la configuración inicial de apache2 desactiva el uso del fichero .htaccess. Para habilitarlo debemos ser cuidadods de poner la directiva AllowOverride All como en el ejemplo anterior.

    Novedad: En versiones recientes de apache está configuración puede no ser suficiente y debemos añadir alguna directiva adicional, para no encontrartos un error HTTP 403 Forbbiden. De modo que en la configuración del directorio con el DOCUMENT ROOT debemos a Require all granted, quedando algo así

    :

    <Directory "your directory here">
       Order allow,deny
       Allow from all
       # New directive needed in Apache 2.4.3: 
       Require all granted
    
    

    Tal y como podemos leer en Stack Overflow.

  5. Activar el mod_rewrite:
    $ sudo a2enmod rewrite
    $ sudo service apache2 restart
  6. Accede a http://midominio

Suerte con vuestros servidores LAMP!

Referencias

  1. DNS en Wikipedia: http://en.wikipedia.org/wiki/Domain_Name_System
  2. Virtual Host: http://httpd.apache.org/docs/2.2/vhosts/
  3. Ejemplos: http://httpd.apache.org/docs/2.2/vhosts/examples.html

Corregir: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName

Problema arrancando apache con Server’s fully qualified domain name

Hace poco, he tenido un pequeño “problema” instalando un servidor web apache2 y quería resolver cómo lo he solucionado. Trans instalar apache2 al realizar cualquier operación de administrador obtengo este mensaje:

* Starting web server apache2
apache2: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName

Tranquilidad, no ocurre nada. Sólo que apache no sabe que nombre (DNS) tiene el servidor y por defecto emplea la IP de loopback (127.0.0.1). esto es así porqué httpd.conf está vacío, una solución sería añadir la cadenaServerName, pero con la nueva estructura de directorios de Apache2 disponemos de la siguiente opción:

sudo sh -c 'echo "ServerName localhost" >> /etc/apache2/conf.d/name' && sudo service apache2 restart

Con lo cual queda asignado este nombre y solucionado el problema.

Usando CURL para depurar mensajes HTTP

Introducción

Todo desarrollador WEB que se precie sabe que debe conocer (sino dominar) el protocolo de comunicación HTTP. Sobre este protocolo se basan todas las comunicaciones en la WEB (esto no es cierto del todo ;_)).

En proyectos anteriores he tenido que realizar varías consultas y envío de datos a través del API de Google usando productos como Contacts, Calendar, etc.

Ahora no voy a explicar cómo funciona el protocolo OAtuh [1], pero si diré que es el mecanismo que usa Google para permitir el acceso a sus APIs de forma segura.

Trabajar con este protocolo y manejar mensajes entre mi aplicación y los distintos servidores de Google ha requerido una depuración muy estricta a nivel HTTP y la mejor herramienta que he podido usar es CURL.

La mágia de CURL

Curl [2], es una herramienta muy conocida entre los administradores de sistemas y muy extendida entre los programadores de PHP.

No quiero perderme en detalles, pero vamos ver un ejemplo donde se realiza una petición a un script PHP que contiene el código:

Este código realiza una redirección a http://www.google.com, pero la pregunta es: Entre mi navegador Web y el servidor, ¿qué mensajes HTTP se transmiten? Si utilizamos la opción -v (verbose) podemos ver los mensajes de información del programa (precedidos por *), los mensajes que se envían al servidor (>) y los mensajes que se reciben del servidor (<).

$ curl -v http://webserver/header_location.php
* About to connect() to webserver port 80 (#0)
* Trying 172.x.y.z... connected
* Connected to webserver (172.x.y.z) port 80 (#0)
> GET /header_location.php HTTP/1.1
> User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1
> Host: webserver
> Accept: */*
>
< HTTP/1.1 302 Found
< Date: Mon, 04 Nov 2013 17:07:30 GMT
< Server: Apache/2.2.8 (Ubuntu) DAV/2 SVN/1.4.6 PHP/5.2.4-2ubuntu5.27 with Suhosin-Patch mod_ssl/2.2.8 OpenSSL/0.9.8g
< X-Powered-By: PHP/5.2.4-2ubuntu5.27
< Location: http://www.google.com/
< Content-Length: 0
< Content-Type: text/html
<
* Connection #0 to host webserver left intact
* Closing connection #0

Bueno, ahora sabemos que este script/página nos envía a google, pero … ¿se puede automatizar el proceso para ver todos los mensajes HTTP hasta que se sirve la página WEB? Sí, usando la opción -L.

Usando un comando cómo:

$ curl -v -L http://webserver/header_location.php

Referencias

  1. Oauth: http://es.wikipedia.org/wiki/OAuth
  2. CURL Homepage: http://curl.haxx.se/

GIT: Repositorios remotos y desarrollo distribuido

Introducción

Hace una semana publiqué una entrada introduciendo el sistema de control de versiones GIT. Ayer añadí otra entrada donde dí unos primeros pasos a git. Hoy después de unas horas de trabajo y recopilar ejemplos basados en mi trabajo diario ha llegado el momento de escribir sobre los repositorio remotos.

Repositorios remotos

Veamos un caso imaginario muy útil. ¿Cual es nuestro escenario?

  • Trabajamos 2+ desarrolladores en un proyecto común.
  • Disponemos de un equipo de trabajo donde día a día actualizamos un repositorio GIT local (a nuestro equipo) para controlar la evolución de nuestro trabajo.
  • Tenemos algún colega/compañero que trabaja desde su casa y también tiene su equipo donde controla su trabajo diario con su instalación local de GIT.
  • Además, cabe la posibilidad que nosotros mismos tengamos en casa otro equipo desde el cual podemos trabajar otras horitas en casa.
La primera pregunta, ¿cómo organizar este lío de tantas personas trabajando en lo mismo sin que haya peligro de sobrescribir uno el trabajo del otro?
Escenario de ejemplo: Repositorios GIT remotos y varios desarolladores
Figura 1: Escenario de ejemplo. Repositorios GIT remotos y varios desarolladores

Bueno, pues ya que hablamos de control de versiones lo primero que entra en juego es un servidor donde crear un/unos repositorio/s GIT donde cada programador realiza un commit de su trabajo y así el resto de colegas estén al tanto de sus cambios (a parte habría que hablar de ciertas políticas o protocolos de trabajo sobre cómo repartir el trabajo pero de eso no hablaremos ahora).

Crear el repositorio en el servidor remoto

Vamos a suponer que disponemos de un servidor con nombre repositorios.net. Este servidor está disponible en Internet o en nuestra red local de trabajo (suponemos una máquina Unix). Hemos creado un usuario llamado git cuya carpeta de trabajo en /home/git. Queremos crear el repositorio para el proyecto ejemplo.

git@repositorios.net:~/$ mkdir ejemplo.git
git@repositorios.net:~/ejemplo.git$ git --bare init
Initialized empty Git repository in /home/git/ejemplo.git/

Ya disponemos de un repositorio (contendor) en crudo donde depositar nuestros commits locales o desde donde descargar las actualizaciones del proyecto realizadas por otros usuarios.

Para poder acceder, desde nuestro directorio de trabajo debemos tener un repositorio git (Vamos a suponer una máquina Windows):

$ git init
Initialized empty Git repository in c:/Workspace/proyecto/.git/
$ git add .
$ git -a -m "Inicio proyecto GIT"

31 files changed, 5873 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
create mode 100644 .project
...
Counting objects: 38, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (37/37), done.
Writing objects: 100% (38/38), 82.87 KiB, done.
Total 38 (delta 1), reused 0 (delta 0)
To ssh://git@repositorios.net/home/git/proyecto.git
* [new branch] master > master

Otro usuario, por ejemplo en un equipo Linux, podría crear su copia de repositorio del siguiente modo:

jperez@jperez-debian:~/gitsample$ git init
Initialized empty Git repository in /home/user/gitsample/.git/
jperez@jperez-debian:~/Desktop/borrar/gitsample$ git remote add Matrix ssh://git@central.ovalus.com:101/home/git/sagema.git
jperez@jperez-debian:~/Desktop/borrar/gitsample$ git pull Matrix
git@central.ovalus.com's password:
remote: Counting objects: 38, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 38 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (38/38), done.
From ssh://central.ovalus.com:101/home/git/sagema
* [new branch] master -> Matrix/master
You asked to pull from the remote 'Matrix', but did not specify
a branch. Because this is not the default configured remote
for your current branch, you must specify a branch on the command line.
jperez@jperez-debian:~/Desktop/borrar/gitsample$ git pull Matrix master
git@central.ovalus.com's password:
From ssh://central.ovalus.com:101/home/git/sagema
* branch master -> FETCH_HEAD
jperez@jperez-debian:~/Desktop/borrar/gitsample$ ls
css geo.html google848132b663ce25f4.html index.htm js menu.html responsive robots.txt template.php
jperez@jperez-debian:~/Desktop/borrar/gitsample$ ls -lha
total 76K
drwxr-xr-x 6 jperez jperez 4,0K jun 24 17:05 .
drwxrwxr-x 3 jperez jperez 4,0K jun 24 17:02 ..
drwxr-xr-x 3 jperez jperez 4,0K jun 24 17:05 css
-rw-r--r-- 1 jperez jperez 881 jun 24 17:05 geo.html
drwxr-xr-x 8 jperez jperez 4,0K jun 24 17:05 .git
-rw-r--r-- 1 jperez jperez 46 jun 24 17:05 .gitignore
-rw-r--r-- 1 jperez jperez 53 jun 24 17:05 google848132b663ce25f4.html
-rw-r--r-- 1 jperez jperez 4,1K jun 24 17:05 index.htm
drwxr-xr-x 3 jperez jperez 4,0K jun 24 17:05 js
-rw-r--r-- 1 jperez jperez 8,6K jun 24 17:05 menu.html
-rw-r--r-- 1 jperez jperez 599 jun 24 17:05 .project
drwxr-xr-x 4 jperez jperez 4,0K jun 24 17:05 responsive
-rw-r--r-- 1 jperez jperez 61 jun 24 17:05 robots.txt
-rw-r--r-- 1 jperez jperez 12K jun 24 17:05 template.php
jperez@jperez-debian:~/Desktop/borrar/gitsample$

Apéndice 1: .gitignore

**.gitignore** es un fichero especial para GIT. Se debe situar en la carpeta raíz del repositorio. Contiene los ficheros que no queremos que añada GIT al repositorio (de modo que no serán tenidos en cuenta).

¿Esto es útil? Ya lo creo. Supongamos que trabajamos en un proyecto WEB. Seguramente no querremos añadir los ficheros de imágenes, PDS (photoshop), etc.Si se tratase de un proyecto C++ en Linux seguramente sólo querríamos guardar los ficheros .c y .h. De modo que no querremos guardar los ficheros objeto (.o). En definitiva tratamos de evitar cualquier recurso que no sea código fuente o texto.

Un ejemplo, el caso del proyecto C/C++, no queremos que se tengan en cuenta los ficheros *.o, el directorio tmp (que se usa para almacenar datos temporales de compilación) y otras carpeta que se llama “resources”.

*.o
tmp/
resources/

Considero este tema muy interesante, recomiendo leer la entrada [2].

Referencias

  1. Trabajando con repositorios remotos (Doc oficial de GIT) : http://git-scm.com/book/es/Fundamentos-de-Git-Trabajando-con-repositorios-remotos
  2. Ignorando archivos en GIT: http://es.gitready.com/beginner/2009/01/19/ignoring-files.html

GIT: Guía sencilla para su uso cotidiano

Introducción

Hace unos días publiqué una entrada introduciendo el sistema de control de versiones GIT. Voy a provechar esta entrada para explicar de una forma muy sencilla cómo instalarlo y empezar a trabajar con él.

Instalación en Linux

En Linux es muy sencillo de instalar, desde la propia página WEB nos muestran cómo instalarlo en varias distribuciones:

Distro Comando para su instalación
Debian/Ubuntu
$ apt-get install git 
Fedora
$ yum install git 
Gentoo
$ emerge --ask --verbose dev-vcs/git 
Arch Linux
$ pacman -S git 
FreeBSD
$ cd /usr/ports/devel/git && make install 
Solaris 11 Express
$ pkg install developer/versioning/git 
OpenBSD
$ pkg_add git 

Instalación en Windows

Debemos acceder al apartado de descargas: http://git-scm.com/downloads y obtenerr la versión de Windows. Es un sencillo programa de instalación en modo de asistente (el clásico siguiente-siguiente-siguiente).

Yo recomiendo marcar durante la instalación la opción “Git Bash Here” que nos permite a través del botón derecho del ratón abrir un shell (bash de mingw) en la carpeta que indiquemos. Resulta más cómodo.

Primeros pasos

Supongamos que trabajamos en un proyecto PHP, C u otro lenguaje de programación. Lo primero que hemos de hacer es situarnos en la carpeta raíz del proyecto (Ej: /home/user(projects/gitsample) y crear un repositorio. Si estamos en linux desde el terminal navegamos hasta la carpeta y en Windows con la opción del menú contextual “Git bash here” podemos abrir una consola en esa misma carpeta. Tecleamos los siguientes comandos:

$ git init
$ git add .
$ git commit -m "Estado inicial del proyecto"

¿Qué hemos hecho?

  1. Hemos creado el repositorio (git init, ver carpetas ocultas)
  2. Hemos añadido TODOS los ficheros/carpetas al repositorio (git add .). Es decir, le notificamos que los tenga en cuenta para cualquier cambio.
  3. Realizamos el primer commit del proyecto obteniendo una imagen de su estado inicial (git commit -m MENSAJE)

Conforme trabajemos podemos ir anotando todos los cambios diarios en el proyecto. Por ejemplo del siguiente modo:

$ git add .
$ git commit -a -m "Fecha de hoy: Que cambios hice"

Pero, ¿qué pasa si un día me pongo a trabajar y “me cargo” el proyecto? ¿Cómo lo restablezco todo? ¿Cómo vuelvo a una versión anterior de un fichero? Existen varías formas, pero la más simple es esta (leer la documentación para conocer otros casos y opciones):

$ git reset --hard
$ git reset /directorio/al/fichero/a/recuperar

Este es básicamente el día a día que se lleva a cabo con el control de versiones. En mi caso uso la herramienta gráfica SmartGIT para visualmente consultar todos los diff de los ficheros y como van evolucionando a través de los commit. Si bien es cierto que estos últimos meses trabajo con Aptana Studio y uso directamente algunas de sus herramientas gráficas para manejar GIT.

Proximamente

Otras de las características interesantes de GIT es la posibilidad de trabajar con repositorios distribuidos, ramas y tags. En futuras entradas hablaré de estas funcionalidades.

Referencias

  1. Git sitio WEB oficial: http://git-scm.com/
  2. Manual de referencia de Git :http://git-scm.com/docs
  3. Guía rápida muy útil:http://www.edy.es/dev/docs/git-guia-rapida/
  4. Blog oficial de GIT: http://git-scm.com/blog