Git pull después de una actualización forzada

334

Acabo de aplastar algunos compromisos git rebasee hice un git push --force(que es malo, lo sé).

Ahora los otros ingenieros de software tienen una historia diferente y cuando lo hacen git pull, Git se fusionará. ¿Hay alguna manera de arreglar esto, excepto hacer un rm my-repo; git clone [email protected]:my-repo.git?

Necesito algo como lo contrario de git push --force, pero git pull --forceno dio los resultados previstos.

iblue
fuente
16
pueden borrar su rama y volver a crearla también, sin tener que borrar todo el repositorio:git checkout master && git branch -D test && git checkout -b test origin/test
Florian Klein

Respuestas:

512

Para recibir los nuevos commits

git fetch

Reiniciar

Puede restablecer el commit para una sucursal local usando git reset.

Para cambiar la confirmación de una sucursal local:

git reset origin/master --hard

Sin embargo, tenga cuidado, como dice la documentación:

Restablece el índice y el árbol de trabajo. Cualquier cambio en los archivos rastreados en el árbol de trabajo desde <commitir> se descartan.

Si realmente desea conservar los cambios que tiene localmente, --softreinicie en su lugar. Lo cual actualizará el historial de confirmación de la rama, pero no cambiará ningún archivo en el directorio de trabajo (y luego puede confirmarlo).

Rebase

Puede reproducir sus confirmaciones locales sobre cualquier otra confirmación / ramificación utilizando git rebase:

git rebase -i origin/master

Esto invocará rebase en modo interactivo donde puede elegir cómo aplicar cada confirmación individual que no está en el historial sobre el que está rebase.

Si las confirmaciones que eliminó (con git push -f ) ya se han incluido en el historial local, aparecerán como confirmaciones que se volverán a aplicar; tendrían que eliminarse como parte del rebase o simplemente se volverán a incluir en el historial para la sucursal y reaparecer en el historial remoto en el siguiente impulso.

Use la ayuda git command --helppara obtener más detalles y ejemplos sobre cualquiera de los comandos anteriores (u otros).

AD7six
fuente
2
@iblue elige entre perder todos los cambios, eliminar el historial de confirmaciones pero mantener los cambios en el archivo o intentar aplicar cada confirmación sobre el nuevo encabezado. La opción más simple es probablemente un reinicio por software.
AD7six
1
@iblue Cuando su colega use `git reabse origin / master ', y mientras tanto, ya tenían un commit antes, git escribirá su commit detrás de su commit.
Tim
66
Vale la pena mencionar que si esto es para una rama diferente:git reset origin/otherbranch --hard
bmaupin
Por lo tanto, para aclarar, esto es ya sea : Opción 1: reset --hard, o Opción 2: reset --soft+ rebase, ¿verdad?
PlasmaBinturong
2
@PlasmaBinturong No. git reset --soft origin/mastercambiará el historial de confirmación para que coincida con el control remoto y las diferencias de etapa con el control remoto que luego se confirmará . No habría necesidad de rebase en ese escenario (y se le impediría hacerlo debido a los cambios no confirmados) porque no hay diferencia en el historial de confirmación. Las dos opciones son restablecer o rebase, no una combinación de ambas. Haga una pregunta si su escenario es diferente al que he respondido aquí.
AD7six
16

Esto no solucionará las ramas que ya tienen el código que no desea en ellas (consulte a continuación para saber cómo hacerlo), pero si habían extraído alguna rama y ahora quieren que esté limpia (y no "por delante" de origen / alguna rama) entonces simplemente:

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Nota: Puede combinar todos estos poniendo && entre ellos

Nota 2: Florian mencionó esto en un comentario, pero ¿quién lee los comentarios cuando busca respuestas?

Nota 3: Si tiene ramas contaminadas, puede crear otras nuevas a partir de la nueva "rama tonta" y simplemente se compromete.

Ex:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

¡Ahora la nueva característica es su rama sin los compromisos adicionales (posiblemente malos)!

Tom Prats
fuente
Esto es lo que realmente quería. Alguien rebasó la rama maestra (por Dios sabe qué razón) pero no tuve cambios locales que quisiera cometer ni nada. Así que todo lo que tuve que hacer fue eliminar mi sucursal maestra local (lo que me pareció realmente extraño) y volver a pagar. ¡Gracias!
Danilo Carvalho
@ peter-mortensen Las ediciones deben ser sustanciales de acuerdo con stackoverflow.com/help/editing
Tom Prats
para el último paso, también puede usar git checkout -b base-branch origin/base-branchcongit checkout --track origin/base-branch
bluesmonk
2

Tire con rebase

Un pull regular es fetch + merge, pero lo que quieres es fetch + rebase. Esta es una opción con el pullcomando:

git pull --rebase
Germán
fuente
Lo uso todo el tiempo para obtener el último código del maestro en mi rama de características sin tener todas esas confirmaciones de fusión en el historial.
herman