Git LFS

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(+)

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>

Geforceerd verval van objecten die voorbij zijn

<head>…

Als je een , blijven alle opties van die head-ref behouden

Discussie

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.

Klaar om Git te leren?

Probeer deze interactieve tutorial.

Nu aan de slag