HOWTO · Git

Git Push --force-with-lease vs Git Push --force

En este artículo, discutiremos la diferencia entre los comandos git push --force-with-lease y git push --force.

En esta página

Cuando un rebase o una enmienda cambia commits que ya se publicaron, es posible que se rechace un push normal porque la rama remota ya no puede avanzar mediante un fast-forward desde la rama local. Tanto git push --force como git push --force-with-lease pueden reemplazar la punta de la rama remota. La diferencia está en si Git comprueba un valor remoto esperado antes de actualizarla. Para reescribir el historial de forma intencional, prefiere la opción con lease y, si Git rechaza el push, inspecciona el estado remoto y reconcilia las ramas.

Cómo funciona git push --force

Un push normal protege los commits remotos al exigir que la rama avance. git push --force desactiva esa protección para la referencia que se envía: la rama remota se establece en el commit que indiques, aunque eso quite commits de su historial visible. Si un compañero envió cambios que aún no has incorporado, esos cambios pueden dejar de ser accesibles desde la rama.

El destino del comando determina su alcance. Por ejemplo, git push --force origin feature apunta a la rama feature de origin; si no indicas claramente el nombre de la rama, puede ser menos evidente qué referencia se verá afectada. Usa force solo cuando reemplazar el historial de la rama sea intencional y esté coordinado con todas las personas que la usan. Un push forzado no genera un conflicto de merge ni combina por sí mismo los commits remotos.

Cómo funciona git push --force-with-lease

git push --force-with-lease origin feature también permite una actualización que no sea fast-forward, pero primero comprueba que la rama remota conserve el valor esperado. En su forma habitual, Git obtiene ese valor de la referencia local de seguimiento remoto, como origin/feature. Si el valor de la rama en el servidor es distinto, Git rechaza la actualización en lugar de reemplazarla.

Esta comprobación es útil, pero no demuestra que nadie haya enviado cambios que aún no hayas visto. Si una descarga en segundo plano actualiza origin/feature después de tu última revisión, el lease predeterminado podría aceptar una reescritura usando ese valor recién descargado. Indicar explícitamente el ID del objeto esperado hace que la comparación sea deliberada: git push --force-with-lease=refs/heads/feature:<expected-object-id> origin HEAD:refs/heads/feature. Obtén y revisa el valor esperado como parte del flujo de trabajo del equipo; no copies un ID sin comprobar qué representa.

Usa --force-with-lease después de reescribir el historial

Supongamos que la rama compartida era A---B---C, que un colaborador añadió D después de C y que rebasaste tu trabajo local para crear A---B---C'. Ahora C' en tu rama local y D en la remota representan puntas distintas. El propósito del lease es evitar que reemplaces D sin darte cuenta cuando el estado remoto que esperas todavía es C.

Primero inspecciona la rama y descarga su estado actual. Después decide si el commit del colaborador debe formar parte del historial reescrito. Puedes rebasar tu trabajo sobre la rama descargada o coordinar con el equipo otro plan de integración. Una vez que hayas resuelto y revisado el historial, envía el resultado previsto con un lease. Si el lease rechaza el push, vuelve a descargar e inspeccionar; no reintentes de inmediato con --force.

Ejecuta esta demostración autocontenida para crear una rama local, publicarla en un repositorio bare temporal, enmendar su punta y actualizarla con un lease:

set -e
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT

git init --bare "$root/remote.git" >/dev/null 2>&1
git init -b feature "$root/work" >/dev/null 2>&1
cd "$root/work"
git config user.name "Example Developer"
git config user.email "developer@example.com"
printf 'first version\n' > README.md
git add README.md
git commit -m "Add first version" >/dev/null 2>&1
git remote add origin "$root/remote.git"
git push -u origin feature >/dev/null 2>&1
git commit --amend -m "Rewrite first version" >/dev/null 2>&1
git push --force-with-lease origin feature >/dev/null 2>&1

Las rutas son temporales y el script elimina el entorno de prueba al terminar. En un repositorio real, inspecciona los commits y coordina con tus colaboradores antes de reemplazar el historial compartido.

Elige una opción de push forzado con seguridad

En una rama personal sin colaboradores, un push forzado directo puede ser aceptable si la intención es reemplazar su punta remota. En una rama compartida, elige --force-with-lease después de revisar el estado remoto esperado y coordinar la reescritura. Si una solicitud de cambios u otro proceso de revisión permite evitar por completo la reescritura de una rama compartida, prefiérelo.

Indica explícitamente el remoto y la rama, descarga los cambios antes de decidir y revisa el grafo de commits antes de enviar el push. Que se rechace un lease es una señal de seguridad: compara tu rama local con la rama remota descargada, conserva los commits necesarios y vuelve a intentarlo solo después de decidir cómo integrarlos. Sincronizarse con regularidad reduce las sorpresas, pero no reemplaza la revisión del historial que vas a publicar.

Recupera commits perdidos o evita perderlos

Si un push forzado quitó un commit de la punta de la rama, deja de hacer tareas de limpieza y busca una referencia que lo conserve. En tu clon local, git reflog puede mostrar posiciones recientes de la rama; el clon de otro colaborador, una copia de seguridad remota o una función de recuperación del proveedor de alojamiento también podrían conservar el commit. Si lo encuentras, crea una rama que apunte a él antes de decidir cómo restaurarlo o integrarlo. Las entradas de reflog caducan y son locales, así que la recuperación no está garantizada.

Para prevenir pérdidas, acuerda quién puede reescribir una rama compartida, avisa a los colaboradores antes de actualizarla y conserva una referencia conocida cuando haya que revisar una reescritura. Un lease reduce una clase de sobrescrituras accidentales, mientras que una coordinación clara y un punto de recuperación verificado ayudan a abordar riesgos que el lease no puede detectar.

Preguntas frecuentes

¿Cuál es la diferencia entre git push --force y git push --force-with-lease? El primero reemplaza la referencia remota sin comprobar su valor actual. El segundo comprueba un valor esperado y rechaza la actualización si el remoto no coincide.

¿Cuándo puedo usar git push --force? Úsalo solo si pretendes reemplazar la punta de la rama de destino, entiendes qué commits podrían desaparecer de esa rama y lo has coordinado con los colaboradores afectados. Para trabajo compartido, prefiere un lease e inspecciona el estado que espera.

¿Es peligroso forzar un push en una rama compartida? Puede ocultar commits de la rama y perjudicar el trabajo de tus colaboradores. Un lease ayuda cuando el remoto no coincide con el valor esperado, pero una descarga que no hayas revisado puede actualizar el valor que espera el lease predeterminado.

¿Cómo puedo reducir conflictos o sorpresas? Descarga e inspecciona el remoto, incorpora los commits de tus colaboradores al historial reescrito cuando corresponda, comunica el plan y usa flujos de revisión para los cambios compartidos.

¿Puedo deshacer un push forzado? No hay una reversión automática. Es posible que encuentres el commit anterior en un reflog, otro clon o una función de recuperación del proveedor; después, puedes crear una referencia y coordinar la restauración. La posibilidad depende de que siga existiendo una referencia a ese commit.