Git prune
Il comando git prune
è un'utilità di pulizia interna che pulisce gli oggetti Git non raggiungibili oppure "orfani". Gli oggetti non raggiungibili sono oggetti inaccessibili da parte dei riferimenti. Qualsiasi commit a cui non è possibile accedere tramite un branch o un tag è considerato non raggiungibile. In genere, git prune
non viene eseguito direttamente. È considerato un comando di garbage collection ed è un comando secondario del comando git gc.
Panoramica di git prune
Per comprendere gli effetti di git prune
dobbiamo simulare uno scenario in cui un commit diventa non raggiungibile. Quella che segue è una sequenza di esecuzioni della riga di comando volta a simulare questa esperienza.
~ $ 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 sequenza di comandi precedente crea un nuovo repository in una directory denominata git-prune-demo
. Un commit composto da un nuovo file hello.text
viene aggiunto al repository con il contenuto di base di "hello git prune". Modifichiamo quindi hello.txt
e creiamo un nuovo commit a partire da tali modifiche.
~/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(+)
materiale correlato
Come spostare un repository Git completo
Scopri la soluzione
Impara a utilizzare Git con Bitbucket Cloud
Ora abbiamo una cronologia di 2 commit in questo repository dimostrativo. Possiamo eseguire una verifica utilizzando 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
L'output di git log mostra i 2 commit e i messaggi di commit corrispondenti relativi alle modifiche apportate a hello.txt
. Il passo successivo è rendere irraggiungibile uno dei commit. Lo faremo utilizzando il comando git reset. Reimpostiamo lo stato del repository al primo commit, ovvero il commit "added hello.txt".
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
Se ora utilizziamo git log
per esaminare lo stato del repository, possiamo vedere che abbiamo un solo commit.
~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
Il repository dimostrativo è ora in uno stato che contiene un commit scollegato. Il secondo commit che abbiamo effettuato con il messaggio "added another line to hello.txt" non è più visualizzato nell'output di git log
ed è ora scollegato. Può sembrare che il commit sia andato perso o che sia stato eliminato, ma non dimentichiamo che Git fa molta attenzione a non eliminare la cronologia. Possiamo verificare che il commit è ancora disponibile, ma scollegato, utilizzando git checkout
per accedervi direttamente:
~/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
Quando estraiamo il commit scollegato, Git mostra un messaggio dettagliato per informarci che ci troviamo nello stato scollegato. Se esaminiamo il log in questo punto, possiamo vedere che il commit "added another line to hello.txt" è ora di nuovo nell'output del log! Ora che sappiamo che il repository è in un buono stato di simulazione con un commit scollegato, possiamo esercitarci a utilizzare git prune
. Prima però, torniamo al branch 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'
Quando torniamo al branch principale tramite git checkout
, Git ci avvisa che stiamo uscendo da un commit scollegato. È il momento di eliminare questo commit scollegato! Quindi eseguiamo git prune
, ma assicurandoci di trasmettere alcune opzioni a questo comando. --dry-run
e --verbose
mostrano l'output che indica gli elementi impostati per l'eliminazione, ma senza effettivamente eliminarli.
~/git-prune-demo $ git prune --dry-run --verbose
Molto probabilmente questo comando restituirà un output vuoto. L'output vuoto implica che il comando di prune eliminerà effettivamente nulla. Perché succede? Beh, molto probabilmente il commit non è completamente scollegato. Da qualche parte Git mantiene ancora un riferimento ad esso. Questo è un ottimo esempio del motivo per cui git prune
non deve essere usato da solo al di fuori di git gc
. Ed è anche un buon esempio di come sia difficile perdere completamente i dati con Git.
Molto probabilmente Git archivia un riferimento al nostro commit scollegato nel reflog. Possiamo indagare eseguendo git reflog. git reflog. Dovresti vedere un output che descrive la sequenza delle azioni intraprese per arrivare a questo punto. Per maggiori informazioni su git reflog
, visita la pagina git reflog. Oltre a preservare la cronologia nel reflog, in Git sono previste date di scadenza interne in cui verranno eliminati i commit scollegati. Ancora una volta, questi sono tutti dettagli di implementazione gestiti da git gc
e non è consigliabile usare git prune
in modo indipendente.
Per concludere la nostra dimostrazione di simulazione di git prune
, dobbiamo cancellare il reflog
~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all
Il comando precedente forza la scadenza di tutte le voci nel reflog precedenti al momento attuale. Si tratta di un comando brutale e pericoloso che gli utenti occasionali di Git non dovrebbero mai usare; noi lo stiamo eseguendo per dimostrare l'esecuzione corretta di git prune
. Ora che il reflog è stato completamente cancellato, possiamo eseguire git prune
.
~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree
Questo comando dovrebbe generare una lista di riferimenti agli oggetti Git SHA simile a quella riportata sopra.
Utilizzo
git prune
dispone di una breve lista di opzioni descritte nella sezione di panoramica.
-n --dry-run
Non esegue l'eliminazione. Mostra soltanto l'output del comando
-v --verbose
Visualizza l'output di tutti gli oggetti e di tutte le azioni intraprese dal comando di eliminazione
--progress
Visualizza l'output con lo stato di avanzamento dell'eliminazione
--expire <time>
Forza la scadenza degli oggetti successivi
<head>…
Se si specifica un
verranno mantenute tutte le opzioni di tale riferimento head
Discussione
Qual è la differenza tra git prune, git fetch --prune e git remote prune?
git remote prune
e git fetch --prune
hanno la stessa funzione: eliminano i riferimenti ai branch che non esistono sul repository remoto. Sono comandi molto utili quando si lavora in un flusso di lavoro di team in cui i branch remoti vengono eliminati dopo il merge con il branch main
. Il secondo comando, git fetch --prune
si connette al repository remoto e recupera lo stato remoto più recente prima dell'eliminazione. Si tratta essenzialmente di una combinazione di comandi:
git fetch --all && git remote prune
Il comando generico git prune
è completamente diverso. Come discusso nella sezione della panoramica, git prune elimina i commit scollegati localmente.
Come faccio a pulire i branch obsoleti?
git fetch --prune
è la migliore utility per la pulizia dei branch obsoleti. Si connette a un repository remoto condiviso e recupera tutti i riferimenti ai branch remoti. Elimina quindi i riferimenti remoti che non sono più in uso nel repository remoto.
Il comando git remote prune origin elimina il branch locale?
No, il comando git remote prune origin
elimina solo i riferimenti ai branch remoti che non esistono più. Git archivia i riferimenti locali e remoti. I repository contengono raccolte di riferimenti local/origin
e remote/origin
. git remote prune origin
elimina solo i riferimenti in remote/origin
. In questo modo, il lavoro locale rimane protetto in local/origin
.
Riepilogo di git prune
Il comando git prune
è pensato per essere richiamato come comando secondario di git gc
. È altamente improbabile che tu debba mai richiamare git prune
durante le attività giornaliere di progettazione software. Sono necessari altri comandi per comprendere gli effetti di git prune
. Alcuni comandi usati in questo articolo sono git log
, git reflog
e git checkout
.
Condividi l'articolo
Argomento successivo
Letture consigliate
Aggiungi ai preferiti queste risorse per ricevere informazioni sui tipi di team DevOps e aggiornamenti continui su DevOps in Atlassian.