Domina Git como un Pro: Claves para una Colaboración Fluida
Cuando trabajas de forma colaborativa en tus proyectos de software, ¿tienes dudas sobre cómo escribir tus commits, cómo se deben llamar las branches en las que trabajas, o cuáles son las mejores prácticas para el trabajo colaborativo en los repositorios? Si respondiste que sí a al menos una de estas preguntas, esta publicación es para ti
En esta ocasión te mostraré un conjunto detallado de reglas y mejores prácticas para realizar commits en los repositorios en los que colabores. El propósito de esta guía es garantizar la consistencia, legibilidad y seguimiento efectivo de los cambios d código, facilitando la colaboración y comprensión entre todos los miembros del equipo.
1. Uso de Prefijos en los Mensajes de Commit
Utiliza prefijos estandarizados al principio de cada mensaje de commit para indicar la naturaleza del cambio:
feat: Una nueva característica o funcionalidad agregada.
fix: Correcciones de errores o problemas.
docs: Cambios relacionados con la documentación.
style: Cambios que no afectan el significado del código (espaciado, formato, etc.).
refactor: Cambios de código que no corrigen errores ni añaden características, como reorganizar el código.
test: Agregar o corregir pruebas.
chore: Tareas de mantenimiento o cambios menores que no encajan en las categorías anteriores.
Ejemplo del uso de prefijos
feat: Añadir sistema de autenticación de usuario
fix: Resolver problema de inicio de sesión en el sistema de autenticación
docs: Actualizar README con detalles del sistema de autenticación
2. Claridad y Concisión en los Mensajes de Commit
Cada mensaje de commit debe explicar clara y precisamente qué cambios se han realizado y por qué. Mantén los mensajes breves y al grano. Idealmente, el título no debe exceder los 50 caracteres.
Ejemplo de claridad
Ejemplo #1
Mensaje poco claro: Cosas arregladas
Mensaje claro: fix: Resolver problema de desbordamiento en la navegación lateral
El mensaje claro explica explícitamente qué se corrigió y dónde, facilitando a los miembros del equipo entender el cambio sin mirar el código
Ejemplo #2
Mensaje poco claro: Actualizaciones
Mensaje claro: feat: Actualizar la lógica de autenticación de usuario para prevenir problemas de expiración de token
El mensaje claro proporciona información específica sobre qué se actualizó y por qué, lo cual es más informativo que un vago "Actualizaciones".
Ejemplo de conciso
Ejemplo #1
Mensaje verboso: Cambió el tamaño de la fuente y el color en la sección del encabezado de la página de inicio para mejorar la visibilidad en pantallas pequeñas
Mensaje conciso: feat: Mejorada la legibilidad del encabezado en pantallas pequeñas
El mensaje conciso resume el cambio clave sin entrar en detalles innecesarios.
Ejemplo #2
Mensaje verboso: Añadidas nuevas comprobaciones de validación al campo de correo electrónico en el formulario de registro para prevenir que los usuarios introduzcan direcciones de correo electrónico inválidas
Mensaje conciso: feat: Mejorada la validación de email en formulario de registro
La versión concisa transmite la esencia del cambio sin describir cada regla de validación específica añadida.
3. Estructura de los Mensajes de Commit
Un mensaje de commit bien organizado incluye:
Título: Un resumen conciso del cambio, típicamente de menos de 50 caracteres. A menudo incluye un tipo (como feat, fix, o docs) y una breve descripción del cambio.
Cuerpo (opcional): Una explicación más detallada de qué fue lo que cambió y por qué. Es opcional pero altamente recomendado para cambios complejos.
Pie de página (opcional): Se utiliza para hacer referencia a problemas relacionados, solicitudes de extracción o cualquier nota adicional. Esta parte es especialmente útil para la gestión de proyectos y propósitos de seguimiento.
Ejemplos de mensajes
Ejemplo #1
feat: Implementar edición de perfil de usuario
Se añadió la opción para que los usuarios editen la información de su perfil.
Los usuarios ahora pueden actualizar su nombre, email y foto de perfil.
Se aseguró la validación de entrada y el manejo de errores.
Se actualizaron los componentes de usuario y la interfaz de usuario del perfil.
Relacionado con el problema #123
Ejemplo #2
docs: Actualizar README con nuevas instrucciones de configuración
Se revisó el README para reflejar los últimos pasos de configuración del proyecto.
Se incluyeron nuevas secciones sobre configuración del entorno y construcción inicial.
Se añadieron preguntas frecuentes para problemas comunes de configuración.
Ver también actualizaciones de documentación en PR #789
4. Granularidad de los Commits
El concepto de granularidad en los commits se refiere a cuánto cambio incluye cada commit. Las mejores prácticas sugieren que cada commit debe contener un único cambio lógico. Este enfoque ofrece varios beneficios, como revisiones de código más fáciles, seguimiento de errores más simple y colaboración más eficiente. Se trata de hacer que cada commit sea autónomo y comprensible.
Responsabilidad Única: Cada commit debe representar un cambio lógico único. Esto facilita la comprensión del propósito e impacto del commit.
Aislamiento de Cambios: Si un commit se enfoca en un tipo específico de cambio (por ejemplo, una corrección de error, una nueva característica o una refactorización), no debe mezclarse con otros cambios no relacionados.
Revertibilidad: En caso de problemas, debería ser fácil revertir un commit sin afectar otros aspectos no relacionados del proyecto.
Facilidad de Revisión: Los commits más pequeños y enfocados son más fáciles de revisar y entender para los compañeros, lo que lleva a una mejor calidad del código y colaboración.
Ejemplos de Commits
Granularidad Buena
feat: Añadir funcionalidad de búsqueda a la página de lista de usuarios
Este commit se enfoca exclusivamente en añadir nueva funcionalidad de búsqueda.
style: Reformato de la página de lista de usuarios de acuerdo a las reglas de linting
Este commit solo involucra cambios de estilo de código.
fix: Resolver fuga de memoria en el componente de lista de usuarios
Este commit aborda un error específico.
En estos ejemplos, cada commit está enfocado y aborda un solo aspecto del proyecto. Son fáciles de describir y entender.
Granularidad Pobre
Añadir característica de búsqueda, reformatear código, corregir fuga de memoria
Este commit mezcla una nueva característica, cambios de estilo y una corrección de error, lo que dificulta discernir el propósito e impacto de cada cambio.
En este ejemplo, el commit incluye múltiples cambios no relacionados. Esta falta de granularidad hace más difícil entender el propósito del commit a primera vista, complica las revisiones de código y obstaculiza el proceso de revertir cambios si es necesario.
5. Uso de Branches
Las branches son una parte esencial de cualquier estrategia de control de versiones, permitiendo que múltiples flujos de trabajo progresen independientemente dentro del mismo proyecto. El uso efectivo de branches facilita el desarrollo de características, correcciones de errores, experimentación y más, sin interferir con la versión estable del proyecto.
Branches para Cada Característica o Tarea: Crea una branch separada para cada nueva característica, corrección de error o tarea significativa. Esto mantiene los cambios organizados y aislados del código base principal hasta que estén listos para ser fusionados.
Convenciones de Nombres: Usa nombres descriptivos y consistentes para las branches. Esto ayuda a identificar el propósito de cada branch de un vistazo.
Ramas de Características de Corta Duración: Mantén las branches de características cortas. Fúsionalas de vuelta en la branch principal tan pronto como la característica esté completada y probada para evitar desviarse demasiado del código base principal.
Fusión Regular: Fusiona regularmente los cambios de la branch principal (o branch de desarrollo, si estás usando Git-Flow) en tus branches de características para mantenerlas actualizadas y minimizar los conflictos de fusión.
Solicitudes de Pull para la Fusión: Usa solicitudes de pull para fusionar branches. Esto facilita las revisiones de código, discusiones y asegura el control de calidad antes de la integración en la branch principal.
Nombrar Branches
Al nombrar branches en nuestro repositorio, es crucial seguir un formato estandarizado y descriptivo. Esto ayuda a mantener un código base organizado y facilita la navegación y comprensión del trabajo en curso. El formato recomendado para nombrar branches es el siguiente:
Formato: [tipo]/[nombre de usuario]-[descripción de la característica]
Ejemplo: feature/alexcamachogz-user-authentication
Esta estructura de nomenclatura está compuesta de tres componentes clave:
Tipo: Indica el propósito de la branch (por ejemplo, feature, fix, refactor, test). Esta categorización ayuda a identificar rápidamente la intención de la branch de un vistazo.
Nombre de Usuario: La inclusión del nombre de usuario o identificador del desarrollador (alexcamachogz en el ejemplo) denota al individuo principal responsable del trabajo en esta rama. Esto es especialmente útil si varios desarrolladores pueden estar trabajando en tareas similares.
Descripción de la Característica: Una descripción breve pero descriptiva del enfoque de la branch (user-authentication en el ejemplo). Esta parte debe transmitir de manera concisa el objetivo principal o la funcionalidad que se está implementando o abordando.
Ejemplo del Uso de Branches
Buena Práctica
Ejemplo #1
Tipo: Branch de características
Nombre: feature/alexcamachogz-user_authentication
Propósito: Desarrollar un sistema de autenticación de usuarios.
Ejemplo #2
Tipo: Branch de corrección de errores
Nombre: fix/alexcamachogz-login_page--crash
Propósito: Arreglar un problema específico de caída en la página de inicio de sesión.
Ejemplo #3
Tipo: Branch de experimentación
Nombre: experiment/alexcamachogz-new_ui--layout
Propósito: Probar un nuevo diseño de UI sin afectar el código principal.
En estos ejemplos, cada branch tiene un enfoque claro y único, sus nombres transmiten inmediatamente su propósito.
Mala Práctica
Ejemplo #1
Tipo: Branch genérica
Nombre: my_changes
Explicación: Este nombre es vago y no transmite el propósito de la branch.
Ejemplo #2
Tipo: Branch de características de larga duración
Nombre: feature/alexcamachogz-new_entire_module
Explicación: Si esta branch vive durante meses, corre el riesgo de convertirse en un universo paralelo que es difícil de fusionar de nuevo en la branch principal.
6. Evita Commits Temporales
Los commits temporales o Work-In-Progress (WIP) se refieren a commitear trabajo parcial, incompleto o experimental. Aunque pueden parecer convenientes para un desarrollador a corto plazo, pueden ensuciar el historial de commits del proyecto y hacer más difícil entender los cambios en el código. Evitar tales commits ayuda a mantener un historial de commits claro y significativo.
Usar Stashes o Ramas Locales: En lugar de comprometer cambios incompletos a una branch compartida, usa la característica de stash de Git o una branch local para el trabajo temporal. Esto mantiene tu progreso guardado sin ensuciar el repositorio principal.
Commits Completos y Funcionales: Asegúrate de que cada commit represente una pieza completa y funcional de trabajo. Esto no significa que un commit deba implementar una característica completa, pero debe ser una parte lógica y autocontenida del trabajo.
Limpiar la Historia Antes de Fusionar: Si tienes commits WIP en una branch de características, reorganiza antes de fusionarlos en la branch principal. Esto limpia la historia y asegura que la branch principal solo contenga commits completos y significativos.
Evitar Commits de "Arreglar Luego": No hagas commit algo con la intención de arreglarlo o limpiarlo más tarde. Es mejor completar el trabajo y luego hacer commit .
Ejemplos de Evitar Commits Temporales
Buena Práctica
Completar una parte de una característica antes de hacer commit
feat: Añadir componente de barra de búsqueda
Este commit representa la finalización de un componente de barra de búsqueda, una parte autocontenida y funcional de una característica más grande.
Usar stashes para trabajo incompleto
En lugar de hacer commit, usa git stash
para guardar temporalmente cambios incompletos, como una característica medio implementada o un experimento rápido.
Mala Práctica
Hacer commit a una funcionalidad incompleta
WIP: Empezado a trabajar en funcionalidad de búsqueda
Este mensaje de commit indica que el trabajo está incompleto. Es mejor completar una porción lógica del trabajo antes de hacer commit.
Commits frecuentes de "Arreglar Luego"
fix: Arreglo temporal para error de inicio de sesión
fix: Otro arreglo rápido para inicio de sesión, mejorará más tarde
Estos mensajes de commit indican un patrón de arreglos temporales. Es más eficiente resolver el problema completamente antes de hacer el commit.
7. Resolución de conflictos
La resolución de conflictos es un aspecto crítico al trabajar con sistemas de control de versiones, especialmente en entornos colaborativos. Los conflictos típicamente ocurren cuando los cambios en diferentes branches se superponen y se contradicen entre sí. Gestionar eficazmente estos conflictos es clave para mantener un flujo de trabajo suave y asegurar la integridad de la base de código.
Actualizaciones Regulares: Actualiza regularmente tus branches con los últimos cambios de la branch principal. Esto minimiza la posibilidad de conflictos manteniendo tu branch sincronizada con el progreso del proyecto.
Comunicación: Coordina con los miembros del equipo que trabajan en áreas relacionadas o similares de la base de código. Una comunicación abierta puede prevenir cambios superpuestos o ayudar a planificar cómo integrarlos.
Entender el Conflicto: Cuando surge un conflicto, comprende los cambios que lo causan. Revisa el código en conflicto de ambos lados para determinar la mejor manera de integrarlos.
Usar Herramientas de Control de Versiones: Utiliza las herramientas proporcionadas por tu sistema de control de versiones para la resolución de conflictos. Estas herramientas a menudo proporcionan una representación visual de los conflictos, lo que facilita entenderlos y resolverlos.
Probar Después de la Resolución: Una vez que los conflictos están resueltos, prueba minuciosamente las partes afectadas de la aplicación para asegurar que los cambios funcionan como se pretende y no introducen nuevos errores.
Ejemplos de Resolución de Conflictos
Ejemplo #1
Situación:
Estás trabajando en una branch de característica feature/new-search-algorithm.
Otro miembro del equipo ha realizado cambios en la funcionalidad de búsqueda en la branch principal.
Cuando intentas fusionar tu branch, surge un conflicto en search.js.
Estrategia de Resolución:
Actualiza tu branch con la última versión de la branch principal.
Utiliza una herramienta de diferencias para entender las líneas específicas de código que causan el conflicto.
Integra manualmente los cambios, asegurando que tanto tu nuevo algoritmo como los cambios del otro miembro del equipo se apliquen correctamente.
Ejecuta pruebas para confirmar que la funcionalidad de búsqueda funciona como se espera.
Ejemplo #2
Situación:
Dos desarrolladores añaden independientemente diferentes configuraciones a config.js.
Ambos intentan fusionar sus branches en main, lo que resulta en un conflicto.
Estrategia de Resolución:
Comunícate con el otro desarrollador para entender sus cambios.
Fusiona manualmente las configuraciones en config.js para incluir ambos conjuntos de cambios.
Valida que las configuraciones nuevas funcionen correctamente en diferentes entornos.
Ejemplo #3
Situación:
Estás trabajando en mejorar el diseño de un componente de la interfaz de usuario.
Otro desarrollador ha realizado algunos cambios de estilo en el mismo componente.
Estrategia de resolución:
Utiliza la herramienta de resolución de conflictos de tu sistema de control de versiones para ver ambos conjuntos de cambios.
Determina si los cambios de estilo son compatibles con tus mejoras de diseño.
Si son incompatibles, discute con el otro desarrollador para encontrar un compromiso o un enfoque unificado.
Prueba la interfaz de usuario final para asegurar que cumple con los requisitos funcionales y estéticos.
8. Referencias a Issues y Pull Requests
Referenciar adecuadamente los issues y solicitudes de pull requests en los commits es una práctica crucial en el desarrollo colaborativo. Esto vincula los cambios de código con las discusiones o tickets correspondientes, proporcionando contexto y facilitando el seguimiento del progreso y la justificación detrás de cada cambio.
Seguimiento de Issues/Pull requests: Utiliza los issues o pull requests (PR) proporcionados por tu plataforma de control de versiones (como GitHub, GitLab, etc.) en tus mensajes de commit.
Palabras Clave para Cerrar Issues: La mayoría de los sistemas de control de versiones admiten palabras clave como fixes, resolves o closes en los mensajes de commit que cierran automáticamente el problema referenciado cuando el commit se fusiona.
Consistencia: Sé consistente en cómo haces referencia a los issues o PRs. Un formato estándar ayuda a automatizar los procesos de seguimiento y reportes.
Claridad y Relevancia: Asegúrate de que las referencias sean directamente relevantes al commit. Evita hacer referencia a issues o PRs no relacionados.
Ejemplos de Referencias a Issues y Pull Requests
Ejemplo #1
Situación: Se reportó un error en el issue #123 donde el formulario de inicio de sesión se cae bajo ciertas condiciones.
Mensaje de commit: fix: Prevenir caída del formulario de inicio de sesión en casos específicos, resolves #123
Explicación: Aquí, el commit describe la corrección y referencia directamente con el número del issue.
Ejemplo #2
Situación: Solicitud de característica en el issue #456 para agregar una nueva funcionalidad de búsqueda.
Mensaje de commit: feat: Implementar búsqueda avanzada, closes #456
Explicación: En este caso, el commit no solo hace referencia al problema sino que también utiliza la palabra clave close para cerrar automáticamente el issue cuando el commit se fusione.
Ejemplo #3
Situación: Tienes un PR en curso #789 para refactorizar el esquema de la base de datos.
Mensaje de commit: refactor: Actualizar modelo de usuario al nuevo esquema, ver PR #789 para más detalles
Explicación: Este commit hace referencia al PR para contexto adicional, guiando a los revisores o a otros miembros del equipo al PR para una discusión completa y justificación de los cambios.
En resumen, la efectividad en la gestión de commits y branches, la resolución de conflictos y la precisa referencia a los issues y pull requests son los pilares de un desarrollo colaborativo exitoso. Estas prácticas no solo mantienen la calidad y claridad del código, sino que también facilitan la colaboración y el seguimiento de los cambios.
Si quieres profundizar en estas prácticas de desarrollo, te invito a suscribirte, ya que estaré compartiendo mis conocimientos y experiencias en el desarrollo de software a partir de hora, en este canal. ✨