¿Puede "git pull" ocultar y mostrar automáticamente los cambios pendientes?

122

Yo se como solucionar esto:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Sin embargo, no hay una manera de dejar que git pullhaga el stashy popbaile para mí?

Si este comando tiene un nombre diferente, está bien.

Crear un alias de shell para git stash; git pull; git stash popes una solución, pero busco una mejor solución.

guettli
fuente
¿qué pasa con un alias de git ?
Яois
20
Ejecutar git stash; git pull; git stash popprogramáticamente es peligroso, porque si no hay nada que esconder, git stashserá una operación no operativa, pero git stash popsacará el último alijo (si lo hay), que es casi seguro que no es lo que desea. El usuario torek tiene una excelente publicación sobre esto en Stack Overflow, pero no puedo encontrarla ...
jub0bs
1
@guettli No estaba insinuando que tu pregunta es un duplicado, solo estaba respondiendo al comentario de Jubobs.
VonC
2
Como paso más adelante, la operación debería tener éxito solo si el alijo se puede aplicar limpiamente después del tirón. Si hay conflictos, toda la operación falla atómicamente para que no se cambie el árbol. Esto es lo que me gustaría hacer: eliminar los cambios con los locales combinados o fallar con un error y dejarme decidir manualmente qué hacer a continuación. ¿Es posible este tipo de 'transacción' de git?
Ed Avis

Respuestas:

185

Para Git 2.6+ (lanzado el 28 de septiembre de 2015)

los solamente git config el escenario que sería de interés es:

rebase.autoStash

(con Git 2.27, Q2 2020, ahora también lo tiene merge.autostash, ver más abajo)

Cuando se establece en verdadero, crea automáticamente un alijo temporal antes de que comience la operación y aplícalo después de que finalice la operación.
Esto significa que puede ejecutar rebase en un árbol de trabajo sucio.

Sin embargo, utilícelo con cuidado: la aplicación de alijo final después de un rebase exitoso puede resultar en conflictos no triviales. El valor predeterminado es falso.

combinar eso con:

pull.rebase

Cuando es verdadero, rebase las ramas en la parte superior de la rama recuperada, en lugar de fusionar la rama predeterminada del control remoto predeterminado cuando se ejecuta "git pull".

git config pull.rebase true
git config rebase.autoStash true

Eso sería suficiente para que un simple git pullfuncione incluso en un árbol sucio.
En ese caso, no se necesita un alias.


Consulte la confirmación 53c76dc (4 de julio de 2015) de Kevin Daudt ( Ikke) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso e69b408 , 17 de agosto de 2015)

pull: permitir árbol sucio cuando está rebase.autostashhabilitado

rebase aprendió a guardar cambios cuando encuentra un árbol de trabajo sucio, pero git pull --rebaseno lo hace.

Solo verifique si el árbol de trabajo está sucio cuando rebase.autostashno está habilitado.


Nota: si desea extraer sin autostash (aunque rebase.autoStash trueesté configurado), lo tiene desde git 2.9 (junio de 2016):

 pull --rebase --no-autostash

Consulte la confirmación 450dd1d , la confirmación 1662297 , la confirmación 44a59ff , la confirmación 5c82bcd , la confirmación 6ddc97c , la confirmación eff960b , la confirmación efa195d (02 de abril de 2016) y la confirmación f66398e , la confirmación c48d73b (21 de marzo de 2016) por Mehul Jain ( mehul2029) .
(Combinado con Junio ​​C Hamano - gitster- en el compromiso 7c137bb , 13 de abril de 2016)

El compromiso f66398e en particular incluye:

pull --rebase: agregar --[no-]autostashbandera

Si rebase.autoStashse establece la variable de configuración, no hay forma de anularla para " git pull --rebase" desde la línea de comando.

Enseñe " git pull --rebase" la --[no-]autostashbandera de la línea de comando que anula el valor actual de rebase.autoStash, si está configurado. Como " git rebase" entiende la --[no-]autostashopción, es sólo una cuestión de pasar la opción al " git rebase" subyacente cuando git pull --rebasese llama " ".


Advertencia: antes de Git 2.14 (tercer trimestre de 2017), " git pull --rebase --autostash" no se guardaba automáticamente cuando el historial local avanzaba rápidamente hacia arriba.

Consulte la confirmación f15e7cf (01 de junio de 2017) de Tyler Brazier ( tylerbrazier) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 35898ea , 05 de junio de 2017)

pull: ff --rebase --autostashfunciona en repositorio sucio

Cuando git pull --rebase --autostashen un repositorio sucio resultó en un avance rápido, nada se estaba haciendo automáticamente y la extracción falló.
Esto se debió a un atajo para evitar ejecutar rebase cuando podemos avanzar rápidamente, pero el autostash se ignora en esa ruta de código.


Actualización: Mariusz Pawelski hace en los comentarios una pregunta interesante:

Entonces, todo el mundo está escribiendo sobre autostashcuándo hacer rebase (o pull --rebase).

Pero nadie se está ocupando del autoescritura cuando haces un pull normal con fusiones .
¿Entonces no hay un interruptor automático para eso? ¿O me falta algo? Prefiero hacerlo, git pull --rebasepero OP preguntó sobre git pull " estándar "

Responder:

El hilo original que analiza esta función de autoestadificación, se implementó originalmente tanto para git pull(fusionar) como para git pull --rebase.

Pero ... Junio ​​C Hamano (mantenedor de Git) señaló que:

Si pull-mergehubiera algo que induciría la "molestia" que desencadenó este tema, por definición, el cambio local se superpone con la fusión, y esta "ventana emergente" interna tocará las rutas que tocó la fusión y es probable que no resulte en "Eliminado "pero dejar más conflictos por resolver.

Sospecho que la pull.autostashconfiguración no es una buena adición porque fomenta un flujo de trabajo malo y doloroso.
En casos simples, puede que no duela, pero cuando los cambios locales son complejos, sería más perjudicial que no tenerlos, y la configuración roba el incentivo para elegir.

La ecuación es algo diferente para "pull-rebase", ya que "rebase" insiste en comenzar desde un árbol de trabajo limpio, por lo que la molestia de "descargar y luego detener" se siente más grande. Tengo la sospecha de que aflojar eso puede ser una solución más productiva para el problema real.

Entonces, con respecto a un pull-merge clásico, es mejor:

Anime al usuario a pensar en la naturaleza de WIP que tiene en el árbol de trabajo antes de ejecutar " git pull" .
¿Es una bestia demasiado compleja que puede interferir con lo que otros están haciendo, o es un cambio trivial que puede esconder y volver a abrir?

Si es lo primero, estará mucho mejor haciendo " checkout -b", siga trabajando hasta que el cambio local se ponga en una mejor forma y se "comprometa", antes de entrar en la rama original.

Si es lo último, es mejor que haga:

  • " git pull",
  • después de encontrar conflictos, ejecute
    • git stash,
    • git merge FETCH_HEAD y
    • git stash pop

Dicho esto, con Git 2.27 (Q2 2020), " git pull" aprendí a advertir cuando no pull.rebaseexiste ninguna configuración y no se da --[no-]rebaseni --ff-onlyse da (lo que resultaría en una fusión).

Consulte la confirmación d18c950 (10 de marzo de 2020) de Alex Henrie ( alexhenrie) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso 1c56d6f , 27 de marzo de 2020)

pull: advierte si el usuario no dijo si cambiar de base o fusionar

Firmado por: Alex Henrie

A menudo, los usuarios novatos de Git se olvidan de decir " pull --rebase" y terminan con una fusión innecesaria desde el principio .

Lo que normalmente quieren es " pull --rebase" en los casos más simples, o " pull --ff-only" actualizar la copia de las principales ramas de integración y reajustar su trabajo por separado.
La pull.rebasevariable de configuración existe para ayudarlos en los casos más simples, pero no existe un mecanismo para que estos usuarios se den cuenta de ella.

Emita un mensaje de advertencia cuando no se proporcione ninguna --[no-]rebaseopción desde la línea de comandos ni ninguna pull.rebasevariable de configuración.
Esto incomodará a aquellos que nunca quieren " pull --rebase", que no han tenido que hacer nada especial, pero el costo del inconveniente se paga una sola vez por usuario, lo que debería ser un costo razonable para ayudar a varios usuarios nuevos.


Con Git 2.27 (Q2 2020), " git merge" aprende la --autostashopción " " y la nueva merge.autostashconfiguración.

Ver cometer d9f15d3 , comprometerse f8a1785 , comprometerse a03b555 , comprometerse 804fe31 , comprometerse 12b6e13 , cometen 0dd562e , cometen 0816f1d , comprometerse 9bb3dea , cometen 4d4bc15 , comprometerse b309a97 , comprometerse f213f06 , comprometerse 86ed00a , cometen facca7f , comprometerse be1bb60 , comprometerse efcf6cf , comprometerse c20de8b , cometen bfa50c2 , confirmar 3442c3d , confirmar 5b2f6d9 (07 de abril de 2020), confirmar 65c425a(4 de abril de 2020), y confirme fd6852c , confirme 805d9ea (21 de marzo de 2020) por Denton Liu ( Denton-L) .
(Combinado por Junio ​​C Hamano - gitster- en el compromiso bf10200 , 29 de abril de 2020)

pull: pasar --autostash para fusionar

Firmado por: Denton Liu

Antes, --autostashsolo trabajaba con git pull --rebase.

Sin embargo, en el último parche, la fusión también se aprendió, --autostashpor lo que ya no hay razón por la que deberíamos tener esta restricción.
Enseñe a tirar para pasar --autostashpara fusionarse, tal como lo hizo para rebase.

Y:

rebase: uso apply_autostash()de secuenciador.c

Firmado por: Denton Liu

La apply_autostash()función en builtin/rebase.ces lo suficientemente similar a la apply_autostash()función en sequencer.cque son casi intercambiables, excepto por el tipo de arg que aceptan. Haga la sequencer.cversión externa y úsela en rebase.

La versión de rebase se introdujo en 6defce2b02 ("builtin rebase: --autostashopción de soporte ", 2018-09-04, Git v2.20.0-rc0 - fusión listada en el lote # 8 ) como parte de la conversión de shell a C.
Optó por duplicar la función porque, en ese momento, había otro proyecto en curso que convertía la rebase interactiva de shell a C y no querían chocar con ellos refactorizando la sequencer.cversión de apply_autostash().
Dado que ambos esfuerzos se han realizado durante mucho tiempo, ahora podemos combinarlos libremente.

VonC
fuente
A partir de 2.4.2, esto aún no está implementado. Quizás algún día. rebase.autoStashse aplica solo cuando se usa rebase. pull.rebasese aplica solo cuando se usa pull.
Randal Schwartz
"Eso sería suficiente para que un simple git pull funcione incluso en un árbol sucio". Como comentó Randal, esto aún no es cierto. El pull.c del maestro actual todavía elige die_on_unclean_work_tree.
Pradhan
1
@Pradhan estoy de acuerdo. La implementación acaba de entrar en master esta mañana y debería estar lista para git 2.6. He editado la respuesta para que quede claro.
VonC
Confirmé que autostash funciona con git 2.5.5.
Joshua Hoblitt
1
Entonces, todo el mundo está escribiendo sobre autostash cuando lo hace rebase(o pull --rebase). Pero nadie se está tomando el autoescritura cuando lo haces normalmente pullcon las fusiones. ¿Entonces no hay un interruptor automático para eso? ¿O me falta algo? Prefiero hacerlo, git pull --rebasepero OP preguntó sobre "estándar"git pull
Mariusz Pawelski
41

Para ahorrar unos segundos para los exploradores que se acercan, aquí hay un resumen (gracias a @VonC):

git pull --rebase --autostash
Vitaliy Ulantikov
fuente
6
El punto es: después de un git config pull.rebase truey git config rebase.autoStash true, todo lo que necesitará es git pull. Solo git pull. No se requieren otras opciones.
VonC
3
Parece que necesita al menos Git 2.9 para la --autostashopción. Las -c rebase.autoStash=trueobras en Git 2.6 en adelante.
ntc2
15

Como se indicó en el comentario anterior, establecer los dos valores de configuración no funciona actualmente git pull, ya que la configuración de autostash solo se aplica a las rebases reales. Estos comandos de git hacen lo que quieres:

git fetch
git rebase --autostash FETCH_HEAD

O configúrelo como un alias:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Entonces hazlo:

git pullr

Por supuesto, este alias puede cambiarse de nombre como desee.

user397114
fuente
7

Con Git 2.6+ puedes usar lo siguiente:

alias gup='git -c rebase.autoStash=true pull --rebase'

Esto --rebasehace que git-pull se use en rebaselugar de merge, por lo que las configuraciones / opciones como --ff-onlyno se aplicarán.

Estoy usando un alias para extraer --ff-onlyde forma predeterminada ( git pull --ff-only), y luego puedo usar gup(desde arriba) en caso de que no sea posible una combinación de avance rápido o haya cambios ocultos.

azulado
fuente
¿Cuál es la principal diferencia entre git pull --ff-onlyy?git pull pull --rebase --autostash
alper
0

Como ya mencionaste, esta es la forma de hacerlo. Puede usarlo en alias para ahorrarle escribir y usar atajos o puede usarlo en una sola línea (también puede ser un alias)

git stash && git pull --rebase && git stash pop

Hará lo mismo que hiciste, pero en una sola línea (&&) y si lo configuras como alias, será incluso más corto.

Las siguientes líneas mostrarán los cambios entrantes / salientes antes de tirar / empujar

git log ^master origin/master
git log master ^origin/master
CodeWizard
fuente
8
Este enfoque no es seguro: si no hay nada que esconder, el primer comando no hará nada y luego stash popeliminará algunas cosas al azar de antes.
John Zwinck
Para ser más claro: incluso si git stashno guarda nada, todavía no "devuelve" ningún código de error, por lo que && continuará con git pully git stash popy mostrará un alijo anterior. ¡Así que es mejor no usar esto a menos que esté seguro de que guardará algo!
MoonLite