¿Es Git/GitHub una buena solución para el despliegue de WordPress?
Actualmente estoy desarrollando WordPress localmente, haciendo commit de mi código a GitHub con Git y luego me conecto por SSH a mi servidor para hacer un "git pull" para actualizar mi código. ¿Es esta una buena opción para el despliegue de código en un sitio WordPress (obviamente tengo acceso root a mi servidor en este caso)? Conozco herramientas como Capistrano, ¿pero sería exagerado usarlo para el despliegue de un sitio WordPress? ¿Cómo puedo aprovechar al máximo Git/GitHub en este caso?

Yo uso git para esto y me parece que funciona muy bien. Algunas sugerencias:
- Añade tu directorio de subidas (wp-content/uploads) a tu archivo
.gitignore
. - Ejecuta un servidor web y un servidor de base de datos en tu sistema de desarrollo para que puedas probar los cambios localmente antes de subirlos a producción.
- Mantén consistentes los ajustes de conexión a la base de datos entre desarrollo y producción, o añade wp-config.php a tu archivo
.gitignore
para evitar que los ajustes de desarrollo de WordPress sobrescriban los de producción. - Evita actualizar plugins en tu sistema de producción usando la interfaz de administración de WordPress, ya que, en el mejor de los casos, tu copia en git sobrescribirá cualquier plugin que actualices tan pronto como hagas push/checkout, y en el peor, tendrás conflictos. Haz las actualizaciones usando la interfaz de administración en tu sistema de desarrollo, haz commit, push y checkout en producción.
Considera añadir un hook
post-receive
de git para hacer checkout de tus actualizaciones automáticamente en el directorio que usas para publicar WordPress a través de tu servidor web (por ejemplo,/var/www
). Esto te permite solo hacer checkout de los archivos en sí, evitando que cualquier metadato de git termine en el directorio raíz de tu servidor web, y también significa que puedes añadir cualquier cambio de permisos en el hook post-receive para que los permisos se mantengan consistentes cada vez. A continuación se incluye un ejemplo:#!/bin/sh unset GIT_INDEX_FILE # el directorio desde donde tu servidor web sirve WordPress export GIT_WORK_TREE=/var/www/example.com/ # el directorio local donde reside tu repositorio git remoto export GIT_DIR=/home/git/repos/example.com.git/ # el usuario de abajo es para Debian - quieres el usuario y grupo que usa tu servidor web sudo git checkout -f sudo chown -R www-data:www-data $GIT_WORK_TREE sudo chmod -R 755 $GIT_WORK_TREE sudo chmod 600 $GIT_WORK_TREE/wp-config.php sudo chmod -R 775 $GIT_WORK_TREE/wp-content

¿Es el acento grave que aparece después de unset GIT_INDEX_FILE
un error tipográfico?

James básicamente ha resumido mi flujo de trabajo, excepto que solo agrego los archivos del tema al repositorio git una vez que tengo el sitio de staging/pruebas/producción establecido.
También recomiendo totalmente usar un hook post-receive en el servidor remoto, evita tener que iniciar sesión y hacer un git pull, etc.

Eso, junto con alias SSH, significa que puedo hacer push al repositorio del tema en vivo usando 'git push live', etc.

No estoy familiarizado con el proceso de actualización de plugins en WordPress, pero ¿qué pasa si la actualización del plugin hace cambios en la base de datos? ¿Cómo se enviarán esos cambios locales al servidor de producción?

@Usuario eso variaría de plugin a plugin. El núcleo de WordPress verifica las versiones del esquema, así que si actualizas WordPress sin usar el actualizador incorporado, hará las actualizaciones de la base de datos por separado. Mi consejo sería que si estás usando cualquier plugin que escriba en la base de datos, revises el área de administración de WordPress, ya que las actualizaciones del esquema usualmente se manejan ahí independientemente de cómo actualices el código del plugin.

Mientras aprendo esto también, he incluido solo mi tema activo y mis plugins personalizados en el repositorio. La pregunta sobre qué pasa cuando un plugin en el sitio se actualiza, pero luego lo sobrescribes con un pull es por qué hago .gitignore a todos los plugins excepto los personalizados. También hago .gitignore a las subidas, porque los archivos multimedia en mi máquina de desarrollo no son necesariamente los mismos que en el servidor de producción. Un problema más grande que quiero mencionar es que GIT no debería ser lo mismo que una copia de seguridad-restauración. Dos operaciones muy diferentes. Git no debería ser tu solución de copia de seguridad-restauración.

