Revertir automáticamente las confirmaciones que fallan en la compilación

44

Un colega mío me dijo que está pensando en hacer nuestro servidor de CI para compromete revert que no pasaron la construcción, por lo que el HEADen masteres siempre estable (como en la acumulación de pasar por lo menos).

¿Es esta una práctica recomendada o puede ser más problemático que simplemente dejarlo masterroto hasta que el desarrollador lo arregle?

Mi opinión es que revertir el commit hará más compleja la tarea de leer el commit y el arreglo (el desarrollador tendrá que revertir el revert y luego confirmar el arreglo, lo que también desordenará git log) y deberíamos dejar el commit y luego confirmar el fijar. Aunque veo algunas ventajas en tener masterestabilidad, esta reversión de confirmaciones fallidas no me convence.

editar: No importa si es mastero cualquier otra rama de desarrollo, pero la pregunta sigue siendo la misma: ¿debería el sistema CI revertir una confirmación que falló la compilación?

otra edición (larga): Ok, la estamos usando gitde una manera extraña. Creemos que el concepto de sucursales va en contra de CI real, porque comprometerse con una sucursal lo aísla de los otros desarrolladores y sus cambios, y agrega tiempo cuando tiene que reintegrar su sucursal y lidiar con posibles conflictos. Si todos se comprometen con masterestos conflictos, se reducen al mínimo y cada confirmación pasa todas las pruebas.

Por supuesto, esto lo obliga a presionar solo estable (o rompe la compilación) y programar con más cuidado para no romper la compatibilidad con versiones anteriores o alternar características al introducir nuevas características.

Hay compensaciones cuando se hace CI de esta o de esa manera, pero eso está fuera del alcance de la pregunta (vea la pregunta relacionada para esto). Si lo prefiere, puedo reformular la pregunta: un pequeño equipo de desarrolladores trabajan juntos en una rama de características. Si un desarrollador comete algo que rompe la compilación para esa rama, ¿debería el sistema de CI revertir el compromiso o no?

Carlos Campderrós
fuente
38
Las compilaciones fallidas nunca deberían haber llegado masterpara empezar. Para eso se utilizan las ramas de desarrollo y características. Esos cambios van entonces en algo así como una rama de integración donde puedes probar si todas las nuevas características de varios desarrolladores funcionarán juntas y solo si esto se prueba puede entrar en master. O al menos ese es un posible flujo de trabajo.
thorsten müller
1
@ thorstenmüller imagina bien que está en una rama de desarrollo que usan todos los desarrolladores. ¿Debería el sistema CI revertir las confirmaciones que fallan en la compilación?
Carlos Campderrós
77
Parece que estás usando git de una manera extraña. En general, las personas deberían estar trabajando en sus propios repositorios en sus propias sucursales, y solo presionar a main una vez que CI para su construcción personal verifique que los cambios estén bien.
Wilbert
44
> "estos conflictos se reducen al mínimo"; obtienes menos conflictos en el momento de la fusión, pero tienes problemas con las fusiones malas mucho más. La solución es fusionar continuamente de maestro a su sucursal como parte de su proceso, no no ramificar.
deworde
2
... ¿Por qué no hacer que las compilaciones que fallan no sean aceptadas en el maestro para empezar?
user253751

Respuestas:

56

Estaría en contra de hacer esto por las siguientes razones:

  • Cada vez que configura una herramienta automatizada para cambiar el código en su nombre , existe el riesgo de que se equivoque o de que surja una situación en la que lo necesite para dejar de hacer ese cambio (por ejemplo, la última versión de Google Mock tenía un error, por lo que no está fallando su código) y tiene que perder el tiempo reconfigurándolo. Además, siempre existe un pequeño riesgo de que la compilación falle debido a un error en el sistema de compilación, en lugar de un error en su código. Para mí, CI se trata de ganar confianza en que mi código es correcto; esto simplemente lo convertiría en otra fuente de posibles problemas por los que preocuparme.

  • Los tipos de errores que rompen "la compilación" deben ser errores tontos que tardan muy poco tiempo en solucionarse (como ha indicado en un comentario, esto es cierto para usted). Si los errores más sutiles y complicados llegan regularmente al maestro, entonces la solución correcta no es "solucionarlo más rápido", es tener más cuidado al revisar las ramas de características antes de que se fusionen.

  • Dejar al maestro sin construir durante unos minutos mientras el error se repara correctamente no hace daño a nadie. No es que el CEO revise personalmente el master y publique el código directamente a los clientes en cualquier momento aleatorio (al menos, con suerte, no sin su participación). En el caso muy poco probable que usted necesita para lanzar algo antes de poder corregir el error, a continuación, usted puede fácilmente tomar la decisión de volver manualmente antes de publicar.

