Git prune
De opdracht git prune
is een intern opruimprogramma dat onbereikbare of 'verweesde' Git-objecten opruimt. Onbereikbare objecten zijn objecten die voor geen enkele ref toegankelijk zijn. Elke commit die niet toegankelijk is via een branch of tag, wordt als onbereikbaar beschouwd. git prune
wordt over het algemeen niet rechtstreeks uitgevoerd. Prune wordt beschouwd als een opdracht voor afvalinzameling en is een onderliggende opdracht van de opdracht git gc.
Overzicht van Git Prune
Om de effecten van git prune
te begrijpen, moeten we een scenario simuleren waarin een commit onbereikbaar wordt. Hieronder volgt een reeks opdrachtregeluitvoeringen waarmee deze ervaring wordt gesimuleerd.
~ $ 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"
De voorgaande reeks opdrachten maakt een nieuwe repository aan in een map met de naam git-prune-demo
. Eén commit, bestaande uit een nieuw bestand hello.text
, is toegevoegd aan de repo met de basisinhoud 'hello git prune'. Vervolgens wijzigen we hello.txt
en maken we op basis van die wijzigingen een nieuwe commit aan.
~/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(+)
gerelateerd materiaal
Een volledige Git-repository verplaatsen
Oplossing bekijken
Git leren met Bitbucket Cloud
We hebben nu een geschiedenis van 2 commits in deze demo-repo. We kunnen dit verifiëren met behulp van 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
De output van git-log toont de twee commits en de bijbehorende commitberichten over de wijzigingen die zijn aangebracht in hello.txt
. De volgende stap is dat we een van de commits onbereikbaar maken. We doen dit met de opdracht git reset. We hebben de status van de repo teruggezet naar de eerste commit, de commit 'added hello.txt'.
~/git-prune-demo $ git reset --hard 994b122045cf4bf0b97139231b4dd52ea2643c7e
HEAD is now at 994b122 added hello.txt
Als we nu git log
gebruiken om de status van de repository te onderzoeken, zien we dat we maar één commit hebben.
~/git-prune-demo $ git log
commit 994b122045cf4bf0b97139231b4dd52ea2643c7e
Author: kevzettler <kevzettler@gmail.com>
Date: Sun Sep 30 09:43:41 2018 -0700
added hello.txt
De demo-repository bevindt zich nu in een staat die een losgekoppelde commit bevat. De tweede commit die we hebben gemaakt met het bericht 'added another line to hello.txt', wordt niet langer weergegeven in de output van git log
en is nu losgekoppeld. Het lijkt misschien alsof we de commit verloren of verwijderd hebben, maar Git is erg strikt als het gaat om het niet verwijderen van geschiedenis. We kunnen bevestigen dat de commit nog steeds beschikbaar is (maar is losgekoppeld) door git checkout
te gebruiken om de commit rechtstreeks te bezoeken:
~/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
Als we de losgekoppelde commit bekijken, is Git erop bedacht om ons gedetailleerd uit te leggen dat we ons in een losgekoppelde toestand bevinden. Als we de log hier bekijken, zien we dat de commit 'added another line to hello.txt' weer terug is in de outputlog! Nu we weten dat de repository zich in een goede simulatietoestand bevindt met een losgekoppelde commit, kunnen we oefenen met git prune
. Maar laten we eerst teruggaan naar de main
-branch via 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'
Als je via git checkout
terugkeert naar main, laat Git weten dat we een losgekoppelde commit achterlaten. Het is nu tijd om de losgekoppelde commit op te schonen! Vervolgens voeren we git clean
uit, maar we moeten daar enkele opties aan doorgeven. --dry-run
en --verbose
leveren output op die aangeeft wat er opgeschoond gaat worden zonder het daadwerkelijk op te schonen.
~/git-prune-demo $ git prune --dry-run --verbose
Deze opdracht zal waarschijnlijk lege output retourneren. Lege output houdt in dat er met opschonen eigenlijk niets wordt verwijderd. Hoe kan dit gebeuren? Wel, de commit is waarschijnlijk niet volledig losgekoppeld. Ergens bevat Git er nog steeds een verwijzing naar. Dit is een goed voorbeeld van waarom git prune
niet op zichzelf gebruikt mag worden buiten git gc
. Dit is ook een goed voorbeeld dat laat zien hoe moeilijk het is om gegevens volledig te verliezen met Git.
Hoogstwaarschijnlijk slaat Git een referentie op naar onze losgekoppelde commit in de reflog. We kunnen dit onderzoeken door git reflog uit te voeren. Je zou wat output moeten zien waarin de volgorde wordt beschreven van de acties die we hebben ondernomen om dit te bereiken. Ga voor meer informatie over git reflog
naar de pagina git reflog. Git bewaart niet alleen de geschiedenis in de reflog, maar heeft ook interne vervaldatums voor het verwijderen van losgekoppelde commits. Nogmaals, dit zijn allemaal implementatiedetails die git gc
verwerkt en git prune
mag niet op zichzelf worden gebruikt.
Om onze demo van de git prune
-simulatie af te sluiten, moeten we de reflog wissen.
~/git-prune-demo $ git reflog expire --expire=now --expire-unreachable=now --all
Met de bovenstaande opdracht vervalt alle invoer voor de reflog die ouder is dan nu. Dit is een en grove en gevaarlijke opdracht die je nooit zou moeten gebruiken als informeel Git-gebruiker. We voeren deze opdracht uit om een succesvolle git prune
te illusteren. Nu de reflog volledig is gewist, kunnen we nu git prune
uitvoeren.
~/git-prune-demo $ git prune --dry-run --verbose --expire=now
1782293bdfac16b5408420c5cb0c9a22ddbdd985 blob
5178becc2ca965e1728554ce1cb8de2f2c2370b1 commit
a1b3b83440d2aa956ad6482535cbd121510a3280 commit
f91c3433eae245767b9cd5bdb46cd127ed38df26 tree
Deze opdracht moet een lijst met Git SHA-objectreferenties opleveren die er als hierboven uitziet.
Gebruik
git prune
biedt een korte lijst met opties die we hebben besproken in het overzichtsgedeelte.
-n --dry-run
Voer het opschonen niet uit. Laat alleen een output zien van wat er gaat gebeuren
-v --verbose
Geef de output weer van alle objecten en acties waarop het opschonen betrekking heeft
--progress
Geeft de output weer die de voortgang van het opschonen aangeeft
--expire <time>
Verval forceren van objecten die afgelopen zijn
<head>…
Als je een <head>
specificeert, blijven alle opties van die head-ref behouden
Bespreking
Wat is het verschil tussen Git Prune, Git Fetch --prune en Git Remote Prune?
git remote prune
en git fetch --prune
doen hetzelfde: de refs verwijderen naar branches die niet op de remote bestaan. Dit is zeer wenselijk als je in een teamworkflow werkt waarin externe branches worden verwijderd na samenvoeging met main
. De tweede opdracht, git fetch --prune
, maakt verbinding met de remote en haalt de laatste externe status op voordat je gaat opschonen. Het is in wezen een combinatie van opdrachten:
git fetch --all && git remote prune
De generieke opdracht git prune
is volledig anders. Zoals besproken in het overzichtsgedeelte, verwijdert git prune lokaal losgekoppelde commits.
Hoe schoon ik verouderde branches op?
git fetch --prune
is de beste tool voor het opschonen van verouderde branches. De tool maakt verbinding met een gedeelde externe repository en haalt alle refs naar externe branches op. Vervolgens worden de externe refs verwijderd die niet langer in gebruik zijn in de externe repository.
Verwijdert git remote prune origin de lokale branch?
Nee. git remote prune origin
verwijdert alleen refs naar externe branches die niet meer bestaan. Git slaat zowel lokale als externe refs op. Een repository bevat local/origin
- en remote/origin
-refcollecties. git remote prune origin
schoont alleen de refs in remote/origin
op. Zo blijft lokaal werk in local/origin
veilig.
Overzicht van Git Prune
De opdracht git prune
is bedoeld om aangeroepen te worden als onderliggende opdracht voor git gc
. Het is zeer onwaarschijnlijk dat je git prune
ooit zult moeten aanroepen in het kader van dagelijkse software-engineering. Er zijn andere opdrachten nodig om de effecten van git prune
te begrijpen. Enkele opdrachten die in dit artikel zijn gebruikt, zijn git log
, git reflog
en git checkout
.
Deel dit artikel
Volgend onderwerp
Aanbevolen artikelen
Bookmark deze resources voor meer informatie over soorten DevOps-teams of voor voortdurende updates over DevOps bij Atlassian.