GIT vs SVN

Angel G. Olloqui 13 May, 2012

Hace ya mucho que no escribo, y la verdad es que después de todo este tiempo tengo una larga lista de temas. Por eso, he decidido empezar con un tema no muy técnico como este para ir calentando motores :)

Principales diferencias entre GIT y SVN

Antes de nada, tengo que advertir que todavía soy principiante en GIT, ya que lo he estado usando durante los ultimos 3 meses nada más, y tampoco tengo experiencia con otros SCM como Mercurial o CVS. No obstante, creo que dispongo de una visión suficiente como para escribir algunas de las cosas que, acostumbrado a SVN, me han chocado en mi cambio, así como algunas de las ventajas de este nuevo sistema de control de versiones. 
 
Os advierto que, aunque parezca que no, hay mucha chicha que contar y explicar.  Por eso no me voy a entretener con información de background  ni tampoco va a ser un tutorial para iniciarse (puedes buscar en Google para esto que hay muchos y muy buenos tutoriales). Voy directo a discutir algunas de las mayores diferencias:
Distribuido
Lo primero que te dice todo el mundo cuando preguntas por GIT es que es descentralizado, así que yo no voy a ser menos. Que significa esto? pues que a diferencia de otros entornos donde los ficheros se encuentran alojados en un repositorio central (SVN Server por ejemplo), aquí cada uno es su propio servidor (al estilo P2P). Esto puede sonar raro, pero a medida que vayamos descubriendo cómo funciona GIT en los próximos apartados, veremos que esto es esencial para poder hacer algunas de las cosas que permite GIT.
Esta característica tiene algunas consecuencias inmediatas que probablemente ya se te estarán ocurriendo:
  1. Si es local, cuando hago un commit no me sincronizo con otros usuarios no?: Correcto! cuando haces un commit  lo haces en tu GIT local, y por tanto, el resto de usuarios no ven tu cambio. Para sincronizarte con el resto de usuarios, deberías “conectarte” con sus GIT y “bajarte” los cambios (ellos deberán hacer lo mismo con el tuyo). Para ello, GIT dispone del concepto de remotes, que no es más que una URL a otro GIT. Así contado parece un desastre para equipos grandes (trabajo extra y conflictos), pero espera un poco porque luego veremos que funciona genial gracias a otras características de GIT.
  2. Si es local, puedo hacer commit sin conexión?: Correcto de nuevo! puedes hacer los commits que quieras sin conexión, y estos serán idénticos a los que hagas con conexión (fecha y conjunto de cambios).
  3. Si es local, significa que tengo toda la información (incluido histórico de cambios) en mi disco? esto no ocupará mucho?: Sí, tienes toda la información en tu disco, pero luego veremos que los commits en GIT son unidades muy pequeñitas que realmente ocupan muy poco espacio, por lo que no es un problema. Además, en caso de serlo tienes comandos para hacer limpieza :)
Commits
En GIT un commit no es más que una secuencia de cambios aplicados sobre una versión anterior, una fecha, un autor y un identificador. No hay mucho más. Puede ser que pienses que en SVN es igual, pero la gran ventaja de GIT es que tiene un control mucho más fino. Los cambios no son ficheros completos que luego se comparan para ver diferencias, sino líneas de texto agregadas/eliminadas (un cambio es una eliminación+agregación), excepto si el fichero es binario. En general, en SVN es común pensar en un commit como un Snapshot de un proyecto en un momento determinado, mientras que en GIT es difícil verlo como otra cosa que no sea un pequeño parche sobre la versión anterior. Es una diferencia sutil, pero ahora cuando veamos como se trabaja a nivel de branch veremos la potencia (y gran ventaja para mi gusto) de todo esto trabajando junto.
 
Contenido de un commit  (verde líneas agregadas, rojo eliminadas)
Branches, rebases y patches
Aquí está para mí la gran diferencia entre ambos sistemas y lo más complicado. Como acabo de comentar, en GIT un commit es una unidad muy pequeña, tanto que incluso se puede mover libremente por tus branches y repositorios! Sí sí, lo que has leído, un commit puede moverse de una rama a otra, duplicarse o llevarse a un repositorio diferente! cómo es posible? bueno, porque como he dicho, un commit no es más que un “parche” (ya se va viendo la sutil diferencia con SVN??). De nuevo, esto tiene consecuencias muy importantes en la forma de trabajo y capacidades de GIT:
  1. El concepto de branch cambia: En SVN un branch es, a nivel de usuario, un nuevo directorio donde reside una copia que se tomó en un determinado momento de otra rama, donde aplicas cambos, y que en un momento posterior puede volverse a unir sobre otra rama resolviendo los conflictos que puedan surgir por ficheros modificados en ambos branches. En GIT esta historia cambia. El concepto de branch en GIT no es más que una secuencia temporal de commits, pero no existe un nuevo directorio ni ideas similares. En un repositorio GIT tienes un conjunto de commits, los cuales pueden estar aplicados (uno tras otro) en una o muchas branches al mismo tiempo
  2. Cambiar de rama significa deshacer los commits de tu rama (hasta el commit común con la rama a la que te cambias) y aplicar los commits de esta nueva rama secuencialmente. No hay descarga de ficheros ni ningún otro cambio.
  3. Los branches puede moverse: podemos jugar con los branches como queramos, incluido el reposicionar (rebase) un branch encima de cualquier commit. El mecanismo es similar al cambio de rama, pero cambia la estructura del repositorio: se deshacen los commits hasta donde sea necesario y se vuelven a aplicar siguiendo la línea nueva, todo automáticamente! Por supuesto, si movemos nuestro branch podemos encontrarnos conflictos, pero en general GIT los resuelve mucho mas eficientemente que otros entornos precisamente gracias al concepto de commit como un parche.
  4. Podemos aplicar commits sueltos: GIT permite coger un commit suelto y aplicarlo en nuestro stage (espacio de trabajo) como si fuera un simple parche. Es más, podemos exportar el commit y aplicarlo en cualquier otra rama o repositorio. Esto es especialmente útil cuando arreglas un bug que afecta a muchas ramas, ya que puedes aplicar el mismo commit a todas ellas sin tener que replicar el cambio (incluso aunque los ficheros afectados hayan cambiado entre ramas).
  5. Al ser un repositorio local, puede haber ramas que existan en los GIT locales de algunos usuarios y no en el de otros.
 