Ixrec
fuente
1
Además, solo las compilaciones exitosas deberían desencadenar la creación de una "caída de compilación" que podría implementarse. Si una compilación falla, no debería haber una caída de compilación desplegable, por lo que no debería haber riesgo de que alguien publique un código incorrecto para los clientes.
Mark Freedman
1
Definitivamente hay otra opción que se usa y mejor que esta, creo, y que es de uso intensivo (la usamos en Twitter). no ponga compilaciones fallidas en master Y los errores tontos también son fáciles de arreglar. Vea mi respuesta completa a continuación.
Dean Hiller
26

Acordemos primero los términos.

Yo personalmente uso los términos Construcción Continua e Integración Continua para distinguir dos escenarios diferentes:

  • Compilación continua: una herramienta que comprueba periódicamente si el repositorio cambió desde la última compilación, y compila / prueba si lo hizo.
  • Integración continua: una herramienta que toma solicitudes de extracción y las valida contra la última cabeza antes de hacerlas visibles.

La última, Integración continua, significa que el repositorio que protege es siempre verde 1 : es estrictamente mejor.

Su pregunta solo tiene sentido para la construcción continua, por lo que responderé suponiendo que esta sea su configuración.

1 : Las causas ambientales también pueden arruinar una construcción, por ejemplo, una prueba con un año codificado (2015) puede comenzar a fallar en enero de 2016, un disco puede llenarse ... Y, por supuesto, existe la plaga de inestabilidad pruebas Altamente ignoro esos problemas aquí; de lo contrario nunca llegaremos a ninguna parte.


Si tiene una configuración de compilación continua, puede automatizar la reversión de confirmaciones que pueden haber roto la compilación, sin embargo, hay varias sutilezas.

  • En realidad, no puede eliminar los compromisos: es posible que otros compañeros de trabajo ya los hayan revisado y los rechazarán la próxima vez que intenten comprometerse. En cambio, una reversión debería estar cometiendo una diferencia inversa . Ah, y los compañeros de trabajo te odiarán por revertir su trabajo cuando era correcto, ya que tendrán que encontrar una manera de retrasarlo nuevamente ...
  • En realidad, no solo puede eliminar la última confirmación (es una combinación), sino que debe eliminar todas las confirmaciones ... hasta cierto punto. Por ejemplo, el último buen compromiso conocido (tenga cuidado al arrancar el sistema).
  • Debe pensar en causas externas (problemas ambientales) y evitar una configuración que revierta todo al día 0. Afortunadamente, volver al último buen compromiso conocido evita este problema.
  • Debe pensar que la última compilación válida conocida podría dejar de compilarse (problemas de entorno), en cuyo caso es probable que todas las confirmaciones adicionales se reviertan. Idealmente, en caso de falla, y antes de revertir, debería verificar la última compilación válida conocida y volver a probarla. Si pasa, revierta, de lo contrario, active una alerta.

Tenga en cuenta que con este sistema, en caso de una prueba inestable o un compañero de trabajo que a menudo comete basura, muchos buenos compromisos se revertirán. Tus compañeros de trabajo te odiarán.


Con suerte, mi historia de terror ha expuesto los problemas de permitir un repositorio roto y ahora implementará una tubería de integración continua adecuada donde las relaciones públicas nunca se envían directamente al repositorio, sino que se ponen en cola para fusionarse en una cola de trabajo, y se integran una a la vez ( o por roll-ups):

  • buscar el jefe del repositorio localmente
  • aplicar solicitud (es) de extracción
  • construir y probar
  • en caso de éxito, empuje al repositorio, de lo contrario, marque como fallido
  • pasar a las siguientes solicitudes

