Tengo un colega que dice que git pulles dañino y se enoja cuando alguien lo usa.
El git pullcomando parece ser la forma canónica de actualizar su repositorio local. ¿El uso git pullcrea problemas? ¿Qué problemas crea? ¿Hay una mejor manera de actualizar un repositorio git?

git pull --rebaseestablecer esta estrategia como predeterminada para nuevas sucursalesgit config branch.autosetuprebase--rebaseindicador paragit pullsincronizar 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 pullcrea confirmaciones de fusión que agregan ruido y complejidad al historial del código. Además,pullhace que sea fácil no pensar en cómo sus cambios podrían verse afectados por los cambios entrantes.El
git pullcomando es seguro siempre que solo realice fusiones de avance rápido. Sigit pullestá 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 upalias como este:y usando en
git uplugar degit pull. Prefiero este alias sobregit pull --ff-onlyporque:origin/*ramas viejas que ya no existen aguas arriba.Problemas con
git pullgit pullno está mal si se usa correctamente. Varios cambios recientes en Git han hecho que sea más fácil de usargit pullcorrectamente, pero desafortunadamente el comportamiento predeterminado de un planogit pulltiene varios problemas:git pullEstos problemas se describen con mayor detalle a continuación.
Historia no lineal
Por defecto, el
git pullcomando es equivalente a ejecutargit fetchseguido degit merge @{u}. Si hay confirmaciones no aceleradas en el repositorio local, la parte degit pullfusió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
rebasecomando y por qué se creó). Las confirmaciones de fusión creadas porgit pullno 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 pulluna nueva versión en lugar de fusionar, pero esto también tiene problemas (discutido más adelante). En su lugar,git pulldebe 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 pullfusionará 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 pullse 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 pullLa 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 stashy luegogit pull, pero ¿qué haces cuando termines de revisar? Para volver a donde estabas, debes deshacer la fusión creada porgit pully 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 pullno te da esa flexibilidad.Rebasándose en una rama remota
Un patrón de uso común de Git es hacer una
git pullpara incorporar los últimos cambios seguidos de unagit rebase @{u}para eliminar la confirmación de fusión que segit pullintrodujo. Es bastante común que Git tiene algunas opciones de configuración para reducir estos dos pasos a un solo paso a contargit pullpara realizar un rebase en lugar de una fusión (verbranch.<branch>.rebase,branch.autosetuprebaseypull.rebaseopciones).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 pullconbranch.<branch>.rebaseset totrue) ni un merge-pull (elgit pullcomportamiento predeterminado ) seguido de un rebase funcionará. Esto se debe a quegit rebaseelimina las fusiones (linealiza el DAG) sin la--preserve-mergesopció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=preserveygit config pull.rebase preserve. Esto segit pulldebe hacergit rebase --preserve-mergesdespués de recuperar las confirmaciones anteriores. (¡Gracias a funkaster por el aviso !)Limpieza de ramas eliminadas
git pullno elimina las ramas de seguimiento remoto correspondientes a las ramas que se eliminaron del repositorio remoto. Por ejemplo, si alguien elimina una ramafoodel 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 uplugar degit pullEn lugar de
git pull, recomiendo crear y usar el siguientegit upalias: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 upnunca lo llevará a un aviso esperando que solucione un conflicto de fusión.Otra opción:
git pull --ff-only --all -pLa siguiente es una alternativa al
git upalias anterior :Esta versión de
git uptiene el mismo comportamiento que elgit upalias anterior , excepto:-pargumento, 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 pullpara hacer solo fusiones de avance rápido de forma predeterminada:Esto hace
git pullque 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 -pes equivalente agit fetch --all -p. Tengo la costumbre de escribirgit remote update -pporque alguna vezfetchno tenía la-popció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.ffconfiguración que parece lograr lo mismo, sin alias.git upsuena 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 pullconsidera 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 pullsea dañino.git rebasey consideragit pullperjudicial? De Verdad?git pullsin la--rebaseopció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 pullno 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=preserveno 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