Git prune
El comando git prune
es una utilidad de mantenimiento interno que limpia objetos de Git inaccesibles o "huérfanos". Los objetos inaccesibles son aquellos a los que no puede acceder ninguna referencia. Cualquier confirmación a la que no se pueda acceder a través de una rama o etiqueta se considera inaccesible. git prune
generalmente no se ejecuta directamente; se considera un comando de "recolección de basura" y es un comando secundario de git gc.
Descripción general de git prune
Para entender los efectos de git prune
, vamos a simular una situación en la que una confirmación se vuelve inaccesible. El siguiente código es una secuencia de ejecuciones de línea de comandos que simulará esta experiencia.
~ $ cd git-prune-demo/
~/git-prune-demo $ git init .
Initialized empty Git repository in /Users/kev/Dropbox/git-prune-demo/.git/
~/git-prune-demo $ echo "hello git prune" > hello.txt
~/git-prune-demo $ git add hello.txt
~/git-prune-demo $ git commit -am "added hello.txt"
La secuencia de comandos anterior creará un nuevo repositorio en un directorio llamado git-prune-demo
. Se añade al repositorio una confirmación que consiste en un nuevo archivo llamado hello.text
con el contenido básico “hello git prune”. A continuación, modificaremos hello.txt
y crearemos una nueva confirmación a partir de esas modificaciones.
~/git-prune-demo $ echo "this is second line txt" >> hello.txt
~/git-prune-demo $ cat hello.txt
hello git prune
this is second line txt
~/git-prune-demo $ git commit -am "added another line to hello.txt"
[main 5178bec] added another line to hello.txt
1 file changed, 1 insertion(+)
Material relacionado
Cómo mover un repositorio de Git completo
VER LA SOLUCIÓN
Aprende a usar Git con Bitbucket Cloud
Ahora tenemos un historial de 2 confirmaciones en este repositorio de demostración. Podemos verificarlo mediante git log
:
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
La salida de git log
muestra las 2 confirmaciones y los mensajes de confirmación correspondientes sobre las ediciones realizadas en hello.txt. El siguiente paso es hacer que una de las confirmaciones sea inaccesible. Para ello, utilizaremos el comando git reset. Restablecemos el estado del repositorio a la primera confirmación (“added hello.txt”).
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
Si ahora utilizamos git log
para examinar el estado del repositorio, podemos ver que solo tenemos una confirmación.
~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
El repositorio de demostración ahora está en un estado que contiene una confirmación desasociada. La segunda confirmación que hicimos con el mensaje “added another line to hello.txt” ya no aparece en la salida de git log
y ahora está desasociada. Puede parecer que hemos perdido o eliminado la confirmación, pero Git es muy estricto en cuanto a no eliminar el historial. Podemos confirmar que todavía está disponible, aunque desasociada, usando git checkout
para consultarla directamente:
~/git-prune-demo $ git checkout 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Note: checking out '5178becc2ca965e1728554ce1cb8de2f2c2370b1'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 5178bec... added another line to hello.txt
~/git-prune-demo $ git log
commit 5178becc2ca965e1728554ce1cb8de2f2c2370b1
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 14:49:59 2018 -0700
added another line to hello.txt
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
Cuando extraemos con checkout la confirmación desasociada, Git es lo suficientemente considerado como para mostrarnos un mensaje detallado explicando que estamos en un estado desasociado. Si examinamos el registro aquí, podemos ver que la confirmación “added another line to hello.txt” vuelve a aparecer en la salida del registro. Ahora que sabemos que el repositorio está en un buen estado de simulación con una confirmación desasociada, podemos practicar el uso de git prune
. No obstante, volvamos antes de nada a la rama main
usando git checkout
.
~/git-prune-demo $ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
5178bec added another line to hello.txt
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 5178bec
Switched to branch 'main'
Al volver a main mediante git checkout
, Git vuelve a ser lo suficientemente considerado como para informarnos de que estamos dejando atrás una confirmación desasociada. ¡Ha llegado el momento de eliminarla! Ahora ejecutaremos git prune
, pero debemos pasarle algunas opciones. --dry-run
y --verbose
mostrarán una salida que indica lo que está configurado para eliminarse pero sin eliminarlo realmente.
~/git-prune-demo $ git prune --dry-run --verbose
Lo más probable es que este comando devuelva una salida vacía, lo que implica que git prune no eliminará nada. ¿Por qué podría pasar esto? Bueno, lo más probable es que la confirmación no esté completamente desasociada. Git sigue manteniendo una referencia a ella en algún lugar. Este es un excelente ejemplo de por qué git prune
no debe usarse de forma independiente fuera de git gc
. También es un buen ejemplo de lo difícil que es perder datos por completo con Git.
Lo más probable es que Git esté almacenando una referencia a nuestra confirmación desasociada en el registro de referencias. Podemos investigar ejecutando git reflog. Deberías ver una salida que describa la secuencia de acciones que hemos llevado a cabo para llegar hasta aquí. Para obtener más información sobre git reflog
, visita la página sobre git reflog. Además de conservar el historial en el registro de referencias, Git fija fechas de caducidad internas para determinar cuándo se eliminarán las confirmaciones desasociadas. Como vimos antes, estos son detalles de implementación de los que se encarga git gc
, y git prune
no debería usarse de forma independiente.
Para concluir nuestra demostración de simulación de git prune
, tenemos que borrar el registro de referencias.
~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all
El comando de arriba forzará la caducidad de todas las entradas del registro de referencias que sean más antiguas que “now” (ahora). Este es un comando brutal y peligroso que nunca deberías tener que usar como usuario casual de Git. Estamos ejecutando este comando para ver cómo funciona git prune
cuando se ejecuta correctamente. Con el registro de referencias totalmente borrado, ahora podemos ejecutar git prune
.
~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree
Este comando debería mostrar una lista de referencias de objetos SHA de Git similar a la de arriba.
Uso
git prune
tiene una breve lista de opciones de las que hemos hablado en la sección de descripción general.
-n --dry-run
No ejecuta git prune, solo muestra una salida de lo que hará.
-v --verbose
Muestra una salida con todos los objetos y acciones que lleva a cabo git prune.
--progress
Muestra una salida que indica el progreso de la eliminación con git prune.
--expire <time>
Fuerza la caducidad de los objetos que están en el pasado
<head>…
Si especificas un <head>
, conservarás cualquier opción de esa referencia head
Análisis
¿Cuál es la diferencia entre git prune, git fetch --prune y git remote prune?
git remote prune
y git fetch --prune
hacen lo mismo: borran las referencias a las ramas que no están presentes en el repositorio remoto. Esto es muy conveniente cuando se trabaja en un flujo de trabajo de equipo en el que las ramas remotas se eliminan después de la fusión con main
. El segundo comando, git fetch --prune
, se conecta al repositorio remoto y recupera el estado remoto más reciente antes de llevar a cabo la eliminación. Se trata esencialmente de una combinación de comandos:
git fetch --all && git remote prune
El comando genérico git prune
es completamente diferente. Como vimos en la sección de descripción general, git prune elimina las confirmaciones desasociadas localmente.
¿Cómo limpio las ramas obsoletas?
git fetch --prune
es la mejor utilidad para limpiar ramas obsoletas. Se conecta a un repositorio remoto compartido y recupera todas las referencias a ramas remotas. A continuación, elimina las referencias remotas que ya no se usan en el repositorio remoto.
¿El comando git remote prune origin elimina la rama local?
No, git remote prune origin
solo elimina las referencias a las ramas remotas que ya no existen. Git almacena referencias locales y remotas. Un repositorio tiene colecciones de referencias local/origin
y remote/origin
. git remote prune origin
solo elimina las referencias en remote/origin
. El trabajo local en local/origin
no se modifica.
Resumen de git prune
El comando git prune
está pensado para invocarse como un comando secundario de git gc
. Es muy poco probable que tengas que invocar git prune
durante el trabajo diario de ingeniería de software. Hay que conocer otros comandos para entender los efectos de git prune
. Algunos de los comandos utilizados en este artículo han sido git log
, git reflog
y git checkout
.
Compartir este artículo
Tema siguiente
Lecturas recomendadas
Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.