Habiendo intentado ambos, esto es estrictamente mejor.

Matthieu M.
fuente
2
De hecho, esta es la respuesta correcta: la solución correcta es evitar que los cambios malos lleguen a la rama maestra, no dejarlos aterrizar y luego tener que lidiar con la reversión.
Daniel Pryden
Creo que el problema aquí es que el interlocutor cree que los costos declarados de "aislarlo de los otros desarrolladores y sus cambios" superan los beneficios. Los costos declarados son el mayor peligro de fusiones no triviales cuanto más tiempo divergen dos personas. En mi opinión, el beneficio de estar aislado del código roto es obvio. El interlocutor quiere adoptar una estrategia "optimista", donde el código roto está disponible brevemente masterpara extraerlo, y luego solucionar esta situación una vez que las pruebas fallan. Todos los demás toman una estrategia "pesimista" como usted aconseja, y solo hacen que el código de aprobación esté disponible para extraer.
Steve Jessop
(donde por "disponible para extraer", quiero decir "extraer de master", que idealmente es algo que los desarrolladores pueden hacer a voluntad, pero para lograrlo debes retrasar las confirmaciones que llegan masterantes de que se prueben y aprueben. Si un desarrollador quiere el código de Cherry-pick no probado o probado y fallido también está bien, y el código está "disponible" en ese sentido, simplemente no es a lo que me refiero)
Steve Jessop
La solución correcta es evitar que los cambios incorrectos lleguen a CUALQUIER rama. Las confirmaciones fallidas nunca deben hacerse públicas, nunca.
Miles Rout
5

¿Es esta una mejor práctica o puede ser más problemático que simplemente dejar el maestro roto hasta que el desarrollador lo arregle?

Es problemático Una persona que decide que "la CABEZA maestra está rota; revertiré el cambio superior" es completamente diferente a que el sistema CI haga lo mismo.

Aquí hay algunas desventajas:

  • Los errores en el proceso de reversión automatizado arruinarán el repositorio;

  • Esto supone que un solo conjunto de cambios (el más alto) arruinó la compilación (lo que no es realista)

  • Los encargados del mantenimiento tendrán más trabajo que hacer para solucionar el problema, que solo investigar y comprometerse (también tendrán que mirar el historial inverso)

Creemos que el concepto de sucursales va en contra de CI real, porque comprometerse con una sucursal lo aísla de los otros desarrolladores y sus cambios, y agrega tiempo cuando tiene que reintegrar su sucursal y lidiar con posibles conflictos.

Esta creencia (ramas vs. CI) es incorrecta. Considere mantener una rama estable, donde confirme solo conjuntos de cambios probados por la unidad . El resto (sucursales de funciones y sucursales locales) debe ser responsabilidad de cada desarrollador y no parte de su política de CI de ninguna manera.

En las ramas de características, desea estar aislado de otros desarrolladores. Esto le permite:

  • realizar codificación exploratoria

  • experimentar con la base del código

  • realice confirmaciones parciales (confirme efectivamente el código que no funciona) para configurar puntos de respaldo (en caso de que lo arruine), para crear un historial de cambios más significativo (a través de mensajes de confirmación), y para respaldar su trabajo y cambiar completamente a otra cosa (en el tiempo que le lleva escribir "git commit && git checkout")

  • realizar tareas de baja prioridad que llevan mucho tiempo (por ejemplo, si desea realizar una refactorización que altere las 80 clases de la capa de datos: cambia dos por día, hasta que las cambie todas y el código compila (pero puede hacerlo) sin afectar a nadie hasta que pueda hacer una sola confirmación).

Si un desarrollador comete algo que rompe la compilación para esa rama, ¿debería el sistema de CI revertir el compromiso o no?

No debería La confirmación del código estable en su sucursal de CI es responsabilidad del emisor, no de un sistema automatizado.

utnapistim
fuente
2

Sugeriría usar un entorno Gerrit + Jenkins para mantener su rama maestra siempre en buena forma. Las personas envían su nuevo código a Gerrit, lo que desencadena un trabajo de Jenkins para extraer ese parche, compilaciones, pruebas, etc. Si a otros desarrolladores les gusta su parche y Jenkins completa su trabajo con éxito, Gerrit fusionará ese fragmento de código con su rama maestra.

