Comparar flujos de trabajo de Git: lo que debes saber
Git es el sistema de control de versiones más utilizado actualmente. Un flujo de trabajo de Git es una fórmula o una recomendación sobre cómo usar Git para llevar a cabo el trabajo de forma homogénea y productiva. Los flujos de trabajo de Git animan a los desarrolladores y a los equipos de DevOps a sacar partido a Git de forma eficaz y estable. Git ofrece a los usuarios una amplia flexibilidad para gestionar los cambios. Dado que Git se centra en la flexibilidad, no existe un proceso estandarizado acerca de cómo interactuar con Git. Cuando se trabaja con un equipo en un proyecto gestionado en Git, es importante asegurarse de que todo el equipo esté de acuerdo con la forma en que se aplicará el flujo de cambios. Para garantizar que todo el equipo se encuentre en sintonía, se debe desarrollar o seleccionar un flujo de trabajo de Git. Hay varios flujos de trabajo de Git publicados que pueden ser adecuados para tu equipo. Aquí hablaremos sobre algunas de estas opciones de flujo de trabajo de Git.
La gama de flujos de trabajos posibles hace que resulte complicado saber por dónde hay que empezar a implementar Git en el lugar de trabajo. En esta página proporcionamos un punto de partida, ya que ofrecemos un análisis de los flujos de trabajo más habituales entre los equipos de software.
Ten en cuenta que estos flujos de trabajo se han diseñado a modo orientativo, en lugar de para usarlos como reglas concretas. Queremos mostrarte las posibilidades, de forma que puedas combinar y mezclar aspectos de distintos flujos de trabajo que respondan a tus necesidades.
¿Qué es un flujo de trabajo de Git exitoso?
Cuando evalúas un flujo de trabajo para tu equipo, lo más importante es que tengas en cuenta la cultura de tu equipo. Quieres que el flujo de trabajo mejore la eficacia de tu equipo, no que sea una carga que limite la productividad. Estas son algunas cosas que debes tener en cuenta a la hora de evaluar un flujo de trabajo de Git:
- ¿Este flujo de trabajo se escala acorde al tamaño del equipo?
- ¿Es fácil deshacer los errores y los fallos con este flujo de trabajo?
- ¿Este flujo de trabajo impone al equipo excesos cognitivos nuevos e innecesarios?
Flujo de trabajo centralizado
El flujo de trabajo centralizado es un flujo de trabajo de Git estupendo para equipos que están realizando la migración desde Subversion (SVN). Al igual que SVN, el flujo de trabajo centralizado usa un repositorio central como punto de entrada de todos los cambios al proyecto. En lugar de trunk
, la rama de desarrollo predeterminada se llama main
(principal), y todos los cambios se confirman en dicha rama. Este flujo de trabajo no requiere ninguna rama más aparte de main
.
La migración a un sistema de control de versiones distribuido puede parecer una tarea complicada, pero no tienes que cambiar tu flujo de trabajo existente para sacarle partido a Git. Tu equipo puede desarrollar proyectos del mismo modo en el que lo hacían con Subversion.
No obstante, usar Git para impulsar tu flujo de trabajo de desarrollo presenta algunas ventajas en comparación con SVN. En primer lugar, le brinda a cada desarrollador su propia copia local del proyecto completo. Este entorno aislado deja que cada desarrollador trabaje de forma independiente a todos los demás cambios de un proyecto; pueden añadir confirmaciones a su repositorio local y olvidarse por completo de los desarrollos posteriores hasta que los necesiten.
En segundo lugar, te proporciona acceso al sólido modelo de fusión y creación de ramas de Git. Al contrario que SVN, las ramas de Git se han diseñado para constituir un mecanismo de seguridad de integración de código y uso compartido de cambios entre repositorios. El flujo de trabajo centralizado es similar a otros flujos de trabajo en lo que respecta al uso de un repositorio remoto alojado en servidor al que los desarrolladores pueden realizar envíos e incorporar cambios. En comparación con otros flujos de trabajo, el flujo de trabajo centralizado no tiene solicitudes de incorporación de cambios o patrones de bifurcación. Un flujo de trabajo centralizado suele ser más adecuado para equipos que migran desde SVN a Git y otros de tamaño reducido.
Material relacionado
Git log avanzado
VER LA SOLUCIÓN
Aprende a usar Git con Bitbucket Cloud
Funcionamiento
Los desarrolladores empiezan por clonar el repositorio central. En sus propias copias locales del proyecto, editan archivos y confirman cambios como lo harían en SVN; no obstante, estas nuevas confirmaciones se almacenan de forma local, completamente aisladas del repositorio central. Esto permite que los desarrolladores aplacen la sincronización con los niveles superiores hasta que realicen una pausa.
Para publicar cambios en el proyecto oficial, los desarrolladores "envían" su rama main
local al repositorio central. Este proceso equivale a svn commit
, excepto porque añade todas las confirmaciones locales que no se han enviado todavía a la rama main
central.
Incialización del repositorio central
En primer lugar, hace falta crear el repositorio central en un servidor. Si se trata de un proyecto nuevo, puedes inicializar un repositorio vacío. Si no es así, tendrás que importar un repositorio Git o SVN existente.
Los repositorios centrales deben ser siempre bare (vacíos, es decir, sin ningún directorio en funcionamiento), que se pueden crear de esta forma:
ssh user@host git init --bare /path/to/repo.git
Asegúrate de utilizar un nombre de usuario de SSH válido en user
, el dominio o la dirección IP de tu servidor en host
, y la ubicación en la que quieres almacenar el repositorio en /path/to/repo.git
. Ten en cuenta que la extensión .git
se sueñe añadir al nombre del repositorio para indicar que es un repositorio bare (vacío).
Repositorios centrales alojados
Los repositorios centrales se suelen crear mediante servicios de alojamiento de Git externos como, por ejemplo, Bitbucket Cloud. El servicio de alojamiento realiza por ti el proceso de inicializar un repositorio bare (vacío) que se ha explicado anteriormente. A continuación, dicho servicio de alojamiento proporcionará una dirección para acceder al repositorio central desde tu repositorio local.
Clonación del repositorio central
Acto seguido, cada desarrollador crea una copia local de todo el proyecto. Esto se consigue mediante el comando git clone:
git clone ssh://user@host/path/to/repo.git
Cuando clonas un repositorio, Git añade automáticamente un acceso rápido llamado origin
que apunta al repositorio "principal", ya que da por sentado que querrás interactuar con él más adelante.
Aplicación de cambios y confirmaciones
Cuando el repositorio se clona de forma local, el desarrollador puede aplicar cambios mediante el proceso de confirmación estándar de Git: editar, preparar y confirmar. Si no te has familiarizado con el entorno de ensayo, debes saber que consiste en una forma de preparar una confirmación sin tener que incluir todos los cambios del directorio en funcionamiento. Esto te permite crear confirmaciones con un enfoque muy claro, incluso si has aplicado muchos cambios locales.
git status # View the state of the repo
git add <some-file> # Stage a file
git commit # Commit a file</some-file>
Recuerda que, como estos comandos crean confirmaciones locales, John puede repetir el proceso todas las veces que quiera sin tener que preocuparse por lo que esté sucediendo en el repositorio central. Esta característica puede resultar muy útil para funciones de gran tamaño que se tienen que desglosar en bloques más sencillos y reducidos.
Envío de nuevas confirmaciones al repositorio central
Una vez que se hayan aplicado cambios nuevos al repositorio local, se deberán enviar estos cambios para compartirlos con otros desarrolladores del proyecto.
git push origin main
Este comando enviará los nuevos cambios confirmados al repositorio central. Cuando envías cambios al repositorio central, es posible que las actualizaciones enviadas anteriormente por otros desarrolladores contengan código que entra en conflicto con las actualizaciones que tú quieres enviar. Git mostrará un mensaje en el que se indica este problema. En esta situación, tendrá que ejecutarse el comando git pull
en primer lugar. Esta situación de conflicto se explica en profundidad en la sección siguiente.
Gestión de conflictos
El repositorio central representa el proyecto oficial, por lo que su historial de confirmación se debe tratar como algo sagrado e inmutable. Si las confirmaciones locales de un desarrollador difieren de las del repositorio central, Git rechazará el envío de cambios porque estos sobrescribirían las confirmaciones oficiales.
Antes de que el desarrollador pueda publicar una función, tiene que buscar y actualizar las confirmaciones centrales y reorganizar los cambios a partir de ellas. Es como decir "quiero añadir mis cambios a lo que los demás ya han hecho". El resultado es un historial perfectamente lineal, como las de los flujos de trabajo de SVN tradicionales.
Si los cambios locales entran en conflicto directo con las confirmaciones en niveles superiores, Git pondrá en pausa el proceso de fusión mediante cambio de base y te dará la oportunidad de resolver los conflictos de forma manual. Lo bueno de Git es que usa los mismos comandos, git status
y git add
, tanto para generar confirmaciones como para resolver conflictos de fusión. Esto facilita a los nuevos desarrolladores la gestión de sus propias fusiones. Además, si tienen problemas, Git hace que sea muy fácil anular por completo la fusión mediante cambio de base y volver a intentarlo (o ir a pedir ayuda).
Ejemplo
Veamos un ejemplo general sobre cómo un equipo que suele ser pequeño puede colaborar mediante este flujo de trabajo. Hemos visto como dos desarrolladores, John y Mary, pueden trabajar en funciones separadas y compartir sus contribuciones mediante un repositorio centralizado.
John trabaja en su función
En este repositorio local, John puede desarrollar funciones mediante el proceso de confirmación estándar de Git: editar, preparar y confirmar.
Recuerda que, como estos comandos crean confirmaciones locales, John puede repetir este proceso tantas veces como desee sin tener que preocuparse por lo que está pasando en el repositorio central.
Mary trabaja en su función
Mientras tanto, Mary trabaja en su propia función y en su propio repositorio local con el mismo proceso de edición/preparación/confirmación. Al igual que a John, no le importa lo que esté sucediendo en el repositorio central y lo cierto es que tampoco le importa lo que John está haciendo en su repositorio local, ya que todos los repositorios locales son privados.
John publica su función
Cuando John haya terminado su función, deberá publicar sus confirmaciones locales en el repositorio central, de forma que otros miembros del equipo puedan acceder a ellas. Puede hacerlo con el comando git push de este modo:
git push origin main
Recuerda que origin
es la conexión remota al repositorio central que Git creó cuando John lo clonó. El argumento main
le indica a Git que intente hacer que la rama main
de origin
tenga el mismo aspecto que su rama main
local. Como el repositorio central no se ha actualizado desde que John lo clonó, esta acción no creará ningún conflicto y el envío se realizará según lo previsto.
Mary intenta publicar su función
Veamos lo que pasa cuando Mary intenta enviar su función después de que John haya publicado con éxito sus cambios en el repositorio central. Puede usar el mismo comando push:
git push origin main
No obstante, como su historial local es distinto que el del repositorio, git rechazará la solicitud con un mensaje de error algo extenso:
error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Así se evita que Mary sobrescriba las confirmaciones oficiales. Tiene que incorporar los cambios de las actualizaciones de John a su repositorio, integrarlos con sus cambios locales y, a continuación, volver a intentarlo.
Mary realiza una reorganización a partir de las confirmaciones de John
Mary puede usar el comando git pull para incorporar a su repositorio cambios presentes en el repositorio remoto. Este comando se parece en cierto modo a svn update
, ya que incorpora al repositorio local de Mary los cambios presentes en todo el historial de confirmaciones del repositorio remoto e intenta integrarlos con sus confirmaciones locales:
git pull --rebase origin main
La opción --rebase
le pide a Git que mueva todas las confirmaciones de Mary al extremo de la rama main
después de sincronizarla con los cambios del repositorio central, como se muestra a continuación:
La incorporación de cambios seguirá funcionando si se te olvida esta opción, pero es posible que tengas que realizar una confirmación de fusión cada vez que alguien tenga que realizar una sincronización con el repositorio central. Para este flujo de trabajo, siempre es mejor reorganizar en lugar de generar una confirmación de fusión.
Mary soluciona un conflicto de fusión
La fusión mediante cambio de base consiste en transferir todas las confirmaciones locales a la rama main
de una en una. De este modo, descubrirás los conflictos de fusión de cada confirmación una por una, en lugar de tener que resolverlos todos con una confirmación de fusión masiva. Además, esto hace que tus confirmaciones mantengan un enfoque lo más claro posible, y hace que el historial del proyecto esté limpio. A su vez, también hace que resulte mucho más sencillo descubrir qué errores se han introducido y, si fuera necesario, revertir cambios con un impacto mínimo sobre el proyecto.
Si Mary y John trabajan en funciones que no están relacionadas, es poco probable que el proceso de reorganización genere conflictos. No obstante, si así fuera, Git pausará la reorganización en la confirmación actual y mostrará el siguiente mensaje, además de algunas instrucciones importantes:
CONFLICT (content): Merge conflict in <some-file>
Lo bueno de Git es que cualquiera puede resolver sus propios conflictos de fusión. En nuestro ejemplo, Mary solo tendría que ejecutar un comando git status para ver dónde está el problema. Los archivos en conflicto se mostrarán en la sección "Unmerged paths":
# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>
A continuación, editará los archivos según estime oportuno. Cuando esté contenta con el resultado, podrá preparar los archivos según el método habitual y dejar que git rebase se encargue del resto:
git add <some-file>
git rebase --continue
Y esto es todo lo que hay que hacer. Git continuará con la siguiente confirmación y repetirá el proceso con cualquier otra confirmación que genere conflictos.
Si llegas a este punto y te das cuenta de que no tienes ni idea de lo que está pasando, no entres en pánico. Solo tienes que ejecutar el siguiente comando y volverás al punto de inicio:
git rebase --abort
Mary publica correctamente su función
Después de terminar con la sincronización del repositorio central, Mary podrá publicar los cambios correctamente:
git push origin main
Hacia dónde ir
Como puedes ver, es posible replicar un entorno de desarrollo de Subversion tradicional con solo unos comandos de Git. Este método es perfecto para los equipos que están migrando de SVN, pero no le sacan partido a la naturaleza distribuida de Git.
El flujo de trabajo centralizado es estupendo para equipos pequeños. El proceso de resolución de conflictos explicado anteriormente puede provocar un cuello de botella a medida que tu equipo escale su tamaño. Si tu equipo se siente cómodo con el flujo de trabajo centralizado, pero quiere perfeccionar la colaboración, merece la pena analizar las ventajas del flujo de trabajo de ramas de función. Al dedicar una rama aislada a cada función, se pueden iniciar conversaciones en profundidad acerca de nuevas adiciones antes de integrarlas en el proyecto oficial.
Otros flujos de trabajo habituales
El flujo de trabajo centralizado consiste en un bloque de construcción de otros flujos de trabajo de Git. Los flujos de trabajo de Git más populares cuentan con una especie de repositorio centralizado del que los desarrolladores pueden incorporar cambios y al que pueden enviar los suyos. A continuación, hablaremos brevemente sobre otros flujos de trabajo de Git populares. Estos flujos de trabajo ampliados ofrecen patrones más específicos en lo que respecta a la gestión de ramas para el desarrollo de funciones, las correcciones inmediatas y la publicación.
Ramas de funcionalidades
La creación de ramas de función es una extensión lógica del flujo de trabajo centralizado. La idea principal que subyace al flujo de trabajo de ramas de función es que el desarrollo de una función debe llevarse a cabo en una rama especializada, en lugar de en la rama main
. Este aislamiento permite que varios desarrolladores trabajen en una función concreta sin modificar el contenido del código base principal. También implica que la rama main
no debería contener en ningún caso código erróneo, lo que supone una gran ventaja para los entornos de integración continua.
Flujo de trabajo de Gitflow
El flujo de trabajo Gitflow se publicó por primera vez en una entrada de blog de 2010 muy reconocida de Vincent Driessen en nvie. El flujo de trabajo Gitflow define un modelo de creación de ramas estricto diseñado con la publicación del proyecto como fundamento. Este flujo de trabajo no añade ningún concepto o comando nuevo, solo los que se necesitan para el flujo de trabajo de ramas de función. En su lugar, asigna funciones muy específicas a las distintas ramas y define cómo y cuándo deben estas interactuar.
Flujo de trabajo de bifurcación
El flujo de trabajo de bifurcación es radicalmente diferente al resto de los flujos de trabajo analizados en este tutorial. En lugar de usar un único repositorio en servidor para que actúe como código base "central", le proporciona a cada desarrollador un repositorio en servidor. Esto quiere decir que cada colaborador tiene dos repositorios de Git: uno local y privado, y otro público y en servidor.
Directrices
No existe un flujo de trabajo de Git universal. Como se ha indicado anteriormente, es muy importante desarrollar un flujo de trabajo de Git que suponga una mejora productiva para tu equipo. Además de la cultura del equipo, el flujo de trabajo debe complementar la cultura empresarial. Las funciones de Git, como las ramas y las etiquetas, deben complementar la planificación de publicación de tu empresa. Si tu equipo usa algún software de gestión de proyectos con seguimiento de tareas, quizá te interese usar ramas que se correspondan con las tareas en curso. Además, aquí presentamos algunas directrices que se deben tener en cuenta a la hora de decantarse por un flujo de trabajo:
Ramas transitorias
Cuanto más tiempo se desarrolle una rama de forma independiente a la rama de producción, mayor será el riesgo de que surjan conflictos de fusión y retos de implementación. Las ramas transitorias proporcionan fusiones e implementaciones más limpias.
Minimización y simplificación de reversiones
Es importante disponer de un flujo de trabajo que ayude de forma proactiva a evitar fusiones que se tengan que revertir. Un ejemplo de esto son los flujos de trabajo que realizan pruebas en las ramas antes de fusionarlas con la rama main
. No obstante, es natural que se produzcan accidentes. Con esto en mente, conviene tener un flujo de trabajo que permita realizar reversiones sencillas que no interrumpan el flujo del resto de los miembros del equipo.
Cumplimiento de una planificación de publicación
Los flujos de trabajo deben complementar tu ciclo de publicación de desarrollo de software empresarial. Si tienes pensado realizar varias publicaciones al día, querrás que tu rama main
se mantenga estable. Si tu planificación de publicación es mucho menos frecuente, quizá te convenga plantearte la opción de usar etiquetas de Git para asignar una rama a una versión.
Resumen
En este documento, hemos hablado de los flujos de trabajo de Git, hemos analizado en profundidad el flujo de trabajo centralizado con ejemplos prácticos y hemos ampliado esta información con la de otros flujos de trabajo especializados. Estas son algunas de las ideas fundamentales de este documento:
- No existe un flujo de trabajo de Git universal.
- Un flujo de trabajo debe ser sencillo y mejorar la productividad de tu equipo.
- Los requisitos de tu empresa deben ayudar a dar forma al flujo de trabajo de Git.
Si quieres más información sobre el flujo de trabajo de Git, echa un vistazo a nuestra explicación exhaustiva del flujo de trabajo de ramas de función.
Compartir este artículo
Tema siguiente
Lecturas recomendadas
Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.