¿Cuándo debo usar git pull --rebase?

806

Sé de algunas personas que usan git pull --rebasepor defecto y otras que insisten en nunca usarlo. Creo que entiendo la diferencia entre fusionar y rebase, pero estoy tratando de poner esto en el contexto de git pull. ¿Se trata simplemente de no querer ver muchos mensajes de confirmación de fusión, o hay otros problemas?

Jason Baker
fuente
1
Fuente para personas que aconsejan contra git pull --rebase? Rebase o git rebase es una actividad separada de git pull --rebase!
przemo_li

Respuestas:

584

Deberías usar git pull --rebasecuando

  • sus cambios no merecen una rama separada

De hecho, ¿por qué no entonces? Es más claro y no impone una agrupación lógica en sus confirmaciones.


Ok, supongo que necesita alguna aclaración. En Git, como probablemente ya sabes, te animamos a ramificarte y fusionarte. Su rama local, en la que extrae los cambios, y la rama remota son, en realidad, diferentes ramas, y git pullse trata de fusionarlas. Es razonable, ya que presiona con poca frecuencia y generalmente acumula varios cambios antes de que constituyan una característica completa.

Sin embargo, a veces, por cualquier motivo, cree que sería mejor si estos dos, remoto y local, fueran una sola rama. Como en SVN. Es aquí donde git pull --rebaseentra en juego. Ya no se fusiona, se compromete en la parte superior de la rama remota . De eso se trata en realidad.

Si es peligroso o no, es la cuestión de si está tratando la rama local y remota como una cosa inseparable. A veces es razonable (cuando sus cambios son pequeños, o si está al comienzo de un desarrollo robusto, cuando los pequeños compromisos introducen cambios importantes). A veces no lo es (cuando normalmente crearías otra rama, pero eras demasiado flojo para hacerlo). Pero esa es una pregunta diferente.

P Shved
fuente
17
Creo que es útil cuando trabaja en la misma rama, pero puede cambiar su estación de trabajo. Tiendo a comprometerme e impulsar mis cambios desde una estación de trabajo, luego hacer rebase en la otra y seguir trabajando en la misma rama.
Pablo Pazos
11
Es una práctica recomendada útil configurar Git para rebase automático al extraer con git config --global pull.rebase preserve (preservar dice además de habilitar rebase, para tratar de preservar fusiones si ha realizado alguna localmente).
Colin D Bennett
2
No estoy de acuerdo en que debe usar pull --rebase solo cuando trabaje en una rama. Debe usarlo todo el tiempo, a menos que sea imposible debido a alguna otra circunstancia.
Tomáš Fejfar
@P Shved ... 'Sin embargo, a veces, por cualquier razón, piensas que en realidad sería mejor si estos dos, remotos y locales, fueran una rama' ... ¿se puede hacer esto? que en el entorno local, puedo tener mi rama y un espejo de rama remoto como origen / maestro. ¿Puede proporcionar entradas aquí?
Mandroid
736

Me gustaría ofrecer una perspectiva diferente sobre lo que realmente significa "git pull --rebase", porque a veces parece perderse.

Si alguna vez ha usado Subversion (o CVS), puede estar acostumbrado al comportamiento de "svn update". Si tiene cambios para confirmar y el compromiso falla porque los cambios se han realizado en sentido ascendente, "svn update". Subversion procede fusionando los cambios aguas arriba con los suyos, lo que puede generar conflictos.

Lo que Subversion acaba de hacer es esencialmente "pull --rebase". El acto de reformular sus cambios locales para que sean relativos a la versión más nueva es la parte de "rebase". Si había hecho "svn diff" antes del intento de confirmación fallido, y luego compara el diff resultante con la salida de "svn diff", la diferencia entre los dos diffs es lo que hizo la operación de rebase.

La principal diferencia entre Git y Subversion en este caso es que en Subversion, "sus" cambios solo existen como cambios no confirmados en su copia de trabajo, mientras que en Git tiene confirmaciones reales localmente. En otras palabras, en Git has bifurcado la historia; su historia y la historia aguas arriba han divergido, pero usted tiene un antepasado común.

En mi opinión, en el caso normal de que su rama local simplemente refleje la rama ascendente y realice un desarrollo continuo en ella, lo correcto es siempre "--rebase", porque eso es lo que está haciendo semánticamente . Usted y otros están pirateando la historia lineal prevista de una rama. El hecho de que alguien más haya empujado un poco antes de su intento de empuje es irrelevante, y parece contraproducente que cada accidente de tiempo resulte en fusiones en la historia.

Si realmente siente la necesidad de que algo sea una rama por cualquier razón, esa es una preocupación diferente en mi opinión. Pero a menos que tenga un deseo específico y activo de representar sus cambios en forma de fusión, el comportamiento predeterminado debería, en mi opinión, ser "git pull --rebase".