Es un entorno similar descrito por @ brian-vandenberg

Además de mantener su sucursal en buen estado, también agrega un paso de revisión de código que mejora la calidad del código y el intercambio de conocimientos sobre su software.

[1] Jenkins https://jenkins-ci.org/

[2] Gerrit https://www.gerritcodereview.com/

Gustavo Coelho
fuente
1

El CI nunca debe alterar el historial de confirmación del repositorio.

La solución correcta aquí es que no se agreguen confirmaciones a la rama maestra si no se han probado y verificado.

¿Trabaja en ramas de características, hace que el CI se ejecute automáticamente en ellas y, si las compilaciones fallan, no las combine en master.

Puede tener una compilación adicional que pruebe fusiones si son una preocupación, ejecutando en la rama de características, y durante la fusión de compilación maestro / integración / lo que sea en la sucursal local, luego ejecutando pruebas.

Daenyth
fuente
1
Esto no responde la pregunta de ninguna manera. Si la compilación falla en una rama de características, ¿el CI debe revertir la confirmación?
Carlos Campderrós
¿Qué sucede si la compilación tiene éxito en la rama de características, pero falla después de la fusión?
Matthieu M.
@MatthieuM. fusionar es una confirmación, ¿debería el paso de CI que combina revertir la compilación?
Carlos Campderrós
@ CarlosCampderrós: ​​Yo personalmente nunca tendría una configuración que intente revertir los commits; demasiado complicado
Matthieu M.
Me dirigí a los comentarios.
Daenyth
1

Usamos Jenkins para nuestro servidor de compilación y utilizamos el modelo gatekeeper para enviar commits, donde una combinación de Jenkins y disparadores de commit (que aseguran que los revisores pares hayan hecho su trabajo) es el gatekeeper.

Los commits se envían indirectamente a través de un curl a Jenkins, donde clona el repositorio maestro, luego extrae los commits para fusionarse y realiza todas las compilaciones necesarias (para Linux / solaris). Si se completan todas las compilaciones, se envía el commit.

Esto evita muchos, si no todos, los problemas discutidos hasta ahora:

  • alteración de la historia
  • obtener el historial correcto si eres el desarrollador que tiene que arreglar la ruptura
  • la inestabilidad (en forma de compilaciones rotas) nunca se introduce

También nos permite hacer cumplir directamente otros requisitos, como las pruebas unitarias que se completan con éxito.

Brian Vandenberg
fuente
re: el voto negativo, ¿te importaría comentar lo que no te gustó de mi respuesta?
Brian Vandenberg
0

¿Cuántas veces has recibido ese correo electrónico automatizado diciendo que tu último commit rompió la compilación? ¿Cuántas veces está mal? Pero ahora tienes que ir a ver si realmente fuiste tú, o alguien más que hizo otro compromiso al mismo tiempo. O tal vez fue algo ambiental.

Si el sistema no lo sabe con certeza, entonces ciertamente no quiero automatizarlo.

Mohair
fuente
0

La pregunta formulada es defectuosa. Aunque respeto esta afirmación

"Creemos que el concepto de sucursales va en contra de CI real, porque comprometerse con una sucursal lo aísla de los otros desarrolladores y sus cambios"

Sin embargo, lo que debes hacer son estos pasos

  • trabaje en master si lo desea (eso está bien y siga sacando cambios de todos) PERO NO se comprometa a masterizar localmente
  • JUSTO ANTES de confirmar los cambios en master, cree una rama con submit_XXXXXX
  • haga que su compilación automatizada recoja todas las sucursales submit_XXX
  • Opción 1: crear saltos o fusionar saltos ... cambio rechazado y nunca aterriza en el maestro
  • Opción 2: la compilación funciona, jenkins empuja al maestro y lo actualiza

ENTONCES, lo que hacemos es poner un gancho git commit para evitar que TODOS se comprometan realmente a dominar. Funciona muy bien ... NO hay compilaciones rotas nunca y NO revoca confirmaciones del maestro tampoco.

luego Dean

Dean Hiller
fuente