what explicado does develop and git git-rebase

explicado - git rebase head master



git pull--rebase--preserve-merges (2)

Técnicamente, y afirmo que esto es un poco estúpido de git, el script de pull (es un script de shell) debería hacer esto por ti, tienes que ejecutar git pull --rebase=preserve lugar de intentar usar git pull --rebase --preserve-merges . (O, como branch. name .rebase en un comentario sobre la respuesta de Vlad Nikitin , puedes configurar la branch. name .rebase para preserve y obtener el mismo efecto automáticamente).

En otras palabras, nunca debe ejecutar git pull --rebase --preserve-merges cuando pasa (incorrectamente) pasa --preserve-merges al paso de fetch , en lugar de al paso de merge -o-- rebase . Sin embargo, puedes ejecutar git pull --rebase=preserve .

La cuestión de cuándo (y si) usar cualquier tipo de rebase, si se trata de preservar la fusión o no, es más una cuestión de opinión. Lo que significa que, en primer lugar, no va bien en el stackoverflow. :-)

Sin embargo, haré una reclamación aquí: solo debería volver a hacer un caso si sabe (en un sentido general) lo que está haciendo, 1 y si sabe lo que está haciendo, es probable que prefiera un cambio de fase para preservar la fusión. como regla general, aunque para el momento en que haya decidido que la rebasada es una buena idea, probablemente encontrará que un historial que tiene sus propios puntos de fusión y fusión integrados no es necesariamente el "historial reescrito final" correcto.

Es decir, si es apropiado hacer una rebase, es al menos bastante probable que la historia que se va a rebasar sea en sí misma lineal, por lo que la cuestión de preservar contra aplanar es discutible de todos modos.

Editar: añadir dibujo

Aquí hay un dibujo de parte de un gráfico de compromiso, que muestra dos ramas con nombre, mainline y experiment . La base común para la mainline y la experiment es el nodo de confirmación A , y la mainline tiene una confirmación G que no está en la rama de experiment prueba:

...--o--A-------------G <-- mainline / / .-C-. B E--F <-- experiment /_D_/

Sin embargo, tenga en cuenta que la rama del experiment tiene una rama y combinación: la base para estas dos ramas es B , una rama contiene el compromiso C y la otra rama mantiene el compromiso D Estas dos ramas (sin nombre) se reducen a un solo hilo de desarrollo en la combinación de mezcla E , y luego la confirmación F sienta sobre la confirmación de combinación y es la punta del experiment de la rama.

Esto es lo que sucede si estás experiment y ejecutando git rebase mainline :

$ git rebase mainline First, rewinding head to replay your work on top of it... Applying: B Applying: C Applying: D Applying: F

Aquí está lo que está ahora en el gráfico de confirmación:

...--o--A--G <-- mainline / B''-C''-D''-F'' <-- experiment

La "rama estructural" que solía estar allí en el experiment rama se ha ido. La operación de rebase copió todos los cambios que había hecho en las confirmaciones B , C , D y F ; estos se convirtieron en los nuevos compromisos B'' , C'' , D'' y F'' . (Commit E fue una combinación pura sin cambios y no requirió copia. No he probado lo que sucede si reagrupo una combinación con cambios incorporados, ya sea para resolver conflictos o, como algunos lo llaman, una "combinación maligna".)

Por otro lado, si hago esto:

$ git rebase --preserve-merges mainline [git grinds away doing the rebase; this takes a bit longer than the "flattening" rebase, and there is a progress indicator] Successfully rebased and updated refs/heads/experiment.

Me sale este gráfico en su lugar:

...--o--A--G <-- mainline / / .-C''. B'' E''-F'' <-- experiment /_D''/

Esto ha preservado la fusión y, por lo tanto, la "ramificación interna" del experiment . ¿Es bueno eso? ¿Malo? ¿Indiferente? Lea la (muy larga) nota al pie!

1 Es una buena idea aprender "qué hace la rebase" de todos modos, lo que en git (¡ay!) Requiere aprender también "cómo lo hace", al menos en un nivel medio. Básicamente, rebase hace copias de (los cambios de sus compromisos anteriores), que luego aplica a los compromisos (suyos o de otra persona), haciendo que "parezca" que hizo el trabajo en algún otro orden. Un ejemplo simple: dos desarrolladores, digamos Alice y Bob, están trabajando en la misma rama. Digamos que Marketing ha solicitado una característica llamada Strawberry, y tanto Alice como Bob están haciendo algunos trabajos para implementar la strawberry , ambos en una rama llamada strawberry .