Recomendaría encarecidamente configurar Capistrano: requiere un poco de trabajo inicial la primera vez, pero después puedes usarlo fácilmente para nuevas configuraciones.
Las principales ventajas son:
- Poder implementar desde tu escritorio. Puede que no parezca mucho, pero conectarse por SSH a tu servidor remoto y hacer un git pull sigue siendo un fastidio.
- Fácil reversión a una versión anterior si es necesario.
- Capacidad para hacer cosas interesantes como configurar la implementación en entornos de staging/producción.
Estoy añadiendo un conjunto de scripts de Capistrano para mostrarte cómo configuro las cosas.
Capfile
require 'railsless-deploy'
load 'config/deploy'`
deploy.rb
set :stages, %w(production staging local)
set :default_stage, "staging"
require 'capistrano/ext/multistage'
set :application, "" # nombre de tu aplicación - usado para establecer el nombre del directorio
set :scm, :git
set :repository, "" # usa la línea de acceso al repositorio SSH que obtienes del proveedor, ej. git@github.com:nombre/repo.git
set :deploy_to, "/var/www/#{application}" #esta es la carpeta raíz del sitio en el servidor remoto
set :deploy_via, :remote_cache # obtener directamente del repositorio
set :copy_exclude, [".git", ".DS_Store", ".gitignore", ".gitmodules", "wp-config.php"]
# hace que Capistrano solicite la contraseña de sudo u otras entradas remotas
default_run_options[:pty] = true
namespace :tasks do
task :fix_links do
run "ln -nfs #{shared_path}/uploads #{release_path}/wp-content/uploads"
run "ln -nfs #{shared_path}/wp-config.php #{release_path}/wp-config.php"
run "ln -nfs #{shared_path}/blogs.dir #{release_path}/wp-content/blogs.dir"
run "ln -nfs #{shared_path}/.htaccess #{release_path}/.htaccess"
run "sudo chown -R www-data.www-data #{release_path}/"
end
end
after "deploy", "tasks:fix_links"
Y finalmente, un archivo de entorno de ejemplo (si usas la gema multistage, puedes tener uno de estos para cada etapa de tu entorno, ej. local, staging, producción)
config/local.rb
server "", :app #nombre del host
set :branch, 'develop' #elige la rama a implementar
set :use_sudo, false #no uses sudo
set :deploy_to, "/var/www/#{application}" #sobrescribe la ruta predeterminada para implementar
Estos archivos podrían no funcionar sin ajustes, y necesitarás un conocimiento básico de Capistrano, pero espero que ayuden a algunas personas.
Este fue el primer tutorial que usé para empezar con Capistrano y WordPress: http://theme.fm/2011/08/tutorial-deploying-wordpress-with-capistrano-2082/

Si utilizas hooks post-receive de git, eliminan la necesidad de conectarte por ssh al servidor remoto y hacer un git pull

@dirt el problema con el hook post-receive es que, a menos que tengas una buena infraestructura de CI configurada, una fusión incorrecta puede derribar todo tu sitio. La probabilidad de que esto ocurra aumenta si estás trabajando en un proyecto con múltiples desarrolladores que tienen acceso de commit a tu repositorio. Por eso, personalmente, prefiero implementar mediante capistrano, pero entiendo por qué otros podrían no preocuparse tanto por ello.

De hecho, di una presentación en un WordCamp sobre este tema. En lugar de repetirme, aquí hay un screencast de la misma y aquí hay un script de implementación muy simple para acompañar lo que discutí.
En resumen, uso GitHub para alojar el repositorio y utilizo un webhook para implementar los cambios basados en la referencia git. Esto te permite usar el modelo de ramificación git de Vincent Driessen y te abre las puertas para tener servidores web ilimitados, servidores de staging, servidores de pruebas, etc., todos con implementación automatizada. También cubro cómo mantener wp-config.php bajo control de versiones mientras se mantienen versiones separadas para desarrollo y producción (renombrando los archivos y utilizando enlaces simbólicos).

Sé que esta pregunta es un poco antigua, pero como no he visto esta respuesta aquí, me gustaría compartir lo que normalmente hago para configuraciones y despliegues basados en git para sitios individuales, y funciona muy bien, incluso trabajando desde múltiples dispositivos, ubicaciones y con múltiples desarrolladores (todos con sus propios repositorios locales en los que operan, como es común con git).
Puedo recomendar de todo corazón la siguiente configuración:
También se describe en (si necesitas un segundo recurso para entenderlo):
Básicamente funciona (con al menos tres repositorios) de la siguiente manera:
- Colocar el sitio web en el servidor en vivo bajo git,
- crear un nuevo repositorio git bare en el servidor en vivo.
- Y luego bifurcar desde el repositorio bare a tu(s) repositorio(s) git de desarrollo local.
Cuando el trabajo está hecho, haces push contra el repositorio bare remoto del que has clonado. El repositorio bare tiene hooks para sincronizar con el repositorio en vivo (en los códigos anteriores llamado prime).
Como configuraciones específicas de Wordpress en el repositorio, tengo este .gitignore
:
# los uploads son datos, excluidos del árbol de origen
wp-content/uploads/
El resto, incl. la configuración de plugins y temas, lo mantengo bajo control de versiones/configuración. Esto me permite rastrear cambios fácilmente y revisar el código antes de usarlo en vivo. También puedo fusionar más fácilmente con árboles remotos con mis propios cambios. Eso es especialmente útil contra el núcleo de Wordpress que está disponible en Github.
Esto funciona bastante bien para la mayoría de mis necesidades con Wordpress. El repositorio bare evita que hagas push de cambios conflictivos. También se sincroniza con una copia remota antes de actualizar el sitio en vivo. Eso significa que actualizar el sitio en vivo normalmente es bastante rápido. Debido a los hooks, incluso puedes llamar a los hooks de actualización de Wordpress después si lo deseas.
No he experimentado cuánto se puede mejorar esto con hooks de Github, pero normalmente no los necesito ya que el código está bajo control de versiones local, no en Github.
Para configurar este sistema por primera vez, debes tomarte un tiempo para evaluar si tienes todas las herramientas disponibles en tu servidor remoto:
- Acceso SSH
- GIT
- Un directorio privado donde puedas colocar archivos y subdirectorios (por ejemplo, para tu repositorio git bare)
El tiempo de configuración inicial debería ser posible en una o dos horas, incluyendo todo el entorno y tu primer push de publicación.
Dependiendo de tu host, también puedes querer proteger el directorio .git
del acceso web. Aquí hay un ejemplo de código .htaccess
que incluso hace esto teniendo Wordpress colocado dentro de un subdirectorio, lo que deja espacio en el repositorio no publicado en línea (útil):
Options -Indexes
# corregir barra final para .git / hacer que desaparezca + .gitignore y archivos similares.
RedirectMatch 404 ^/\.git(.*)$
# enmascarar 403 en .ht* como 404
<Files ~ "^\.ht">
Order Deny,Allow
Allow from all
Satisfy All
Redirect 404 /
</Files>
RewriteEngine On
RewriteBase /
# mapear todo en public y establecer variable de entorno
# para etiquetar la solicitud como válida
RewriteCond %{ENV:REDIRECT_sitealias} !set
RewriteRule ^(.*)$ /public/$1 [E=sitealias:set,L]
En resumen, todo lo que no esté dentro del directorio public no está en línea. Dentro del directorio public puede estar el código de Wordpress, por ejemplo, para el .htaccess
allí necesitas entonces:
RewriteEngine On
# enmascarar como 404 si se accede directamente
RewriteCond %{ENV:REDIRECT_sitealias} !set
RewriteRule .* - [L,R=404]
Esto evita el acceso directo a public. Parte de este .htaccess se puede encontrar descrito aquí: Las solicitudes a .htaccess deberían devolver 404 en lugar de 403. Para las variables de entorno, necesitas probar si eso funciona en tu entorno. También debes decidir si poner eso bajo control de versiones o no.
Si tienes más control sobre el alojamiento, puedes hacer más cosas aquí (y de manera diferente / más optimizada), los ejemplos anteriores están dirigidos a entornos típicos de hosting compartido (que ofrecen GIT, algunos usuarios dicen que puedes instalarlo fácilmente tú mismo, normalmente le pido a mis proveedores de hosting que lo proporcionen porque prefiero que ellos se encarguen, para eso les pago).
En el lado negativo, esto tiene algunos de los problemas comunes también mencionados en las otras respuestas. Una cosa de la que no estoy orgulloso pero que funciona es dar al host de desarrollo un cambio en su archivo de hosts para que el servidor de base de datos apunte a la copia de desarrollo. Así puedes mantener una configuración de base de datos. No es realmente genial, especialmente por las credenciales.
Copias de seguridad automáticas
Sin embargo, normalmente no me preocupo mucho aquí, sino que tengo copias de seguridad diarias ejecutándose en los sistemas remotos que son incrementales y que a su vez se almacenan en otra ubicación remota. Eso es fácil y económico y te permite restaurar tanto la instalación de Wordpress como los archivos subidos, la base de datos y el repositorio git. También para mis comandos de copia de seguridad, puede que no sean perfectos, pero funcionan para mí:
mysql: mysqldump --host=%s -u %s --password=%s %s| gzip > %s
git : git gc
git bundle
files: tar --force-local -czf %s %s
Lo que sugiero aquí es que mantengas los procesos alrededor de tu instalación de Wordpress fuera de Wordpress. Necesitan ejecutarse en un sistema específico, por lo que normalmente no los tienes dentro de la aplicación (por ejemplo, la aplicación puede caerse, pero necesitas que estos sigan funcionando).
Habilitado para trabajo en equipo
Otro beneficio agradable es que tu sitio ya está habilitado para el trabajo en equipo. Gracias al repositorio bare adicional, no puedes hacer mucho mal y puedes incluso compartir ramas remotas aparte de una rama master o live con tus colegas.
