traemos - ¿Cómo presiona la confirmación modificada en el repositorio de Git remoto?
git ver archivos modificados (13)
Cuando trabajé un poco con mi código fuente, hice mi confirmación habitual y luego pasé a un repositorio remoto. Pero luego noté que olvidé organizar mis importaciones en el código fuente. Así que hago el comando enmendar para reemplazar el commit anterior:
> git commit --amend
Desafortunadamente, la confirmación no puede ser devuelta al repositorio. Se rechaza así:
> git push origin
To //my.remote.repo.com/stuff.git/
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to ''//my.remote.repo.com/stuff.git/''
¿Qué tengo que hacer? (Puedo acceder al repositorio remoto).
Aquí hay una manera muy simple y limpia de impulsar sus cambios después de que ya haya hecho un git add "your files"
y un git commit --amend
:
git push origin master -f
o:
git push origin master --force
En realidad, una vez --force
con --force
y .git
repositorio y me regañó Linus BIG TIME . En general esto creará muchos problemas para otras personas. Una respuesta simple es "No lo hagas".
Veo que otros dieron la receta para hacerlo de todos modos, así que no los repetiré aquí. Pero aquí hay un consejo para recuperarse de la situación después de que haya eliminado la confirmación modificada con --force (o + master).
- Encuentre el compromiso anterior que modificó (llámelo
old
y llamaremos el compromiso nuevo que creó al enmendarnew
). - Cree una combinación entre lo
old
y lonew
, registrando el árbol de lonew
, comogit checkout new && git merge -s ours old
. - Combina eso con tu maestro con
git merge master
- Actualiza tu master con el resultado con
git push . HEAD:master
git push . HEAD:master
- Empuje el resultado hacia afuera.
Luego, las personas que tuvieron la mala suerte de haber basado su trabajo en el compromiso que usted eliminó modificando y forzando un empuje (que es que usted es un niño muy malo ) verán que la fusión resultante verá que usted prefiere a lo new
sobre lo old
. Sus fusiones posteriores no verán los conflictos entre lo old
y lo new
que resultaron de su modificación, por lo que no tienen que sufrir.
Estás viendo una característica de seguridad de Git. Git se niega a actualizar la rama remota con su rama, ya que la confirmación de encabezado de su rama no es un descendiente directo de la confirmación de cabecera actual de la rama a la que está presionando.
Si este no fuera el caso, entonces dos personas que empujan al mismo repositorio casi al mismo tiempo no sabrían que se estaba produciendo un nuevo compromiso al mismo tiempo y quien lo empujara por última vez perdería el trabajo del pulsador anterior sin ninguno de los dos. Ellos se dan cuenta de esto.
Si sabe que es la única persona que está presionando y desea empujar una confirmación modificada o empujar una confirmación que enrolla la rama, puede ''forzar'' a Git a actualizar la rama remota usando el interruptor -f
.
git push -f origin master
Incluso esto puede no funcionar, ya que Git permite que los repositorios remotos rechacen los avances no rápidos en el extremo remoto mediante el uso de la variable de configuración receive.denynonfastforwards
. Si este es el caso, el motivo de rechazo se verá así (observe la parte ''rechazada a distancia''):
! [remote rejected] master -> master (non-fast forward)
Para solucionar esto, debes cambiar la configuración del repositorio remoto o, como truco, puedes eliminar y recrear la rama de la siguiente manera:
git push origin :master
git push origin master
En general, el último parámetro para git push
usa el formato <local_ref>:<remote_ref>
, donde local_ref
es el nombre de la rama en el repositorio local y remote_ref
es el nombre de la rama en el repositorio remoto. Este par de comandos utiliza dos abreviaturas. :master
tiene un local_ref nulo que significa empujar una rama nula al master
lado remoto, es decir, eliminar la rama remota. Un nombre de rama sin :
significa empujar la rama local con el nombre dado a la rama remota con el mismo nombre. master
en esta situación es la abreviatura de master:master
.
Esta es una forma muy simple y limpia de impulsar sus cambios después de que ya haya realizado un commit --amend
: commit --amend
:
git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master
Que hace lo siguiente:
- Restablecer el encabezado de rama a la confirmación principal
- Guarda este último commit.
- Fuerza de empuje a distancia. El mando a distancia ahora no tiene el último commit.
- Pop tu alijo.
- Comprometerse limpiamente.
- Empuje a control remoto.
Recuerde cambiar "origen" y "maestro" si lo aplica a una rama o control remoto diferente.
Lo resolví descartando mi confirmación modificada local y agregando los nuevos cambios en la parte superior:
# Rewind to commit before conflicting
git reset --soft HEAD~1
# Pull the remote version
git pull
# Add the new commit on top
git add ...
git commit
git push
Recibirá este error porque el control remoto de Git ya tiene estos archivos de confirmación. Tienes que forzar el empuje de la rama para que esto funcione:
git push -f origin branch_name
También asegúrese de extraer el código del control remoto, ya que otra persona de su equipo podría haberlo enviado a la misma rama.
git pull origin branch_name
Este es uno de los casos en los que tenemos que forzar el envío del compromiso a remoto.
Respuesta corta: No presione los compromisos modificados a un repositorio público.
Respuesta larga: algunos comandos de Git, como git commit --amend
y git rebase
, en realidad reescriben el gráfico histórico. Esto está bien siempre y cuando no hayas publicado tus cambios, pero una vez que lo hagas, realmente no deberías estar metiéndote en el historial, porque si alguien ya recibió tus cambios, cuando intenten volver a intentarlo, podría fallar. . En lugar de enmendar una confirmación, solo debe realizar una nueva confirmación con los cambios.
Sin embargo, si realmente desea impulsar un compromiso modificado, puede hacerlo así:
$ git push origin +master:master
El signo +
inicio obligará a que se produzca el empuje, incluso si no resulta en un compromiso de "avance rápido". (Una confirmación de avance rápido ocurre cuando los cambios que está impulsando son un descendiente directo de los cambios que ya están en el repositorio público).
Respuesta rápida: el hecho de que nadie haya publicado la respuesta simple aquí demuestra la desesperada hostilidad del usuario mostrada por el CLI de Git.
De todos modos, la forma "obvia" de hacer esto, asumiendo que no ha intentado forzar el empuje, es tirar primero. Esto elimina el cambio que enmendó (y por lo tanto ya no tiene) para que lo tenga nuevamente.
Una vez que haya resuelto cualquier conflicto, puede presionar de nuevo.
Asi que:
git pull
Si obtiene errores en la extracción, tal vez haya algún error en la configuración del repositorio local (tuve una referencia incorrecta en la sección de rama .git / config).
Y después
git push
Tal vez obtendrá un compromiso adicional con el tema que habla sobre una "fusión trivial".
Seguí haciendo lo que Git me dijo que hiciera. Asi que:
- No se puede empujar debido a un compromiso modificado.
- Hago un tirón como se sugiere.
- La fusión falla. Así lo arreglo manualmente.
- Crea una nueva confirmación (etiquetada como "fusionar") y presiona.
- ¡Parece funcionar!
Nota: La confirmación modificada fue la última.
Si no ha introducido el código en su sucursal remota (GitHub / Bitbucket), puede cambiar el mensaje de confirmación en la línea de comando como se muestra a continuación.
git commit --amend -m "Your new message"
Si estás trabajando en una rama específica, haz esto:
git commit --amend -m "BRANCH-NAME: new message"
Si ya ha presionado el código con un mensaje incorrecto, debe tener cuidado al cambiar el mensaje. es decir, después de cambiar el mensaje de confirmación y volver a intentarlo, terminas con problemas. Para que sea suave siga los siguientes pasos.
Por favor lee la respuesta completa antes de hacerlo.
git commit --amend -m "BRANCH-NAME : your new message"
git push -f origin BRANCH-NAME # Not a best practice. Read below why?
Nota importante: cuando usa la fuerza de empuje directamente, puede terminar con problemas de código que otros desarrolladores están trabajando en la misma rama. Por lo tanto, para evitar esos conflictos, debe extraer el código de su sucursal antes de presionar a la fuerza :
git commit --amend -m "BRANCH-NAME : your new message"
git pull origin BRANCH-NAME
git push -f origin BRANCH-NAME
Esta es la mejor práctica al cambiar el mensaje de confirmación, si ya se ha enviado.
Si sabe que nadie ha retirado su compromiso sin enmendar, use la opción --force-with-lease
de git push
.
En TortoiseGit, puede hacer lo mismo en "Push ..." opciones "Force: puede descartar" y verificar "cambios conocidos".
La fuerza (puede descartar los cambios conocidos) permite que el repositorio remoto acepte un empuje más rápido que no avance rápido. Esto puede hacer que el repositorio remoto pierda confirmaciones; Úsalo con cuidado. Esto puede evitar perder cambios desconocidos de otras personas en el control remoto. Comprueba si la rama del servidor apunta a la misma confirmación que la rama de seguimiento remoto (cambios conocidos). Si es así, se realizará un empuje de fuerza. De lo contrario será rechazado. Dado que git no tiene etiquetas de seguimiento remoto, las etiquetas no se pueden sobrescribir con esta opción.
Tuve que solucionar este problema con la extracción desde el repositorio remoto y lidiar con los conflictos de fusión que surgieron, cometer y luego presionar. Pero siento que hay una mejor manera.
Yo tuve el mismo problema.
- Se modificó accidentalmente la última confirmación que ya fue empujada.
- Hizo muchos cambios a nivel local, cometido unas cinco veces.
- Intenté empujar, obtuve un error, entró en pánico, combinó el control remoto, consiguió muchos archivos que no eran mis archivos, fue empujado, falló, etc.
Como Git-novato, pensé que era FUBAR completo.
Solución: Algo como @bara sugirió + creó una rama de respaldo local
# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>
# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad
# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"
# Switch back to the original branch
git checkout feature/1234
# Pull the from remote (named ''origin''), thus ''repairing'' our main problem
git pull origin/feature/1234
# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php
Tal vez no sea una solución rápida y limpia, y perdí mi historial (1 confirmación en lugar de 5), pero me ahorró el trabajo de un día.