Close

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


Repositorios centrales y locales

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.

Ventana de consola
Material relacionado

Git log avanzado

Logotipo de Bitbucket
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

Inicialización del repositorio central de cuidados

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.

Gestión de conflictos

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

Proceso de la función de cambio, preparación y confirmació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

Función de cambio, preparación y confirmació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

Publicación de una 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

Error del comando de envío

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

Reorganización de incorporación de cambios de Git

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:

Fusión mediante cambio de base a la rama principal (main)

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

Fusión mediante cambio de base en confirmaciones (commits)

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>
Flujo de trabajo de Git para la resolución de conflictos durante una fusión.

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

Sincronización del repositorio central

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

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.

Gente que colabora utilizando un muro lleno de herramientas

Blog de Bitbucket

Ilustración de Devops

Ruta de aprendizaje de DevOps

Demostraciones de funciones con expertos de Atlassian del Centro de demostraciones

Cómo funciona Bitbucket Cloud con Atlassian Open DevOps

Suscríbete para recibir el boletín de DevOps

Thank you for signing up