Haciendo un deploy con Git para una webApp

En ocasiones los clientes FTP suelen ser lentos conforme nuestras estructuras de archivos se vuelven complejas, por otra parte suele ser algo incomodo para un desarrollador estar saliendoce de entorno de lineas de comandos (CLI) para realza esta tarea.

El siguiente POST describe un mecanismo simple para realizar esta tarea utilizando, Git y una conexión SSH de un servidor Linux.

Consideraciones:

  1. Se considera que el lector cuenta con conocimientos básicos de Git, así como del manejo del CLI en entornos *nix.
  2. También que ya se cuenta con algún repositorio que contiene tu aplicación web, en este caso la describo como si estuviera en una carpeta con nombre app.
  3. Se cuenta con una cuenta de acceso SSH para el usuario user_x, en el servidor my.server.
  4. Para referirme a la carpeta destino en el servidor usaré /full_path/htdocs/

Creando la carpeta del repositorio remoto

Para crear esto necesitamos realizar un clone local con la opción --bare, esto sería con la siguiente instrucción:

git clone --bare app app.git

Esto hace que Git clone el repositorio app la opción --bare crea un directorio simple(bare), esto significa que no contendrá los archivos del repositorio, en cambio  contendrá los metadatos que Git requiere para trabajar, sí observamos el contenido de la carpeta resultante (/app.git) tendrá una estructura similar a:

app.git/
	|-- HEAD
	|-- config
	|-- description
	|-- hooks
	|-- info
	|-- objects q q
	|-- packed-refs
	`-- refs

	4 directories, 4 files

Para mayor info ver: https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-init.html

🔗 Creando el gancho al recibir cambios.

Git tiene con un mecanismo de ganchos (hooks), estos son scripts que están enganchados a diversos eventos, de tal forma que ¡son disparados 🔫 cuando dicho evento sucede!.

Para ligar un script a un evento de Git basta con crear el archivo con el nombre adecuado en la carpeta de hooks, esta carpeta generalmente ya contiene algunos ejemplos como se muestra a continuación:

app.git/hooks/
	|-- applypatch-msg.sample
	|-- commit-msg.sample
	|-- fsmonitor-watchman.sample
	|-- post-update.sample
	|-- pre-applypatch.sample
	|-- pre-commit.sample
	|-- pre-push.sample
	|-- pre-rebase.sample
	|-- pre-receive.sample
	|-- prepare-commit-msg.sample
	`-- update.sample

	0 directories, 11 files

Vemos que el sistema nos creó 11 ejemplos los cuales si les quitamos el sub-fijo .sample y los hacemos ejecutable (chmod u+x) estarán ligados al evento descrito por su nombre.

Lamentablemente en este caso no creó el ejemplo para el evento post-recibir por lo cual lo tenemos que crear manualmente:

touch app.git/hooks/post-receive

Respecto al contenido agregamos el siguiente código el cual está basado del siguiente ejemplo:

#!/bin/bash
#Carpeta de mi respotorio git
GIT_DIR="/full_path/htdocs/app.git"
#Carpeta destino de mi aplicación web
DST_DIR="/full_path/htdocs/web-app"
BRANCH="master"

while read oldrev newrev ref
do
	# Revisa que el $ref sea igual al $BRANCH a observar
	if [[ $ref = refs/heads/$BRANCH ]];
	then
		echo "Referencia recibida $ref: ";
		echo "Deployando la rama ${BRANCH} En el servidor."
		git --work-tree=$DST_DIR --git-dir=$GIT_DIR checkout -f
	else
		echo "Referencia recibida $ref. No se hizo algo: ";
		echo "Solo la rama ${BRANCH} puede deployar el servidor."
	fi
done

Como podemos ver el script cuenta con algunas variables p.e. BRANCH que permite definir el brazo a observar por defecto master.

⬆ Subiendo el repositorio en el servidor:

Una vez agregado el hook ya tenemos el repositorio listo (app.git) para subirlo a nuestro servidor:

scp -rp app.git user_x@my.server:/full_path/htdocs/

Nota: Este proceso puede tardar varios minutos dependiendo del tamaño de tu proyecto y la velocidad de tu conexión.

Lo siguiente que tenemos que hacer será conectarse al servidor mediante SSH para darle los permisos de ejecución (para el usuario) al script del hook post-receive:

# Ingresamos
ssh user_x@my.server
# Al conectarnos por defecto nos conecta en nuestra carpeta htdocs
# Damos permisos solo al usuario (`u`) de ejecución (`+x`).
chmod u+x app.git/hooks/post-receive

🔗 Vincular el repositorio con el servidor remoto.

Los repositorios Git pueden tener uno o varias fuentes remotas, estas son básicamente lugares en donde se enviar el código(push) y donde se puede obtener(fetch/pull).

Forma 1 (Agregando nuevo remoto):

Si ya tienes el proyecto clonado previamente de algun servidor (p.e. github), lo recomendable seria agregar una nueva fuente remota p.e. webserver:

git remote add webserver \
ssh://user_x@my.server:/full_path/htdocs/app.git

Forma 2 (clonando el proyecto):

Puedes clonar el proyecto del servidor, en este caso la fuente remota de origen origin sera el servidor:

git clone 
ssh://user_x@my.server:/full_path/htdocs/app.git

Mayor info: https://git-scm.com/book/es/v2/Fundamentos-de-Git-Trabajar-con-Remotos

