¿Por qué tantos proyectos prefieren "git rebase" en lugar de "git merge"?

64

Una de las ventajas de usar un DVCS es el flujo de trabajo edit-commit-merge (sobre edit-merge-commit a menudo aplicado por un CVCS). Permitir que cada cambio único se registre en el repositorio independiente de las fusiones garantiza que el DAG refleja con precisión el verdadero pedigrí del proyecto.

¿Por qué tantos sitios web hablan sobre el deseo de "evitar la combinación de combinaciones"? ¿La fusión previa o posterior de la fusión no hace que sea más difícil aislar regresiones, revertir cambios pasados, etc.?

Punto de aclaración: El comportamiento predeterminado para un DVCS es crear confirmaciones de fusión. ¿Por qué tantos lugares hablan de un deseo de ver un historial de desarrollo lineal que oculta estos compromisos de fusión?

    
pregunta Jace Browning 18.11.2013 - 19:15

6 respuestas

62

La gente quiere evitar las combinaciones de combinaciones porque hace que el registro sea más bonito. Seriamente. Parece que los registros centralizados con los que crecieron, y localmente pueden hacer todo su desarrollo en una sola rama. No hay beneficios aparte de esos aspectos estéticos, y hay varios inconvenientes además de los que mencionó, como hacer que sea propenso a los conflictos el obtener directamente de un colega sin pasar por el servidor "central".

    
respondido por el Karl Bielefeldt 18.11.2013 - 20:30
44

En dos palabras: git bisect

Un historial lineal le permite identificar la fuente real de un error.

Un ejemplo. Este es nuestro código inicial:
def bar(arg=None):
    pass

def foo():
    bar()

La rama 1 realiza algunas refacciones de manera que arg ya no es válido:

def bar():
    pass

def foo():
    bar()

La rama 2 tiene una nueva función que necesita usar arg :

def bar(arg=None):
    pass

def foo():
    bar(arg=1)

No habrá conflictos de combinación, sin embargo, se ha introducido un error. Afortunadamente, este en particular quedará atrapado en el paso de la compilación, pero no siempre tenemos tanta suerte. Si el error se manifiesta como un comportamiento inesperado, en lugar de un error de compilación, es posible que no lo encontremos durante una semana o dos. En ese momento, git bisect al rescate!

Oh mierda. Esto es lo que ve:

(master: green)
|             \_________________________
|                \                      \
(master: green)  (branch 1: green)     (branch 2: green)
|                 |                     |
|                 |                     |
(master/merge commit: green)            |
|                         ______________/
|                        /
(master/merge commit: red)
|
...days pass...
|
(master: red)

Entonces, cuando enviamos git bisect para encontrar el commit que rompió la compilación, se va a identificar un commit de fusión. Bueno, eso ayuda un poco, pero esencialmente apunta a un paquete de confirmaciones, no a una sola. Todos los ancestros son verdes. Por otro lado, con la rebasación, obtienes un historial lineal:

(master: green)
|
(master: green)
|
(all branch 1 commits: green)
|
(some branch 2 commits: green)
|
(branch 2 commit: red)
|
(remaining branch 2 commits: red)
|
...days pass...
|
(master: still red)

Ahora, git bisect apuntará a la característica de confirmación exacta que rompió la compilación. Idealmente, el mensaje de confirmación explicará lo que se pretendía lo suficientemente bien como para hacer otro refactor y corregir el error de inmediato.

El efecto solo se agrava en proyectos grandes cuando los mantenedores no escribieron todo el código, por lo que no necesariamente recuerdan por qué se realizó un compromiso determinado / para qué era cada rama. Por lo tanto, es una gran ayuda localizar con precisión el compromiso exacto (y luego poder examinar los compromisos a su alrededor).

Dicho esto, yo (actualmente) todavía prefiero la fusión. Al volver a colocar en una rama de lanzamiento, obtendrá su historial lineal para usarlo con git bisect , al tiempo que conservará el historial real para el trabajo diario.

    
respondido por el Izkata 19.11.2013 - 05:20
16

En resumen, porque la fusión es a menudo otro lugar para que algo salga mal, y solo tiene que ir mal una vez para que la gente tenga mucho miedo de lidiar con eso nuevamente (una vez mordida dos veces tímida, por así decirlo). >

Entonces, digamos que estamos trabajando en una nueva pantalla de administración de cuentas, y resulta que hay un error descubierto en el flujo de trabajo de la nueva cuenta. De acuerdo, tomamos dos rutas separadas: finaliza la Administración de cuentas y yo soluciono el error con Cuentas nuevas. Como los dos estamos tratando con cuentas, hemos estado trabajando con un código muy similar, tal vez incluso tuvimos que ajustar las mismas piezas de código.

Ahora, en este momento tenemos dos versiones diferentes pero completamente operativas de software. Ambos nos hemos comprometido con nuestros cambios, ambos hemos probado debidamente nuestro código y, de manera independiente, tenemos mucha confianza en que hemos hecho un trabajo increíble. ¿Y ahora qué?