Considere a otras personas que necesitan observar y comprender la historia de su proyecto. ¿Desea que la historia esté plagada de cientos de fusiones por todo el lugar, o desea solo las pocas fusiones seleccionadas que representan fusiones reales de esfuerzos de desarrollo divergentes intencionales?

scode
fuente
18
@MarceloCantos Para ser claros, no estoy diciendo que git (la herramienta) deba volver a crear una base predeterminada. Eso sería peligroso ya que un rebase esencialmente destruye la historia. Estoy diciendo que, en términos de flujo de trabajo, cuando no tiene la intención de bifurcarse y simplemente está cortando alguna bifurcación en la que otras personas también están trabajando, "git pull --rebase" debería ser el comportamiento predeterminado del usuario.
scode
1
¿Estás diciendo que uno no debería git config --global branch.autosetupmerge always?
Marcelo Cantos
99
@MarceloCantos No, no lo soy;) Personalmente, dejaría el autoajuste como valor predeterminado de verdadero (si me estoy fusionando de nuevo y cuarto entre ramas que no sean <-> local remoto, me gustaría que sea explícito). Solo digo que, como humano, siempre uso "git pull --rebase" como parte de mi flujo de trabajo normal de "agarrar lo último en rama maestra", porque nunca quiero crear una confirmación de fusión a menos que esté bifurcando explícitamente.
puntaje
99
+1 @scode. Después de muchas horas dolorosas de lidiar con la pregunta de rebase / fusionar, finalmente aquí hay una respuesta que lo aclara .
AgileYogi
10
Esta respuesta es solo un intento de adaptar los usuarios de sistemas de control de versiones no distribuidos a Git en lugar de darles la oportunidad de comprender adecuadamente los beneficios de tener sucursales adecuadas.
Alexey Zimarev
211

Quizás la mejor manera de explicarlo es con un ejemplo:

  1. Alice crea la rama de tema A y trabaja en ella
  2. Bob crea una rama de tema B no relacionada y trabaja en ella
  3. Alice lo hace git checkout master && git pull. El maestro ya está actualizado.
  4. Bob lo hace git checkout master && git pull. El maestro ya está actualizado.
  5. Alice hace git merge topic-branch-A
  6. Bob hace git merge topic-branch-B
  7. Bob lo hace git push origin masterantes de Alice
  8. Alice lo hace git push origin master, lo cual es rechazado porque no es una fusión de avance rápido.
  9. Alice mira el registro de origen / maestro y ve que el compromiso no está relacionado con el de ella.
  10. Alice hace git pull --rebase origin master
  11. El commit de fusión de Alice se desenrolla, el commit de Bob se retira y el commit de Alice se aplica después del commit de Bob.
  12. Alice lo hace git push origin master, y todos están felices de no tener que leer una confirmación de fusión inútil cuando miran los registros en el futuro.

Tenga en cuenta que la rama específica en la que se fusiona es irrelevante para el ejemplo. Master en este ejemplo podría ser fácilmente una rama de lanzamiento o una rama de desarrollo. El punto clave es que Alice y Bob están fusionando simultáneamente sus sucursales locales en una sucursal remota compartida.

Encuesta de Cody
fuente
2
Agradable. Tiendo a ser explícito y git co master && git pull; git checkout topic-branch-A; git rebase master; git checkout master; git merge topic-branch-A; git push origin masterrepito si el impulso de otro para dominar ocurrió antes que el mío. Aunque puedo ver las sucintas ventajas en tu receta.
HankCa
Buena explicación @Cody Poll
Rajanikanta Pradhan
148

Creo que deberías usarlo git pull --rebasecuando colaboras con otros en la misma rama. Está en su ciclo de trabajo → compromiso → trabajo → compromiso, y cuando decide empujar su trabajo, su empuje es rechazado, porque ha habido trabajo paralelo en la misma rama. En este punto siempre hago un pull --rebase. No uso squash (para aplanar los commits), pero reescribo para evitar los commits adicionales de fusión.

A medida que aumenta su conocimiento de Git, se encuentra mirando mucho más la historia que con cualquier otro sistema de control de versiones que haya utilizado. Si tiene un montón de pequeños compromisos de fusión, es fácil perder el enfoque de la imagen más grande que está sucediendo en su historia.

Esta es en realidad la única vez que hago un rebase (*), y el resto de mi flujo de trabajo se basa en la fusión. Pero siempre que sus confirmadores más frecuentes hagan esto, la historia se verá mucho mejor al final.