☑ Deployando mis cambios en el Servidor:

Para desplegar nuestros cambios, solo es necesario hacer un push en el remoto que apunte a nuestro servidor web (en este caso webserver ) sobre la rama master (o la que hayas elegido):

git commit -am 'Se hizo algún cambio....'
git push -u webserver master

¡¡¡Listo!!!

 

Archivos fuentes

El contenido de este post así como el código fuente del script esta disponible en un gist que hice en github.com:

https://gist.github.com/fitorec/b100aebff4df20890a53dc4e971a91c0

Siéntete con la libertad de hacer lo que gustes con él, si tienes alguna idea o algún cambio que quisieras aportar favor de dejármela en los comentarios =)

Agregando y Eliminando rama remota con git

En ocasiones puede ser útil compartir una rama temporal en nuestro repositorio, por ejemplo imaginemos que por alguna razón tenemos que compartir algún brazo de prueba, el cual sera una copia del master pero con algunos pequeños cambios:

# Agregamos un nuevo brazo y nos brincamos a el al mismo tiempo
git checkout -b brazo-prueba
# Editamos algunos archivos
vim algun_archivo_test.php
# Agregamos nuestra confirmación respectiva.
git commit -am 'Haciendo nuestras pruebas'
# Compartiendo nuestra rama brazo-prueba
git push -u origin brazo-prueba

Una vez que compartimos nuestra prueba, podemos quizás hacer una combinación hacia nuestra rama maestra (ó alguna otra organización en nuestro repositorio), en fin el caso es que si por alguna razón la rama brazo-prueba ya no es necesaria la podemos eliminar del repositorio remoto de la siguiente manera:

git push origin --delete brazo-prueba

Conocer la lista de los archivos modificados en confirmaciones previas con git

En ocasiones necesitamos saber cuales son los archivos modificados en nuestras confirmaciones realizadas con git. ¿No se?, se me ocurre por ejemplo si deseo obtener esta lista para saber que archivos tengo que revisar ó cuales tengo que actualizar en algún servidor por poner algunos ejemplos.

Lista de archivos modificados en n confirmaciones previas El ejemplo mas simple

Por ejemplo si el día de hoy realice 3 confirmaciones, al final del día me gustaría obtener la lista del total de archivos modificados. Esto lo podemos hacer con el comando git-log, veamos este ejemplo:

# Archivos modificados hace 3 confirmaciones.
 git log -3 --name-only --pretty=format:''

Esto lo podemos ocupar para n confirmaciones previas, si sustituimos el -3 por el número de confirmaciones de las que interesan obtener la lista de sus archivos.

Lista de archivos modificados un un intervalo de tiempo definiendo un limite en tiempo

Quizás no recordemos exactamente cuantas confirmaciones hemos realizado un algun tiempo determinado, por ejemplo ¿que pasaría si nos interesa obtener es la lista de los archivos modificados hace 3 semanas al día de hoy?, no podríamos obtener esta lista con la instrucción anterior(ya que de momento no sabemos cuantas confirmaciones se han realizado).

Nos podemos ver tentados en realizar alguna búsqueda con el comando find partiendo de las fechas de modificación(ocupando el parámetro -mtime) de los archivos de nuestro repositorio, lo cual seguramente nos mostrara archivos propios del git que han sido modificados.

Por otra parte el  git-log nos proporciona parámetros(--before, --after, --since… ) para visualizar la bitacola en función del tiempo, veamos como seria esto con algunos ejemplos:

# Buscando archivos modificados hace 3 semanas(21 días) con el comando find
# Ojo: esta opción se requeriría filtrar para quitar los archivos del git
 find .  -mtime -21 -print 

# Archivos modificados después de hace 3 semanas, hasta antes al día de hoy :
 git log --before={today} --after={3.weeks.ago} --name-only --pretty=format:''

# Archivos modificados después de hace 2 días, hasta este momento :
 git log --before={now} --after={2.days.ago} --name-only --pretty=format:''

# Archivos modificados después de hace 2 días, hasta este momento
# Notar que es lo mismo que el ejemplo anterior sólo que son la opción "--since" :
 git log --since={2.weeks.ago} --name-only --pretty=format:'' | sort -u

Filtrando la lista poniéndonos creativos

En la lista puede que algunos archivos se repitan mas de una vez(ya que quizás fue modificado en varias confirmaciones),para esto una solución podría ser filtrar la lista para asegurar que los archivos no se repitan, para esto podemos ocupar el comando sort con la opción de único (-u esto con una tubería |), veamos como seria este filtro:

# Archivos modificados después de hace 3 semanas, hasta antes al día de hoy
git log --since={1.year.ago} --name-only --pretty=format:'' \
| sort -u

O quizás nos interesa obtener solo la lista de los archivos con alguna extensión(es), por ejemplo si nos interesa saber que archivos he modificado hace 3 semanas y que tienen la extensión php, css ó js. Para esto podemos hacer un filtro un poco mas detallado con el comando grep:

# Archivos modificados desde de hace 3 semanas y que ademas
# cumple que son archivos con la extensión: .php, .css ó js :
git log --since={3.weeks.ago} --name-only --pretty=format:'' \
| sort -u | grep -E '\.(php|css|js)$'

En general nos podemos poner mas curiosos de acuerdo a nuestras necesidades.

Mayor información: