¿Cómo forzo correctamente un empuje Git?

1274

He configurado un repositorio "principal" remoto no descubierto y lo he clonado en mi computadora. Hice algunos cambios locales, actualicé mi repositorio local y devolví los cambios a mi repositorio remoto. Las cosas estaban bien hasta ese punto.

Ahora, tuve que cambiar algo en el repositorio remoto. Luego cambié algo en mi repositorio local. Me di cuenta de que no era necesario el cambio al repositorio remoto. Así que intenté git pushdesde mi repositorio local a mi repositorio remoto, pero recibí un error como:

Para evitar que pierda el historial, se rechazaron las actualizaciones que no son de avance rápido. Combine los cambios remotos antes de presionar nuevamente. Consulte la sección 'Nota sobre avance rápido' git push --helppara obtener más detalles.

Pensé que probablemente un

git push --force

obligaría a mi copia local a empujar los cambios a la remota y la haría igual. Obliga a la actualización , pero cuando vuelvo al repositorio remoto y realizo una confirmación, noto que los archivos contienen cambios desactualizados (los que el repositorio remoto principal tenía anteriormente).

Como mencioné en los comentarios a una de las respuestas :

[Intenté forzarlo, pero cuando vuelvo al servidor maestro para guardar los cambios, me quedo obsoleto. Por lo tanto, cuando confirmo los repositorios no son lo mismo. Y cuando trato de usar git push nuevamente, aparece el mismo error.

¿Cómo puedo solucionar este problema?

Spyros
fuente
44
Pronto (git1.8.5, Q4 2013) podrá hacerlo con git push -forcemás cuidado .
VonC
66
Como detallo en mi propia respuesta , git push --forcees de hecho otra forma válida de forzar el empuje, y empujará las ramas tan bien como git push origin master --forcecon el valor predeterminado de Git push.default config settings, aunque las ramas que se empujan específicamente difieren entre las versiones de Git anteriores a 2.0 frente a 2.0.
2
git push --forcefunciona bien en estos días, FWIW ...
rogerdpack
git push --force-with-leasefunciona aún mejor :), se negará a actualizar una rama a menos que sea el estado que espera. (vea developer.atlassian.com/blog/2015/04/force-with-lease )
spoorcc

Respuestas:

2309

Solo haz:

git push origin <your_branch_name> --force

o si tienes un repositorio específico:

git push https://git.... --force

Esto eliminará sus confirmaciones anteriores y empujará la actual.

Puede que no sea apropiado, pero si alguien se topa con esta página, pensó que podría querer una solución simple ...

Bandera corta

También tenga en cuenta que -fes la abreviatura de --force, entonces

git push origin <your_branch_name> -f

También funcionará.

Katie
fuente
58
Puede usar git push origin +masteren su lugar, lo que le permite empujar múltiples especificaciones de referencia sin forzarlas a todas.
nickgrim
55
Tenga en cuenta que, si accidentalmente lo hace git push --force, podría terminar arruinando su rama maestra (dependiendo de su comportamiento predeterminado de inserción) ... lo que podría ser un poco
malo
99
@Jeewes comenzando con Git versión 2.0, el comportamiento predeterminado de git push --forcees básicamente forzar el empuje de la rama actualmente desprotegida a su parte de contador remoto, por lo que si tiene la rama maestra desprotegida, entonces es idéntica git push origin master --force. Será diferente si está utilizando la matchingconfiguración para push.default, que es el valor predeterminado para las versiones de Git anteriores a 2.0. matchingempuja todas las sucursales locales a las remotas que tienen el mismo nombre, por lo que forzar el empuje definitivamente no podría ser lo que quieres hacer ...
@Jeewes Pero con Git 2.0, el valor predeterminado es más seguro, o al menos no es más peligroso de lo que git push origin master --forcees.
2
push -f es bueno pero no se recomienda para master ya que la mayoría de los repositorios corporativos tienen -f desactivado para master. el merge -s ourstrabajó para mí
Mihai
247

Y si push --forceno funciona puedes hacerlo push --delete. Mire la línea en esta instancia:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Pero cuidado...

¡Nunca vuelvas a una historia pública de git!

En otras palabras:

  • Nunca forceempujes un repositorio público.
  • No hagas esto ni nada que pueda romper el de alguien pull.
  • Nunca lo hagas reseto la rewritehistoria en un repositorio que alguien ya podría haber hecho.

Por supuesto, hay excepciones excepcionalmente raras incluso a esta regla, pero en la mayoría de los casos no es necesario hacerlo y generará problemas para todos los demás.

Haz una reversión en su lugar.

Y siempre tenga cuidado con lo que empuja a un repositorio público . Revertir:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

En efecto, ambos HEADs de origen (del reversión y desde el reinicio del mal ) contendrán los mismos archivos.


editar para agregar información actualizada y más argumentos sobre push --force

Considere empujar la fuerza con arrendamiento en lugar de empujar, pero aún así prefiere revertir

Otro problema que push --forcepuede traer es cuando alguien empuja algo antes que tú, pero después de que ya hayas ido. Si presiona forzar su versión reforzada ahora lo hará reemplazará el trabajo de otros .

git push --force-with-leaseintroducido en el git 1.8.5 ( gracias al comentario de @VonC sobre la pregunta) intenta abordar este problema específico. Básicamente, traerá un error y no empujará si el control remoto fue modificado desde su última búsqueda.

Esto es bueno si está realmente seguro de que push --forcese necesita, pero aún así quiere evitar más problemas. Me atrevería a decir que debería ser el push --forcecomportamiento predeterminado . Pero aún está lejos de ser una excusa para forzar a push. Las personas que buscaron antes de tu rebase todavía tendrán muchos problemas, que podrían evitarse fácilmente si hubieras revertido en su lugar.

Y como estamos hablando de git --pushinstancias ...

¿Por qué alguien querría forzar el empuje?

@linquize trajo un buen ejemplo de fuerza de empuje en los comentarios: datos confidenciales . Ha filtrado información erróneamente que no debe ser enviada. Si eres lo suficientemente rápido, puedes "arreglarlo"* forzando un empujón en la parte superior.

*Los datos seguirán estando en el control remoto a menos que también haga una recolección de basura o la limpie de alguna manera . También existe el potencial obvio de que otros usuarios ya lo hayan contagiado , pero se entiende la idea.

cregox
fuente
1
El problema, @rogerdpack, no es si es factible. Está. Pero puede resumir en un gran desastre. Cuanto más alguien lo haga (forzar) y menos a menudo actualice (tire) del repositorio público, mayor será el desastre. ¡Puede desmantelar el mundo tal como lo conoce! 111 Al menos el mundo que forma parte de ese repositorio particular.
cregox
3
Si tiene datos confidenciales, forzarlo a empujar
linquize
3
@Cawas: Creo que quiere decir que si está tratando de eliminar datos confidenciales del repositorio, entonces desea reescribir el historial. Si revierte, los datos confidenciales todavía están allí en la confirmación anterior. Dicho esto, si alguien más ya se retiró del repositorio, reescribir el historial no lo ayudará a evitar que accedan a los datos confidenciales; ya es demasiado tarde en ese momento.
Stuart Golodetz
3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushEsto realmente resolvió mi problema perfectamente (en un repositorio solo con mi amigo y yo). tal vez esté mal para repositorios públicos pero para uno privado esto es un salvavidas.
Can Poyrazoğlu
1
Esto sucede automáticamente con algunos administradores de repositorios, también conocido como auto-squash, etc. Es común y esperado forzar el empuje después de terminar una rama de características para reducir las confirmaciones.
FlavorScape
18

En primer lugar, no haría ningún cambio directamente en el repositorio "principal". Si realmente quieres tener un repositorio "principal", entonces solo debes presionarlo, nunca cambiarlo directamente.

Con respecto al error que está recibiendo, ¿ha intentado git pulldesde su repositorio local y luego git pushal repositorio principal? Lo que está haciendo actualmente (si lo entendí bien) es forzar el empuje y luego perder sus cambios en el repositorio "principal". Debe fusionar los cambios localmente primero.

ubik
fuente
Sí, intenté un tirón pero estoy perdiendo datos perdidos debido a ese tirón. Quiero hacer mis repositorios principales como mi local, sin actualizar primero desde el principal.
Spyros
1
En ese caso git push -f, use , pero si cambia su repositorio principal nuevamente, debe volver a su repositorio local y git pull, para que se sincronice con los últimos cambios. Entonces puedes hacer tu trabajo y presionar de nuevo. Si sigue este flujo de trabajo "push-pull", no obtendrá el tipo de error del que se quejaba.
ubik 01 de
sí, entiendo que esto fue mi culpa: / Lo intentaré y volveré en un rato gracias
Spyros
1
Intenté forzar, pero cuando vuelvo al servidor maestro para guardar los cambios, me quedo obsoleto. Por lo tanto, cuando confirmo los repositorios no son lo mismo. Y cuando trato de usar git push nuevamente, obtengo el mismo error.
Spyros
17

Si estoy en mi rama local A, y quiero forzar el empuje de la rama local B a la rama de origen CI, puedo usar la siguiente sintaxis:

git push --force origin B:C
IcedDante
fuente
2
Descubrí que incluso estoy en mi sucursal local B, todavía tengo que hacerlo git push --force origin B:C. En mi caso, parece que git push --force origin Csolo pasará del maestro local a la rama C remota, independientemente de la rama en la que esté actualmente. git version 2.3.8 (Apple Git-58)
Weishi Zeng
12

use este siguiente comando:

git push -f origin master
Mustafa Elsayed
fuente
1
Tal vez dé más explicaciones sobre por qué esta respuesta es preferible a las otras y qué la hace diferente.
Adam
oh, disculpen las molestias, estaba teniendo el mismo problema y este comando lo resolvió, pensé que debería compartirlo.
mustafa Elsayed
12
Es igual que los demás, acabas de cambiar la posición de la -fbandera ...
svelandiag
11

Realmente recomendaría:

  • empujar solo al repositorio principal

  • asegúrese de que el repositorio principal sea un repositorio simple , para nunca tener ningún problema con el árbol de trabajo del repositorio principal que no esté sincronizado con su .gitbase. Consulte " ¿Cómo enviar un repositorio git local a otra computadora? "

  • Si tiene que hacer modificaciones en el repositorio principal (desnudo), clónelo (en el servidor principal), realice su modificación y vuelva a presionarlo

En otras palabras, mantenga un repositorio desnudo accesible tanto desde el servidor principal como desde la computadora local, para tener un único repositorio ascendente desde / hacia el cual extraer / extraer.

VonC
fuente
5

Esta fue nuestra solución para reemplazar master en un repositorio corporativo de gitHub mientras se mantenía el historial.

push -fdominar en repositorios corporativos a menudo está deshabilitado para mantener el historial de la sucursal. Esta solución funcionó para nosotros.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

empuja tu rama hacia desiredOriginy crea un PR

mihai
fuente
3

Tenía la misma pregunta, pero finalmente lo descubrí. Lo más probable es que necesite ejecutar los siguientes dos comandos git (reemplazando el hash con el número de revisión git commit):

git checkout <hash>
git push -f HEAD:master
Brian M.
fuente