Alice y Bob ejecutan git fetch para traer strawberry de origin .

Alice descubre que el archivo abc necesita algunos cambios para prepararse para la nueva función. Ella escribe eso y se compromete, pero no empuja todavía.

Bob escribe una descripción de la nueva característica, que cambia el archivo README , pero no tiene otro efecto. Bob comete su cambio y empuja.

Alice luego actualiza el archivo para proporcionar la característica real. Ella escribe y confirma (por separado) eso, y ahora está lista para presionar. Pero, oh no, Bob la venció:

$ git push origin strawberry ... ! [rejected] strawberry -> strawberry (non-fast-forward)

Luego, Alice debería buscar los cambios y mirarlos (no solo fusionar o reajustar a ciegas):

$ git fetch ... $ git log origin/strawberry

(o usando gitk o lo que sea, tiendo a usar git lola mí mismo, y git show las confirmaciones individuales si es necesario).

Ella puede ver en esto que Bob solo cambió el README , por lo que sus cambios definitivamente no se ven afectados de ninguna manera. En este punto, puede decir que es seguro volver a ajustar sus cambios en origin/strawberry :

$ git rebase origin/strawberry

(tenga en cuenta que no hay fusiones que preservar), lo que hace que parezca (en términos de historial de git) que esperó a que Bob actualizara la documentación, y solo entonces realmente comenzó a implementar los cambios, que aún se dividen en dos confirma para que sea fácil saber, más tarde, si el cambio al archivo abc rompió algo más. Sin embargo, esas dos confirmaciones separadas ahora son adyacentes, por lo que es fácil decir, más tarde, que el punto del cambio a abc fue habilitar el cambio a la feat archivo. Y dado que el cambio a README es lo primero, es aún más claro que este fue el punto del cambio para abc . No es que sea difícil decirlo, incluso si Alice lo hiciera:

$ git merge origin/strawberry

en cambio, aunque eso crea una confirmación de fusión cuyo único punto parece ser "Alicia comenzó en abc antes de que Bob terminara de actualizar README , y terminó después", lo cual no es realmente útil.

En casos más complejos, donde Bob hizo algo más que actualizar la documentación, Alice podría encontrar que es mejor reorganizar sus propios compromisos (probablemente más de dos en este caso) en un nuevo historial lineal diferente, de modo que algunos de los cambios de Bob ( esta vez, probablemente más de un compromiso) están "en el medio", por ejemplo, como si hubieran cooperado en tiempo real (y quién sabe, tal vez lo hicieron). O podría encontrar que es mejor mantener sus cambios como una línea de desarrollo separada que se fusiona, quizás incluso más de una vez, con los cambios de Bob.

Todo es una cuestión de lo que proporcionará la información más útil para alguien (posiblemente Alice y Bob, posiblemente otros desarrolladores) en el futuro, cuando sea necesario volver atrás y ver el (aparente, si es rebasado, o actual si no es) secuencia de eventos. A veces, cada compromiso individual es información útil. A veces es más útil reorganizar y combinar compromisos, o eliminar algunos compromisos por completo: por ejemplo, cambios que demostraron ser una mala idea. (¡Pero considera dejarlos solo por el valor de señalar que "esto fue una mala idea, así que no lo intentes de nuevo en el futuro" también!)

Versión corta: ¿Necesita preservar-fusionar solo si se fusionó explícitamente después de realizar un compromiso local? ¿Qué sucede exactamente de otra manera? ¿Vuelve a aplicar su código comprometido a la rama fusionada?

Explique cuándo es útil git pull --rebase --preserve-merges frente a un git pull --rebase regular git pull --rebase ? Leí sobre un problema con git pull --rebase aquí: http://notes.envato.com/developers/rebasing-merge-commits-in-git/ Esto podría causar que los cambios de código se dupliquen.

Leí aquí: ¿ Cuándo `git pull --rebase` me meterá en problemas?

Eso solo sucede si básicamente se vuelve a generar una base después de que se hayan enviado algunas confirmaciones.

Así que no estoy seguro de entender cuándo necesitaría git pull --rebase --preserve-merges y si alguna vez es malo usar vs. git pull --rebase .