Tengo un colega que dice que git pull
es dañino y se enoja cuando alguien lo usa.
El git pull
comando parece ser la forma canónica de actualizar su repositorio local. ¿El uso git pull
crea problemas? ¿Qué problemas crea? ¿Hay una mejor manera de actualizar un repositorio git?
git pull --rebase
establecer esta estrategia como predeterminada para nuevas sucursalesgit config branch.autosetuprebase
--rebase
indicador paragit pull
sincronizar local con remoto, luego reproduce los cambios locales además de los locales actualizados. Luego, cuando empuja, todo lo que está haciendo es agregar sus nuevas confirmaciones al final del control remoto. Bastante simple.Respuestas:
Resumen
De forma predeterminada,
git pull
crea confirmaciones de fusión que agregan ruido y complejidad al historial del código. Además,pull
hace que sea fácil no pensar en cómo sus cambios podrían verse afectados por los cambios entrantes.El
git pull
comando es seguro siempre que solo realice fusiones de avance rápido. Sigit pull
está configurado para hacer fusiones de avance rápido y cuando no es posible una fusión de avance rápido, Git saldrá con un error. Esto le dará la oportunidad de estudiar los commits entrantes, pensar en cómo podrían afectar sus commits locales y decidir el mejor curso de acción (fusionar, rebase, reset, etc.).Con Git 2.0 y más reciente, puede ejecutar:
para alterar el comportamiento predeterminado a solo avance rápido. Con las versiones de Git entre 1.6.6 y 1.9.x tendrás que acostumbrarte a escribir:
Sin embargo, con todas las versiones de Git, recomiendo configurar un
git up
alias como este:y usando en
git up
lugar degit pull
. Prefiero este alias sobregit pull --ff-only
porque:origin/*
ramas viejas que ya no existen aguas arriba.Problemas con
git pull
git pull
no está mal si se usa correctamente. Varios cambios recientes en Git han hecho que sea más fácil de usargit pull
correctamente, pero desafortunadamente el comportamiento predeterminado de un planogit pull
tiene varios problemas:git pull
Estos problemas se describen con mayor detalle a continuación.
Historia no lineal
Por defecto, el
git pull
comando es equivalente a ejecutargit fetch
seguido degit merge @{u}
. Si hay confirmaciones no aceleradas en el repositorio local, la parte degit pull
fusión crea una confirmación de fusión.No hay nada inherentemente malo en los compromisos de fusión, pero pueden ser peligrosos y deben tratarse con respeto:
Por supuesto, hay un momento y un lugar para las fusiones, pero comprender cuándo las fusiones deben y no deben usarse puede mejorar la utilidad de su repositorio.
Tenga en cuenta que el propósito de Git es hacer que sea fácil compartir y consumir la evolución de una base de código, no registrar con precisión el historial exactamente como se desarrolló. (Si no está de acuerdo, considere el
rebase
comando y por qué se creó). Las confirmaciones de fusión creadas porgit pull
no transmiten semántica útil a los demás, solo dicen que alguien más empujó al repositorio antes de que haya terminado con sus cambios. ¿Por qué esos compromisos de fusión si no son significativos para los demás y podrían ser peligrosos?Es posible configurar
git pull
una nueva versión en lugar de fusionar, pero esto también tiene problemas (discutido más adelante). En su lugar,git pull
debe configurarse para hacer solo fusiones de avance rápido.Reintroducción de Comisiones Rebajadas
Supongamos que alguien rebasa una rama y la fuerza la empuja. Esto generalmente no debería suceder, pero a veces es necesario (p. Ej., Eliminar un archivo de registro de 50GiB que se introdujo y se introdujo accidentalmente). La fusión realizada por
git pull
fusionará la nueva versión de la rama ascendente en la versión anterior que todavía existe en su repositorio local. Si presiona el resultado, las horquillas y las antorchas comenzarán a aparecer.Algunos pueden argumentar que el verdadero problema son las actualizaciones forzadas. Sí, generalmente es aconsejable evitar los empujes forzados siempre que sea posible, pero a veces son inevitables. Los desarrolladores deben estar preparados para lidiar con las actualizaciones de fuerza, porque a veces sucederán. Esto significa no fusionarse ciegamente en los viejos commits a través de un ordinario
git pull
.Modificaciones de directorio de trabajo sorpresa
No hay forma de predecir cómo se verá el directorio o índice de trabajo hasta que
git pull
se haga. Puede haber conflictos de fusión que tiene que resolver antes de que pueda hacer cualquier otra cosa, podría introducir un archivo de registro de 50GiB en su directorio de trabajo porque alguien lo presionó accidentalmente, podría cambiar el nombre de un directorio en el que está trabajando, etc.git remote update -p
(ogit fetch --all -p
) le permite ver los compromisos de otras personas antes de que decida fusionar o cambiar de base, lo que le permite formar un plan antes de tomar medidas.Dificultad para revisar los compromisos de otras personas
Suponga que está haciendo algunos cambios y alguien más quiere que revise algunas confirmaciones que acaba de enviar.
git pull
La operación de fusión (o rebase) modifica el directorio y el índice de trabajo, lo que significa que el directorio y el índice de trabajo deben estar limpios.Podrías usar
git stash
y luegogit pull
, pero ¿qué haces cuando termines de revisar? Para volver a donde estabas, debes deshacer la fusión creada porgit pull
y aplicar el alijo.git remote update -p
(ogit fetch --all -p
) no modifica el directorio o índice de trabajo, por lo que es seguro ejecutarlo en cualquier momento, incluso si tiene cambios organizados o no organizados. Puede pausar lo que está haciendo y revisar el compromiso de otra persona sin preocuparse por ocultar o terminar el compromiso en el que está trabajando.git pull
no te da esa flexibilidad.Rebasándose en una rama remota
Un patrón de uso común de Git es hacer una
git pull
para incorporar los últimos cambios seguidos de unagit rebase @{u}
para eliminar la confirmación de fusión que segit pull
introdujo. Es bastante común que Git tiene algunas opciones de configuración para reducir estos dos pasos a un solo paso a contargit pull
para realizar un rebase en lugar de una fusión (verbranch.<branch>.rebase
,branch.autosetuprebase
ypull.rebase
opciones).Desafortunadamente, si tiene una confirmación de fusión no acelerada que desea conservar (p. Ej., Una confirmación que fusiona una rama de función empujada
master
), ni un rebase-pull (git pull
conbranch.<branch>.rebase
set totrue
) ni un merge-pull (elgit pull
comportamiento predeterminado ) seguido de un rebase funcionará. Esto se debe a quegit rebase
elimina las fusiones (linealiza el DAG) sin la--preserve-merges
opción. La operación de rebase-pull no se puede configurar para preservar las fusiones, y una fusión-extracción seguida de ungit rebase -p @{u}
no eliminará la fusión causada por la fusión-extracción. Actualización: Git v1.8.5 agregadogit pull --rebase=preserve
ygit config pull.rebase preserve
. Esto segit pull
debe hacergit rebase --preserve-merges
después de recuperar las confirmaciones anteriores. (¡Gracias a funkaster por el aviso !)Limpieza de ramas eliminadas
git pull
no elimina las ramas de seguimiento remoto correspondientes a las ramas que se eliminaron del repositorio remoto. Por ejemplo, si alguien elimina una ramafoo
del repositorio remoto, aún veráorigin/foo
.Esto lleva a los usuarios a resucitar accidentalmente ramas muertas porque creen que todavía están activas.
Una mejor alternativa: usar en
git up
lugar degit pull
En lugar de
git pull
, recomiendo crear y usar el siguientegit up
alias:Este alias descarga todas las últimas confirmaciones de todas las ramas ascendentes (podando las ramas muertas) e intenta adelantar la rama local a la última confirmación en la rama ascendente. Si tuvo éxito, entonces no hubo compromisos locales, por lo que no hubo riesgo de conflicto de fusión. El avance rápido fallará si hay confirmaciones locales (no eliminadas), lo que le brinda la oportunidad de revisar las confirmaciones anteriores antes de tomar medidas.
Esto todavía modifica su directorio de trabajo de maneras impredecibles, pero solo si no tiene ningún cambio local. A diferencia
git pull
,git up
nunca lo llevará a un aviso esperando que solucione un conflicto de fusión.Otra opción:
git pull --ff-only --all -p
La siguiente es una alternativa al
git up
alias anterior :Esta versión de
git up
tiene el mismo comportamiento que elgit up
alias anterior , excepto:-p
argumento, que se pasa afetch
) que puede cambiar en futuras versiones de GitSi está ejecutando Git 2.0 o más reciente
Con Git 2.0 y versiones más recientes, puede configurar
git pull
para hacer solo fusiones de avance rápido de forma predeterminada:Esto hace
git pull
que actúe comogit pull --ff-only
, pero todavía no obtiene todos los commits ascendentes ni limpia lasorigin/*
ramas viejas , por lo que todavía prefierogit up
.fuente
git remote update -p
es equivalente agit fetch --all -p
. Tengo la costumbre de escribirgit remote update -p
porque alguna vezfetch
no tenía la-p
opción. En cuanto a la guía!
, vea la descripción dealias.*
ingit help config
. Dice: "Si la expansión del alias tiene el prefijo de un signo de exclamación, se tratará como un comando de shell".pull.ff
configuración que parece lograr lo mismo, sin alias.git up
suena como una alternativa interesante.git pull
.Mi respuesta, extraída de la discusión que surgió en HackerNews:
Me siento tentado de responder la pregunta utilizando la Ley de titulares de Betteridge: ¿Por qué se
git pull
considera perjudicial? No lo esfuente
git pull
. Sin embargo, podría entrar en conflicto con algunas prácticas dañinas, como querer reescribir la historia más de lo estrictamente necesario. Pero git es flexible, por lo que si desea usarlo de una manera diferente, hágalo. Pero eso es porque usted (bueno, @ Richard Hansen) quiere hacer algo inusual en git, y no porquegit pull
sea dañino.git rebase
y consideragit pull
perjudicial? De Verdad?git pull
sin la--rebase
opción es la dirección de fusión que crea. Cuando observa el diferencial, todos los cambios en esa fusión ahora pertenecen a la persona que realizó la extracción, en lugar de la persona que realizó los cambios. Me gusta un flujo de trabajo donde la fusión está reservada para dos ramas separadas (A -> B), por lo que la confirmación de fusión es clara de lo que se introdujo, y la reorganización está reservada para actualizarse en la misma rama (A remota> A local )No se considera dañino si está utilizando Git correctamente. Veo cómo te afecta negativamente dado tu caso de uso, pero puedes evitar problemas simplemente no modificando el historial compartido.
fuente
git pull
no hay ningún tipo de problema. Ramificar en git es barato.La respuesta aceptada reclama
pero a partir de Git 1.8.5 , que data de esa respuesta, puedes hacer
o
o
Los documentos dicen
Esta discusión previa tiene información y diagramas más detallados: git pull --rebase --preserve-merges . También explica por qué
git pull --rebase=preserve
no es lo mismo quegit pull --rebase --preserve-merges
, lo que no hace lo correcto.Esta otra discusión previa explica qué hace realmente la variante preservar-fusiones de rebase, y cómo es mucho más complejo que un rebase regular: ¿Qué hace exactamente "rebase --preserve-merges" de git (y por qué?)
fuente
Si va al antiguo repositorio de git, obtenga el alias que sugieren que es diferente. https://github.com/aanand/git-up
git config --global alias.up 'pull --rebase --autostash'
Esto funciona perfecto para mi.
fuente