(*) Mientras enseñaba un curso de Git, hice que un estudiante me arrestara por esto, ya que también abogaba por rebasar ramas de características en ciertas circunstancias. Y había leído esta respuesta;) Tal rebase también es posible, pero siempre tiene que ser de acuerdo con un sistema preestablecido / acordado, y como tal no debe "siempre" aplicarse. Y en ese momento generalmente tampoco lo hago pull --rebase, que es de lo que se trata la pregunta;)

krosenvold
fuente
2
seguramente uno puede escribir un script para ocultar las confirmaciones de fusión del registro
hasen
3
Las fusiones también pueden contener diferencias, lo que significa que no es del todo trivial
krosenvold
99
@hasen j Sí, pero el CONTENIDO de esas fusiones puede importar
krosenvold
Esta respuesta es vaga y obstinada en comparación con la respuesta elegida: ¿qué quiere decir exactamente con "la misma rama"? Sin embargo, hay algunos puntos buenos que no están en la respuesta elegida.
iwein
1
La vaguedad en torno a la "rama" es bastante intencional, ya que hay muchas maneras de usar referencias; "línea de trabajo" es solo una opción.
krosenvold 05 de
49

No creo que haya una razón para no usarlo pull --rebase: agregué código a Git específicamente para permitir que mi git pullcomando rebase siempre contra los commits ascendentes.

Al mirar a través de la historia, nunca es interesante saber cuándo el chico / chica que trabaja en la función se detuvo para sincronizarse. Puede ser útil para el chico / chica mientras lo está haciendo, pero para eso reflogestá. Solo agrega ruido para todos los demás.

Dustin
fuente
2
"Al mirar a través de la historia, nunca es interesante saber cuándo el tipo que trabaja en la función se detuvo para sincronizar". / pero ¿eso no significa que esas confirmaciones intermedias son probablemente compilaciones rotas?
eglasius
10
Sí, y tampoco son un "estado completo". Por eso no los queremos. Quiero saber qué quería, no cómo llegó allí.
Dustin
44
Si pull --rebasesiempre debe usarse, ¿por qué no lo hace pullpor defecto?
Straya
2
Me temo que tendrás que formarte tu propia opinión. Tengo varias cosas en mi .gitconfigpara hacer que algunas de las opciones hagan lo correcto. Creo que git rebase hace lo incorrecto de manera predeterminada, al igual que git tag, etc. Si no está de acuerdo, no necesita justificar su opinión.
Dustin
8
Eso parece un buen consejo si sacas de "aguas arriba", digamos desde master, y si la rama a la que llegas no se ha hecho pública (todavía). Si, por el contrario, masterpasa de una rama de características a otra, es más como al revés: nunca hay una razón para usar --rebase, ¿verdad? Esa podría ser la razón por la cual no es por defecto. Encontré que las bases son cómo deben pasar los cambios desde la parte superior de la jerarquía hacia abajo y las fusiones son cómo fluyen hacia arriba. derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase
jolvi
38

Solo recuerda:

  • pull = buscar + fusionar
  • pull --rebase = buscar + rebase

Por lo tanto, elija la forma en que desea manejar su sucursal.

Será mejor que sepa la diferencia entre fusionar y rebase :)

leohxj
fuente
9

Creo que se reduce a una preferencia personal.

¿Quieres ocultar tus errores tontos antes de impulsar tus cambios? Si es así, git pull --rebasees perfecto. Le permite luego aplastar sus commits a unos pocos (o uno) commits. Si tiene fusiones en su historial (no eliminado), no es tan fácil hacer git rebaseuno más tarde.

Personalmente, no me importa publicar todos mis errores tontos, por lo que tiendo a fusionar en lugar de rebase.

Hasen
fuente
8
Nota para cualquiera que vea esta pregunta: esta respuesta es completamente irrelevante para la pregunta "¿cuándo debo usar git pull --rebase?"
therealklanni
3
@therealklanni Edité la respuesta para que quede más claro cómo es relevante para la pregunta (con suerte sin destruir la intención).
Paŭlo Ebermann
Compartir un registro de trabajo sucio y desestructurado no es un esfuerzo honesto, es solo pereza. Estás perdiendo el tiempo de las personas al hacer que te persigan a través de tu madriguera de desarrollo y depuración; darles el resultado, no las divagaciones.
krystah
8

git pull --rebasepuede ocultar una reescritura del historial de un colaborador git push --force. Recomiendo usar git pull --rebase solo si sabe que olvidó presionar sus confirmaciones antes de que otra persona haga lo mismo.

Si no confirmó nada, pero su espacio de trabajo no está limpio, justo git stashantes de hacerlo git pull. De esta forma, no reescribirá su historial en silencio (lo que podría dejar en silencio parte de su trabajo).

Habax
fuente