Bueno, es hora de fusionarse, pero ... mierda, ¿qué pasa ahora? Es muy posible que pasemos de dos conjuntos de software a uno, un software malicioso y unificado, roto de forma incorrecta, en el que la administración de su cuenta no funciona y las cuentas nuevas se rompen, y ni siquiera sé si el antiguo error sigue ahí. .

Tal vez el software era inteligente y dijo que había un conflicto e insistió en que le brindáramos orientación. Bueno, mierda, me siento a hacerlo y veo que has agregado un código complejo que no entiendo de inmediato. Creo que está en conflicto con los cambios que he hecho ... le pregunto, y cuando obtiene un minuto, comprueba y ve mi código que no comprende. Uno o ambos tenemos que tomarnos el tiempo para sentarnos, sacar una combinación adecuada y, posiblemente, volver a probar todo el asunto para asegurarnos de que no lo rompimos.

Mientras que otros 8 tipos están cometiendo código como los sádicos que son, hice algunas correcciones de errores pequeñas y las envié antes de que supiera que teníamos un conflicto de fusión, y parece que es un buen momento para tomar un descanso. y tal vez usted está fuera por la tarde o atascado en una reunión o lo que sea. Tal vez debería tomar unas vacaciones. O cambiar de carrera.

Y así, para escapar de esta pesadilla, algunas personas se han vuelto muy temerosas del compromiso (¿qué más hay de nuevo, en serio?). Naturalmente, somos reacios a los riesgos en situaciones como esta, a menos que pensemos que apestamos y vamos a arruinarlo de todos modos, en cuyo caso las personas comienzan a actuar con un abandono imprudente. sigh

Así que ahí tienes. Sí, los sistemas modernos están diseñados para aliviar este dolor, y se supone que es capaz de retroceder y rebase y desbastar fácilmente, de forma gratuita y de hanglide y todo eso.

Pero es mucho más trabajo, y solo queremos presionar el botón del microondas y tener una comida de 4 platos antes de que tengamos tiempo de encontrar un tenedor, y todo parece muy insatisfactorio: el código es trabajo, es productivo, es significativo, pero manejando con gracia una combinación que solo no cuenta.

Como regla general, los programadores tienen que desarrollar una gran memoria de trabajo y luego tienden a olvidar de inmediato todos los nombres de basura y variables y el alcance cuando terminan el problema, y manejan un conflicto de combinación (o peor aún, una fusión mal manejada) es una invitación a que se te recuerde tu mortalidad.

    
respondido por el BrianH 18.11.2013 - 19:38
4

Rebasar proporciona un punto de derivación móvil que simplifica el proceso de devolver los cambios a la línea de base. Esto le permite tratar una rama de larga duración como si fuera un cambio local. Sin rebasar, las sucursales acumulan cambios desde la línea de base que se incluirán en los cambios que se fusionarán nuevamente a la línea de base.

La fusión deja su línea de base en el punto de derivación original. Si combina algunas semanas de cambios desde la línea de la que se bifurcó, ahora tiene muchos cambios desde su punto de bifurcación, muchos de los cuales estarán en su línea de base. Esto hace que sea difícil identificar sus cambios en su sucursal. Volver a colocar los cambios en la línea de base puede generar conflictos no relacionados con los cambios. En el caso de conflictos, es posible impulsar cambios inconsistentes. Las fusiones continuas requieren un esfuerzo de gestión, y es relativamente fácil perder los cambios.

Rebase mueve su punto de bifurcación a la última revisión de su línea de base. Cualquier conflicto que encuentre será solo por su (s) cambio (s). Empujar cambios es mucho más simple. Los conflictos se resuelven en la sucursal local haciendo una rebase adicional. En el caso de empujes conflictivos, el último para impulsar su cambio deberá resolver el problema con su cambio.

    
respondido por el BillThor 19.11.2013 - 03:31
3

Las herramientas automatizadas están mejorando para asegurarse de que el código de fusión se compile y ejecute, evitando así conflictos sintácticos , pero no pueden garantizar la ausencia de conflictos lógicos . Puede ser introducido por fusiones. Por lo tanto, una fusión 'exitosa' te da una sensación de falsa confianza, cuando en realidad no garantiza nada, y tienes que rehacer todas tus pruebas.

El problema real con la ramificación y la fusión, como lo veo, es que patea la lata proverbial en el camino. Te permite decir "Trabajaré en mi pequeño mundo" durante una semana y resolveré cualquier problema que surja más tarde. Pero reparar errores siempre es más rápido / barato cuando están frescos. Para cuando todas las ramas del código empiecen a fusionarse, es posible que ya hayas olvidado algunos de los matices de las cosas que se hicieron.

Tome los dos problemas mencionados juntos y es posible que se encuentre en una situación en la que es más simple y más fácil hacer que todos trabajen desde el mismo tronco y resuelvan los conflictos a medida que surjan, incluso si hacen que el desarrollo activo sea un poco más lento. .

    
respondido por el MrFox 18.11.2013 - 20:49
0

Un punto relevante adicional es este: con la rebasación puedo elegir fácilmente o revertir una característica en mi versión de lanzamiento.

    
respondido por el Bruno Schäpper 28.01.2018 - 18:07

Lea otras preguntas en las etiquetas