La consecuencia negativa de todo esto, como puedes imaginar, es que se producen complicados cruces de commits entre ramas. No obstante, existen muchas herramientas que ayudan a visualizarlos como líneas temporales para ver gráficamente en que punto te encuentras.
 
Vista de cruces de distintos branches
 
Github y remotes
Todo lo anterior está muy bien, pero si tenemos un equipo de varias personas y todas ellas tienen que sincronizarse con todas las demás cada día sería inviable usarlo. Para estos casos, se suele utilizar un repositorio centralizado que recoge los commits de todos los usuarios, de forma que cada usuario solo necesite sincronizarse con este repositorio central (al estilo SVN). Pero una vez más, con GIT puedes utilizar una mejora muy grande sobre este concepto: en lugar de dar a cada usuario permiso para escribir en el repositorio central, se les da sólo de lectura, y se les facilita un mecanismo para que soliciten “integrar” cambios al repositorio central. Alguien, encargado de preservar la calidad del proyecto, aprueba o desaprueba los cambios que le lleguen antes de que estos pasen a estar disponibles para el resto de usuarios. Este “mecanismo” son servicios como GitHub o BitBucket, que básicmanete son portales desde los que puedes gestionar tu copia de un proyecto (fork), pedir integrar tus cambios en el repositorio principal (pull request), hacer cambios desde el entorno Web, seguir usuarios,.... Este mecanismo es tremendamente potente especialmente cuando trabajas con muchos colaboradores o en proyectos de OpenSource donde cualquiera puede contribuir con una mejora. No es casualidad la inmensa cantidad de proyectos que se encuentran en GitHub, y cada día más! ahora entenderás por qué!
Stashes
Un stash es algo muy sencillo pero a la vez práctico: un commit temporal. Se utiliza cuando estás en medio de una serie de cambios (sin acabar) y por alguna razón quieres cambiar de rama o hacer un revert sin perder el trabajo (en mi caso me suele pasar cuando viene un cliente que no esperaba y me pide que le instale alguna versión de algo que estoy cambiando). Muy simple, pero muy cómodo: creas stash, te mueves al commit que quieras y cuando acabes vuelves a moverte y aplicar stash. Menos de 30 segundos y problema resuelto.
Submódulos
GIT proporciona un mecanismo bastante potente para incluir submódulos de otros repositorios. Por ejemplo, si tu proyecto hace uso de librerías de terceros puedes agregarlas como módulos y así permanecerás siempre actualizado (si apuntas al HEAD) y no tienes que andar descargando código. Además, si este submódulo requiere otros submódulos estos se incluirán también automáticamente si lo deseas.
Integracion con herramientas
Tanto SVN como GIT tienen multitud de herramientas y plugins para integrarse con diferentes entornos. No obstante, en mi caso (que uso XCode), el IDE viene con una vista GIT donde puedes trabajar sin necesidad de instalar plugins ni similares y que además trae un gestor de conflictos para los projects files bastante potente.
Gitflow
No quiero entrar mucho en esto ya que es un tema avanzado (no hace falta usarlo), pero sí me gustaría mencionar que GitFlow es un “workflow” y un conjunto de scripts que te ayudan a mantener el orden en proyectos con múltiples ramas en paralelo y developers. No conozco nada parecido en SVN, aunque quizá exista.
 

Por qué cambiar a GIT?

Después de todo lo anterior creo que no es necesario extenderme mucho en esto, pero claramente GIT es un sistema mucho más nuevo y renovado, que le da un nuevo enfoque a un problema presente en todos los desarrollos de software. 
Es mucho más completo y potente que otras alternativas, y puede ayudar enormemente a aumentar la calidad de tus proyectos si tienes a un buen gestor del repositorio principal que haga revisiones de las pull request. 
Habrá quien piense que no hay nada de lo que he dicho que realmente no se pueda hacer con SVN, pero lo cierto es que algunas cosas que he contado anteriormente son tremendamente fáciles de hacer con GIT, a un nivel que SVN ni se acerca (además de que en otras cosas como la gestión de conflictos es objetivamente mejor).
Creo que la pregunta no es “por qué cambiar a GIT” sino “por qué no estás usando ya GIT”.
 

Mi experiencia personal

Mi opinión es claramente favorable, si bien es cierto que he encontrado algunos problemas. El diferente concepto de ramas, su complejidad, sus cruces, etc. me llevaron al principio a no ver un verdadero motivo para usar este SCM en vez de seguir con el tradicional SVN, mucho más sencillo. No obstante, una vez superada la tormenta inicial (un par de semanas), tengo que decir que el cambio merece la pena. 
La capacidad de hacer y deshacer trabajo, de cambiar ramas, de compartir código con otros developers o de controlar la calidad del proyecto es algo que compensa con creces el tiempo de aprendizaje donde todo resulta mas lento, complejo y pesado. Si vas a empezar con ello, hínchate de energía, pasarás malos momentos, pero poco a poco empezarás a ver la luz y a enamorarte de cómo funciona GIT. Después de eso mirarás hacia atrás y pensarás que SVN está anticuado :)

Tags: svn, git