Chapters ▾ 2nd Edition

10.7 Git Internals - Onderhoud en Dataherwinning

Onderhoud en Dataherwinning

Soms moet jy dalk 'n bietjie skoonmaakwerk doen – 'n bewaarplek meer kompak maak, 'n ingevoerde bewaarplek skoonmaak, of verlore werk herwin. Hierdie afdeling sal sommige van hierdie scenario’s dek.

Onderhoud

Git voer af en toe outomaties 'n opdrag uit genaamd “auto gc”. Meestal doen hierdie opdrag niks nie. As daar egter te veel los objekte (objekte wat nie in 'n paklêer is nie) of te veel paklêers (packfiles) is, begin Git 'n volwaardige git gc-opdrag. Die “gc” staan vir vullisverwydering (garbage collect), en die opdrag doen 'n aantal dinge: dit versamel al die los objekte en plaas dit in paklêers, dit konsolideer paklêers in een groot paklêer, en dit verwyder objekte wat nie vanaf enige vaslegging bereikbaar is nie en 'n paar maande oud is.

Jy kan auto gc handmatig as volg uitvoer:

$ git gc --auto

Weereens, dit doen oor die algemeen niks nie. Jy moet ongeveer 7 000 los objekte of meer as 50 paklêers hê sodat Git 'n ware gc-opdrag kan aanskakel. Jy kan hierdie limiete verander met onderskeidelik die gc.auto- en gc.autopacklimit-konfigurasie-instellings.

Die ander ding wat gc sal doen, is om jou verwysings (references) in 'n enkele lêer saam te pak. Gestel jou bewaarplek bevat die volgende takke en merkers:

$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1

As jy git gc uitvoer, sal jy nie meer hierdie lêers in die refs-gids hê nie. Git sal hulle ter wille van doeltreffendheid na 'n lêer genaamd .git/packed-refs skuif, wat so lyk:

$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9

As jy 'n verwysing bywerk, wysig Git nie hierdie lêer nie, maar skryf eerder 'n nuwe lêer na refs/heads. Om die gepaste SHA-1 vir 'n gegewe verwysing te kry, kyk Git na daardie verwysing in die refs-gids en kyk dan na die packed-refs-lêer as 'n terugval. Dus, as jy nie 'n verwysing in die refs-gids kan vind nie, is dit waarskynlik in jou packed-refs-lêer.

Let op die laaste reël van die lêer, wat met 'n ^ begin. Dit beteken dat die merker direk daarbo 'n geannoteerde merker is en dat daardie reël die vaslegging is waarna die geannoteerde merker wys.

Dataherwinning

Op een of ander stadium in jou Git-reis mag jy dalk per ongeluk 'n vaslegging (commit) verloor. Oor die algemeen gebeur dit omdat jy 'n tak waarop werk gedoen is geforceerd uitvee, en dit blyk dat jy die tak tog wou hê; of jy doen 'n hard-reset op 'n tak, wat beteken jy laat vaar vasleggings waarvan jy iets wou hê. Gestel dit gebeur, hoe kan jy jou vasleggings terugkry?

Hier is 'n voorbeeld wat die master-tak in jou toetsbewaarplek na 'n ouer vaslegging hard-reset en dan die verlore vasleggings herwin. Eerstens, kom ons kyk waar jou bewaarplek op hierdie stadium is:

$ git log --pretty=oneline
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo.rb a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Skuif nou die master-tak terug na die middelste vaslegging:

$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD is now at 1a410ef Third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Jy het in effek die boonste twee vasleggings verloor – jy het geen tak waarvandaan daardie vasleggings bereikbaar is nie. Jy moet die nuutste vaslegging SHA-1 vind en dan 'n tak byvoeg wat daarna wys. Die kuns is om daardie nuutste vaslegging SHA-1 te vind – dis nie asof jy dit gememoriseer het nie, reg?

Dikwels is die vinnigste manier om 'n hulpmiddel genaamd git reflog te gebruik. Terwyl jy werk, teken Git in stilte aan wat jou HEAD is elke keer as jy dit verander. Elke keer as jy vaslê of takke verander, word die verwysingslog (reflog) bygewerk. Die reflog word ook bygewerk deur die git update-ref-opdrag, wat nog 'n rede is om dit te gebruik in plaas daarvan om net die SHA-1-waarde na jou verwysingslêers te skryf, soos ons in Git-verwysings (Git References) bespreek het. Jy kan enige tyd sien waar jy was deur git reflog uit te voer:

$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: Modify repo.rb a bit
484a592 HEAD@{2}: commit: Create repo.rb

Hier kan ons die twee vasleggings sien wat ons uitgetrek (checked out) gehad het, maar daar is nie veel inligting hier nie. Om dieselfde inligting op 'n baie nuttiger manier te sien, kan ons git log -g uitvoer, wat jou 'n normale log-afvoer vir jou reflog sal gee.

$ git log -g
commit 1a410efbd13591db07496601ebc7a059dd55cfe9
Reflog: HEAD@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri May 22 18:22:37 2009 -0700

		Third commit

commit ab1afef80fac8e34258ff41fc1b867c702daa24b
Reflog: HEAD@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: updating HEAD
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri May 22 18:15:24 2009 -0700

       Modify repo.rb a bit

Dit lyk of die onderste vaslegging die een is wat jy verloor het, sodat jy dit kan herwin deur 'n nuwe tak by daardie vaslegging te skep. Jy kan byvoorbeeld 'n tak genaamd recover-branch by daardie vaslegging (ab1afef) begin:

$ git branch recover-branch ab1afef
$ git log --pretty=oneline recover-branch
ab1afef80fac8e34258ff41fc1b867c702daa24b Modify repo.rb a bit
484a59275031909e19aadb7c92262719cfcdf19a Create repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit

Koel – nou het jy 'n tak genaamd recover-branch wat is waar jou master-tak voorheen was, wat die eerste twee vasleggings weer bereikbaar maak. Vervolgens, gestel jou verlies was om een of ander rede nie in die reflog nie – jy kan dit simuleer deur recover-branch te verwyder en die reflog uit te vee. Nou is die eerste twee vasleggings deur niks bereikbaar nie:

$ git branch -D recover-branch
$ rm -Rf .git/logs/

Omdat die reflog-data in die .git/logs/-gids gehou word, het jy in effek geen reflog nie. Hoe kan jy daardie vaslegging op hierdie stadium herwin? Een manier is om die git fsck-hulpmiddel te gebruik, wat jou databasis vir integriteit kontroleer. As jy dit met die --full opsie uitvoer, wys dit jou alle objekte waarna nie deur 'n ander objek gewys word nie:

$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293

In hierdie geval kan jy jou ontbrekende vaslegging sien na die string “dangling commit”. Jy kan dit op dieselfde manier herwin deur 'n tak by te voeg wat na daardie SHA-1 wys.

Verwydering van Objekte

Daar is baie wonderlike dinge omtrent Git, maar een eienskap wat probleme kan veroorsaak, is die feit dat 'n git clone die hele geskiedenis van die projek aflaai, insluitend elke weergawe van elke lêer. Dit is reg as die hele ding bronkode is, want Git is hoogs geoptimaliseer om daardie data doeltreffend saam te pers. As iemand egter op enige stadium in die geskiedenis van jou projek 'n enkele enorme lêer bygevoeg het, sal elke kloon vir ewig gedwing word om daardie groot lêer af te laai, selfs al is dit in die heel volgende vaslegging uit die projek verwyder. Omdat dit vanuit die geskiedenis bereikbaar is, sal dit altyd daar wees.

Dit kan 'n yslike probleem wees wanneer jy Subversion- of Perforce-bewaarplekke in Git omskakel. Omdat jy nie die hele geskiedenis in daardie stelsels aflaai nie, dra hierdie tipe byvoeging min gevolge. As jy 'n invoer vanaf 'n ander stelsel gedoen het of andersins vind dat jou bewaarplek baie groter is as wat dit behoort te wees, is hier hoe jy groot objekte kan vind en verwyder.

Wees gewaarsku: hierdie tegniek is vernietigend vir jou vasleggingsgeskiedenis. Dit herskryf elke vasleggingsobjek sedert die vroegste boom (tree) wat jy moet verander om 'n grootlêerverwysing te verwyder. As jy dit onmiddellik na 'n invoer doen, voordat enigiemand begin het om werk op die vaslegging te baseer, is jy oukei – andersins moet jy alle bydraers in kennis stel dat hulle hul werk op jou nuwe vasleggings moet rebase.

Om te demonstreer, sal jy 'n groot lêer in jou toetsbewaarplek byvoeg, dit in die volgende vaslegging verwyder, dit vind, en dit permanent uit die bewaarplek verwyder. Eerstens, voeg 'n groot objek by jou geskiedenis:

$ curl -L https://www.kernel.org/pub/software/scm/git/git-2.1.0.tar.gz > git.tgz
$ git add git.tgz
$ git commit -m 'Add git tarball'
[master 7b30847] Add git tarball
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 git.tgz

Oeps – jy wou nie 'n massiewe tarball by jou projek voeg nie. Raak liewer daarvan ontslae:

$ git rm git.tgz
rm 'git.tgz'
$ git commit -m 'Oops - remove large tarball'
[master dadf725] Oops - remove large tarball
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 git.tgz

Nou, voer gc op jou databasis uit en kyk hoeveel spasie jy gebruik:

$ git gc
Counting objects: 17, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (17/17), done.
Total 17 (delta 1), reused 10 (delta 0)

Jy kan die count-objects-opdrag uitvoer om vinnig te sien hoeveel spasie jy gebruik:

$ git count-objects -v
count: 7
size: 32
in-pack: 17
packs: 1
size-pack: 4868
prune-packable: 0
garbage: 0
size-garbage: 0

Die size-pack-inskrywing is die grootte van jou paklêers in kilogrepe, so jy gebruik byna 5MB. Voor die laaste vaslegging het jy nader aan 2K gebruik – dit is duidelik dat die verwydering van die lêer uit die vorige vaslegging dit nie uit jou geskiedenis verwyder het nie. Elke keer as iemand hierdie bewaarplek kloon, sal hulle al 5MB moet kloon net om hierdie klein projekkie te kry, omdat jy per ongeluk 'n groot lêer bygevoeg het. Kom ons raak ontslae daarvan.

Eers moet jy dit vind. In hierdie geval weet jy reeds watter lêer dit is. Maar gestel jy het nie; hoe sou jy identifiseer watter lêer of lêers soveel spasie in beslag neem? As jy git gc uitvoer, is al die objekte in 'n paklêer; jy kan die groot objekte identifiseer deur nog 'n loodgietersopdrag (plumbing command) genaamd git verify-pack uit te voer en op die derde veld in die afvoer, wat lêergrootte is, te sorteer. Jy kan dit ook deur die tail-opdrag pyp, want jy is slegs in die laaste paar grootste lêers geïnteresseerd:

$ git verify-pack -v .git/objects/pack/pack-29…69.idx \
  | sort -k 3 -n \
  | tail -3
dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12
033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob   22044 5792 4977696
82c99a3e86bb1267b236a4b6eff7868d97489af1 blob   4975916 4976258 1438

Die groot objek is heel onder: 5MB. Om uit te vind watter lêer dit is, sal jy die rev-list-opdrag gebruik, wat jy vlugtig in Afdwing van 'n Spesifieke Vasleggingsboodskapformaat (Enforcing a Specific Commit-Message Format) gebruik het. As jy --objects na rev-list deurgee, lys dit al die vaslegging SHA-1’s en ook die blob SHA-1’s met die lêerpaaie wat daarmee geassosieer is. Jy kan dit gebruik om jou blob se naam te vind:

$ git rev-list --objects --all | grep 82c99a3
82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz

Nou moet jy hierdie lêer verwyder uit al die bome in jou verlede. Jy kan maklik sien watter vasleggings hierdie lêer gewysig het:

$ git log --oneline --branches -- git.tgz
dadf725 Oops - remove large tarball
7b30847 Add git tarball

Jy moet al die vasleggings stroomaf (downstream) vanaf 7b30847 herskryf om hierdie lêer ten volle uit jou Git-geskiedenis te verwyder. Om dit te doen, gebruik jy filter-branch, wat jy in Herskryf van Geskiedenis (Rewriting History) gebruik het:

$ git filter-branch --index-filter \
  'git rm --ignore-unmatch --cached git.tgz' -- 7b30847^..
Rewrite 7b30847d080183a1ab7d18fb202473b3096e9f34 (1/2)rm 'git.tgz'
Rewrite dadf7258d699da2c8d89b09ef6670edb7d5f91b4 (2/2)
Ref 'refs/heads/master' was rewritten

Die --index-filter-opsie is soortgelyk aan die --tree-filter-opsie wat in Herskryf van Geskiedenis (Rewriting History) gebruik is, behalwe dat, in plaas daarvan om 'n opdrag deur te gee wat lêers wysig wat op die skyf uitgetrek is, jy elke keer jou voorbereidingsarea (staging area) of indeks wysig.

Eerder as om 'n spesifieke lêer te verwyder met iets soos rm lêer, moet jy dit verwyder met git rm --cached – jy moet dit uit die indeks verwyder, nie van die skyf af nie. Die rede om dit op hierdie manier te doen is spoed – aangesien Git nie elke hersiening op die skyf hoef uit te trek voordat jou filter uitgevoer word nie, kan die proses baie, baie vinniger wees. Jy kan dieselfde taak met --tree-filter verrig as jy wil. Die --ignore-unmatch-opsie vir git rm sê vir dit om nie 'n fout te gooi as die patroon wat jy probeer verwyder nie daar is nie. Uiteindelik vra jy filter-branch om jou geskiedenis slegs vanaf die 7b30847 vaslegging af op te herskryf, want jy weet dat dit is waar hierdie probleem begin het. Anders sal dit van die begin af begin en sal dit onnodig langer neem.

Jou geskiedenis bevat nie meer 'n verwysing na daardie lêer nie. Jou reflog en 'n nuwe stel verwysings wat Git bygevoeg het toe jy die filter-branch gedoen het onder .git/refs/original het egter nog wel, so jy moet dit verwyder en dan die databasis herpak. Jy moet ontslae raak van enigiets wat 'n wyser (pointer) na daardie ou vasleggings het voordat jy herpak:

$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
Counting objects: 15, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (15/15), done.
Total 15 (delta 1), reused 12 (delta 0)

Kom ons kyk hoeveel spasie jy gespaar het.

$ git count-objects -v
count: 11
size: 4904
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0

Die gepakte bewaarplekgrootte is af tot 8K, wat baie beter as 5MB is. Jy kan van die grootte-waarde af sien dat die groot objek nog steeds in jou los objekte is, so dit is nie weg nie; maar dit sal nie oorgedra word tydens 'n push of daaropvolgende kloon nie, en dit is wat belangrik is. As jy regtig wou, kon jy die objek heeltemal verwyder deur git prune met die --expire opsie uit te voer:

$ git prune --expire now
$ git count-objects -v
count: 0
size: 0
in-pack: 15
packs: 1
size-pack: 8
prune-packable: 0
garbage: 0
size-garbage: 0
----```

=== Omgewingsveranderlikes (Environment Variables)

Git loop altyd binne 'n `bash` dop (shell), en gebruik 'n aantal dop-omgewingsveranderlikes om te bepaal hoe dit optree.
Af en toe is dit handig om te weet wat dit is, en hoe hulle gebruik kan word om Git te laat optree soos jy dit wil hê.
Hierdie is nie 'n volledige lys van al die omgewingsveranderlikes waaraan Git aandag gee nie, maar ons sal die nuttigste dek.

==== Globale Gedrag (Global Behavior)

Sommige van Git se algemene gedrag as 'n rekenaarprogram hang af van omgewingsveranderlikes.

*`GIT_EXEC_PATH`* bepaal waar Git na sy subprogramme soek (soos `git-commit`, `git-diff`, en andere).
Jy kan die huidige instelling nagaan deur `git --exec-path` uit te voer.

*`HOME`* word gewoonlik nie as aanpasbaar beskou nie (te veel ander dinge hang daarvan af), maar dit is waar Git na die globale konfigurasielêer soek.
As jy 'n werklik draagbare (portable) Git-installasie wil hê, kompleet met globale konfigurasie, kan jy `HOME` in die draagbare Git se dopprofiel (shell profile) oorskryf.

*`PREFIX`* is soortgelyk, maar vir die stelselwye konfigurasie.
Git soek na hierdie lêer by `$PREFIX/etc/gitconfig`.

*`GIT_CONFIG_NOSYSTEM`*, as dit gestel is, deaktiveer die gebruik van die stelselwye konfigurasielêer.
Dit is nuttig as jou stelselkonfigurasie met jou opdragte inmeng, maar jy nie toegang het om dit te verander of te verwyder nie.

*`GIT_PAGER`* beheer die program wat gebruik word om multi-bladsy afvoer op die opdragreël te vertoon.
As dit nie gestel is nie, sal `PAGER` as 'n terugvalopsie (fallback) gebruik word.

*`GIT_EDITOR`* is die redigeerder wat Git sal aanskakel wanneer die gebruiker 'n bietjie teks moet redigeer (byvoorbeeld 'n vasleggingsboodskap).
As dit nie gestel is nie, sal `EDITOR` gebruik word.

==== Bewaarplekliggings (Repository Locations)

Git gebruik verskeie omgewingsveranderlikes om te bepaal hoe dit met die huidige bewaarplek in wisselwerking tree.

*`GIT_DIR`* is die ligging van die `.git` gids.
As dit nie gespesifiseer is nie, loop Git op in die gidsboom totdat dit by `~` of `/` kom, en soek by elke stap na 'n `.git` gids.

*`GIT_CEILING_DIRECTORIES`* beheer die gedrag van die soektog na 'n `.git` gids.
As jy toegang verkry tot gidse wat stadig laai (soos dié op 'n banddryf, of oor 'n stadige netwerkverbinding), wil jy dalk hê dat Git vroeër ophou probeer as wat dit andersins sou, veral as Git opgeroep word wanneer jou dop-aanwysing (shell prompt) gebou word.

*`GIT_WORK_TREE`* is die ligging van die wortel van die werkgids vir 'n nie-kaal (non-bare) bewaarplek.
As `--git-dir` of `GIT_DIR` gespesifiseer is maar geeneen van `--work-tree`, `GIT_WORK_TREE` of `core.worktree` gespesifiseer is nie, word die huidige werkgids as die boonste vlak van jou werkboom (working tree) beskou.

*`GIT_INDEX_FILE`* is die pad na die indekslêer (slegs nie-kaal bewaarplekke).

*`GIT_OBJECT_DIRECTORY`* kan gebruik word om die ligging van die gids wat gewoonlik by `.git/objects` is, te spesifiseer.

*`GIT_ALTERNATE_OBJECT_DIRECTORIES`* is 'n dubbelpunt-geskeide lys (geformateer soos `/dir/one:/dir/two:…`) wat vir Git vertel waar om vir objekte te kyk as hulle nie in `GIT_OBJECT_DIRECTORY` is nie.
As jy toevallig baie projekte het met groot lêers wat presies dieselfde inhoud het, kan dit gebruik word om te vermy dat te veel kopieë daarvan gestoor word.

==== Padspesifikasies (Pathspecs)

'n "`Padspesifikasie`" ("`pathspec`") verwys na hoe jy paaie na dinge in Git spesifiseer, insluitend die gebruik van jokertekens (wildcards).
Dit word gebruik in die `.gitignore` lêer, maar ook op die opdragreël (`git add *.c`).

*`GIT_GLOB_PATHSPECS`* en *`GIT_NOGLOB_PATHSPECS`* beheer die verstekgedrag van jokertekens in padspesifikasies.
As `GIT_GLOB_PATHSPECS` op 1 gestel is, tree jokertekenkarakters op as jokertekens (wat die verstek is); as `GIT_NOGLOB_PATHSPECS` op 1 gestel is, pas jokertekenkarakters net by hulself, wat beteken iets soos `\*.c` sou slegs pas by 'n lêer _genaamd_ "`\*.c`", eerder as enige lêer waarvan die naam op `.c` eindig.
Jy kan dit in individuele gevalle oorskryf deur die padspesifikasie met `:(glob)` of `:(literal)` te begin, soos in `:(glob)\*.c`.

*`GIT_LITERAL_PATHSPECS`* deaktiveer beide van die bogenoemde gedragte; geen jokertekenkarakters sal werk nie, en die oorskryf-voorvoegsels word ook gedeaktiveer.

*`GIT_ICASE_PATHSPECS`* stel alle padspesifikasies in om op 'n kas-onsensitiewe (case-insensitive) manier te werk.

==== Vaslegging (Committing)

Die finale skepping van 'n Git-vasleggingsobjek word gewoonlik gedoen deur `git-commit-tree`, wat hierdie omgewingsveranderlikes as sy primêre bron van inligting gebruik, en val slegs terug op konfigurasiewaardes as hierdie nie teenwoordig is nie.

*`GIT_AUTHOR_NAME`* is die mensleesbare naam in die "`author`" (outeur) veld.

*`GIT_AUTHOR_EMAIL`* is die e-posadres vir die "`author`" veld.

*`GIT_AUTHOR_DATE`* is die tydstempel wat vir die "`author`" veld gebruik word.

*`GIT_COMMITTER_NAME`* stel die menslike naam vir die "`committer`" (vaslêer) veld.

*`GIT_COMMITTER_EMAIL`* is die e-posadres vir die "`committer`" veld.

*`GIT_COMMITTER_DATE`* word gebruik vir die tydstempel in die "`committer`" veld.

*`EMAIL`* is die terugval-e-posadres ingeval die `user.email` konfigurasiewaarde nie gestel is nie.
As _dit_ nie gestel is nie, val Git terug op die stelsel se gebruiker- en gasheername.

==== Netwerke (Networking)

Git gebruik die `curl` biblioteek om netwerkbedrywighede oor HTTP te doen, so *`GIT_CURL_VERBOSE`* sê vir Git om al die boodskappe wat deur daardie biblioteek gegenereer is, uit te straal.
Dit is soortgelyk aan die uitvoer van `curl -v` op die opdragreël.

*`GIT_SSL_NO_VERIFY`* sê vir Git om nie SSL-sertifikate te verifieer nie.
Dit kan soms nodig wees as jy 'n self-ondertekende sertifikaat gebruik om Git-bewaarplekke oor HTTPS te bedien, of jy in die middel van die opstelling van 'n Git-bediener is, maar nog nie 'n volledige sertifikaat geïnstalleer het nie.

As die datatempo van 'n HTTP-bewerking vir langer as *`GIT_HTTP_LOW_SPEED_TIME`* sekondes laer is as *`GIT_HTTP_LOW_SPEED_LIMIT`* grepe per sekonde, sal Git daardie bewerking staak.
Hierdie waardes oorskryf die `http.lowSpeedLimit` en `http.lowSpeedTime` konfigurasiewaardes.

*`GIT_HTTP_USER_AGENT`* stel die user-agent string wat Git gebruik wanneer hy oor HTTP kommunikeer.
Die verstek is 'n waarde soos `git/2.0.0`.

==== Diffing en Saamsmelting (Diffing and Merging)

*`GIT_DIFF_OPTS`* is 'n bietjie van 'n wanbenaming.
Die enigste geldige waardes is `-u<n>` of `--unified=<n>`, wat die aantal konteksreëls beheer wat in 'n `git diff` opdrag gewys word.

*`GIT_EXTERNAL_DIFF`* word gebruik as 'n oorskrywing vir die `diff.external` konfigurasiewaarde.
As dit gestel is, sal Git hierdie program oproep wanneer `git diff` opgeroep word.

*`GIT_DIFF_PATH_COUNTER`* en *`GIT_DIFF_PATH_TOTAL`* is nuttig van binne die program gespesifiseer deur `GIT_EXTERNAL_DIFF` of `diff.external`.
Die eerste verteenwoordig watter lêer in 'n reeks gediff word (beginnend by 1), en die tweede is die totale aantal lêers in die groep.

*`GIT_MERGE_VERBOSITY`* beheer die afvoer vir die rekursiewe saamsmeltingstrategie.
Die toegelate waardes is soos volg:

* 0 voer niks uit nie, behalwe moontlik 'n enkele foutboodskap.
* 1 wys slegs konflikte.
* 2 wys ook lêerveranderings.
* 3 wys wanneer lêers oorgeslaan word omdat dit nie verander het nie.
* 4 wys alle paaie soos dit verwerk word.
* 5 en hoër wys gedetailleerde ontfoutingsinligting (debugging information).

Die verstekwaarde is 2.

==== Ontfouting (Debugging)

Wil jy _regtig_ weet waarmee Git besig is?
Git het 'n redelik volledige stel spore (traces) ingebed, en al wat jy hoef te doen is om dit aan te skakel.
Die moontlike waardes van hierdie veranderlikes is soos volg:

* "`true`", "`1`", of "`2`" – die spoorkategorie word na stderr geskryf.
* 'n Absolute pad wat met `/` begin – die spoorafvoer sal na daardie lêer geskryf word.

*`GIT_TRACE`* beheer algemene spore, wat nie in enige spesifieke kategorie pas nie.
Dit sluit die uitbreiding van aliassen en delegering na ander subprogramme in.

[source,console]

$ GIT_TRACE=true git lga 20:12:49.877982 git.c:554 trace: exec: 'git-lga' 20:12:49.878369 run-command.c:341 trace: run_command: 'git-lga' 20:12:49.879529 git.c:282 trace: alias expansion: lga ⇒ 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all' 20:12:49.879885 git.c:349 trace: built-in: git 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all' 20:12:49.899217 run-command.c:341 trace: run_command: 'less' 20:12:49.899675 run-command.c:192 trace: exec: 'less'

*`GIT_TRACE_PACK_ACCESS`* beheer die opsporing van paklêer-toegang (packfile access).
Die eerste veld is die paklêer wat verkry word, die tweede is die relatiewe verskuiwing (offset) binne daardie lêer:

[source,console]

$ GIT_TRACE_PACK_ACCESS=true git status 20:10:12.081397 sha1_file.c:2088 .git/objects/pack/pack-c3fa…​291e.pack 12 20:10:12.081886 sha1_file.c:2088 .git/objects/pack/pack-c3fa…​291e.pack 34662 20:10:12.082115 sha1_file.c:2088 .git/objects/pack/pack-c3fa…​291e.pack 35175 # […] 20:10:12.087398 sha1_file.c:2088 .git/objects/pack/pack-e80e…​e3d2.pack 56914983 20:10:12.087419 sha1_file.c:2088 .git/objects/pack/pack-e80e…​e3d2.pack 14303666 On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean

*`GIT_TRACE_PACKET`* maak pakkievlak-opsporing (packet-level tracing) vir netwerkbedrywighede moontlik.

[source,console]

$ GIT_TRACE_PACKET=true git ls-remote origin 20:15:14.867043 pkt-line.c:46 packet: git< # service=git-upload-pack 20:15:14.867071 pkt-line.c:46 packet: git< 0000 20:15:14.867079 pkt-line.c:46 packet: git< 97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2.0.4 20:15:14.867088 pkt-line.c:46 packet: git< 0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-show-diff-func-name 20:15:14.867094 pkt-line.c:46 packet: git< 36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config # […]

*`GIT_TRACE_PERFORMANCE`* beheer die aanteken van prestasiedata.
Die afvoer wys hoe lank elke spesifieke `git` oproep neem.

[source,console]

$ GIT_TRACE_PERFORMANCE=true git gc 20:18:19.499676 trace.c:414 performance: 0.374835000 s: git command: 'git' 'pack-refs' '--all' '--prune' 20:18:19.845585 trace.c:414 performance: 0.343020000 s: git command: 'git' 'reflog' 'expire' '--all' Counting objects: 170994, done. Delta compression using up to 8 threads. Compressing objects: 100% (43413/43413), done. Writing objects: 100% (170994/170994), done. Total 170994 (delta 126176), reused 170524 (delta 125706) 20:18:23.567927 trace.c:414 performance: 3.715349000 s: git command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack' 20:18:23.584728 trace.c:414 performance: 0.000910000 s: git command: 'git' 'prune-packed' 20:18:23.605218 trace.c:414 performance: 0.017972000 s: git command: 'git' 'update-server-info' 20:18:23.606342 trace.c:414 performance: 3.756312000 s: git command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago' Checking connectivity: 170994, done. 20:18:25.225424 trace.c:414 performance: 1.616423000 s: git command: 'git' 'prune' '--expire' '2.weeks.ago' 20:18:25.232403 trace.c:414 performance: 0.001051000 s: git command: 'git' 'rerere' 'gc' 20:18:25.233159 trace.c:414 performance: 6.112217000 s: git command: 'git' 'gc'

*`GIT_TRACE_SETUP`* wys inligting oor wat Git ontdek oor die bewaarplek en omgewing waarmee hy interaksie het.

[source,console]

$ GIT_TRACE_SETUP=true git status 20:19:47.086765 trace.c:315 setup: git_dir: .git 20:19:47.087184 trace.c:316 setup: worktree: /Users/ben/src/git 20:19:47.087191 trace.c:317 setup: cwd: /Users/ben/src/git 20:19:47.087194 trace.c:318 setup: prefix: (null) On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean

==== Diverse (Miscellaneous)

*`GIT_SSH`*, indien gespesifiseer, is 'n program wat in plaas van `ssh` opgeroep word wanneer Git aan 'n SSH-gasheer probeer koppel.
Dit word opgeroep as `$GIT_SSH [username@]host [-p <port>] <command>`.
Let op dat dit nie die maklikste manier is om aan te pas hoe `ssh` opgeroep word nie; dit sal nie ekstra opdragreëlparameters ondersteun nie.
Om ekstra opdragreëlparameters te ondersteun, kan jy *`GIT_SSH_COMMAND`* gebruik, 'n toedraaiskrip (wrapper script) skryf en `GIT_SSH` stel om daarna te wys, of die `~/.ssh/config` lêer gebruik.

*`GIT_SSH_COMMAND`* stel die SSH-opdrag wat gebruik word wanneer Git aan 'n SSH-gasheer probeer koppel.
Die opdrag word deur die dop geïnterpreteer, en ekstra opdragreëlargumente kan met `ssh` gebruik word, soos `GIT_SSH_COMMAND="ssh -i ~/.ssh/my_key" git clone git@example.com:my/repo`.

*`GIT_ASKPASS`* is 'n oorskrywing (override) vir die `core.askpass` konfigurasiewaarde.
Dit is die program wat opgeroep word wanneer Git die gebruiker vir aanmeldbewyse moet vra, wat 'n teksaanwysing as 'n opdragreëlargument kan verwag, en die antwoord op `stdout` behoort terug te gee (sien <<_credential_caching>> vir meer oor hierdie substelsel).

*`GIT_NAMESPACE`* beheer toegang tot naamspasie-verwysings (namespaced refs), en is ekwivalent aan die `--namespace` vlag.
Dit is meestal nuttig aan die bedienerkant, waar jy dalk veelvuldige vurke (forks) van 'n enkele bewaarplek in een bewaarplek wil stoor, en net die verwysings apart wil hou.

*`GIT_FLUSH`* kan gebruik word om Git te dwing om nie-gebufferde I/O te gebruik wanneer dit inkrementeel na stdout skryf.
'n Waarde van 1 veroorsaak dat Git meer gereeld spoel (flush), 'n waarde van 0 veroorsaak dat alle afvoer gebuffer word.
Die verstekwaarde (as hierdie veranderlike nie gestel is nie) is om 'n gepaste bufferingskema te kies na gelang van die aktiwiteit en die afvoermodus.

*`GIT_REFLOG_ACTION`* laat jou toe om die beskrywende teks te spesifiseer wat na die verwysingslog (reflog) geskryf word.
Hier is 'n voorbeeld:

[source,console]

$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'My message' [master 9e3d55a] My message $ git reflog -1 9e3d55a HEAD@{0}: my action: My message

=== Summary

At this point, you should have a pretty good understanding of what Git does in the background and, to some degree, how it's implemented.
This chapter has covered a number of plumbing commands -- commands that are lower level and simpler than the porcelain commands you've learned about in the rest of the book.
Understanding how Git works at a lower level should make it easier to understand why it's doing what it's doing and also to write your own tools and helper scripts to make your specific workflow work for you.

Git as a content-addressable filesystem is a very powerful tool that you can easily use as more than just a VCS.
We hope you can use your newfound knowledge of Git internals to implement your own cool application of this technology and feel more comfortable using Git in more advanced ways.


[[A-git-in-other-environments]]
[appendix]
== Git in Other Environments

If you read through the whole book, you've learned a lot about how to use Git at the command line.
You can work with local files, connect your repository to others over a network, and work effectively with others.
But the story doesn't end there; Git is usually used as part of a larger ecosystem, and the terminal isn't always the best way to work with it.
Now we'll take a look at some of the other kinds of environments where Git can be useful, and how other applications (including yours) work alongside Git.

== Grafiese Koppelvlakke (Graphical Interfaces)

(((GUIs)))(((Grafiese hulpmiddels)))
Git se natuurlike omgewing is in die terminaal.
Nuwe kenmerke verskyn eerste daar, en slegs op die opdragreël (command line) is die volle krag van Git heeltemal tot jou beskikking.
Maar gewone teks is nie die beste keuse vir alle take nie; soms is 'n visuele voorstelling wat jy nodig het, en sommige gebruikers is baie meer gemaklik met 'n wys-en-klik-koppelvlak.

Dit is belangrik om daarop te let dat verskillende koppelvlakke vir verskillende werkvloeie (workflows) aangepas is.
Sommige kliënte stel slegs 'n noukeurig uitgesoekte substel van Git-funksionaliteit bloot, ten einde 'n spesifieke manier van werk te ondersteun wat die outeur as effektief beskou.
In hierdie lig gesien, kan nie een van hierdie hulpmiddels "`beter`" as enige van die ander genoem word nie; hulle is bloot meer geskik vir hul beoogde doel.
Let ook daarop dat daar niks is wat hierdie grafiese kliënte kan doen wat die opdragreël-kliënt nie kan doen nie; die opdragreël is steeds waar jy die meeste krag en beheer sal hê wanneer jy met jou bewaarplekke werk.

==== `gitk` en `git-gui`

(((git opdragte, gitk)))(((git opdragte, gui)))(((gitk)))
Wanneer jy Git installeer, kry jy ook sy visuele hulpmiddels, `gitk` en `git-gui`.

`gitk` is 'n grafiese geskiedeniskyker (history viewer).
Dink daaraan as 'n kragtige GUI-dop (shell) oor `git log` en `git grep`.
Dit is die hulpmiddel om te gebruik wanneer jy probeer om iets te vind wat in die verlede gebeur het, of jou projek se geskiedenis wil visualiseer.

Gitk is die maklikste om vanaf die opdragreël op te roep.
Gaan net met `cd` na 'n Git-bewaarplek, en tik:

[source,console]

$ gitk [git log options]

Gitk aanvaar baie opdragreëlopsies, waarvan die meeste na die onderliggende `git log` aksie deurgegee word.
Waarskynlik een van die nuttigste is die `--all` vlag, wat vir `gitk` sê om vasleggings (commits) te wys wat vanaf _enige_ verwysing bereikbaar is, nie net HEAD nie.
Gitk se koppelvlak lyk so:

.Die `gitk` geskiedeniskyker
image::images/gitk.png[The `gitk` history viewer]

Aan die bokant is iets wat 'n bietjie soos die afvoer van `git log --graph` lyk; elke kolletjie verteenwoordig 'n vaslegging, die lyne verteenwoordig ouerverhoudings, en verwysings (refs) word as gekleurde boksies gewys.
Die geel kolletjie verteenwoordig HEAD, en die rooi kolletjie verteenwoordig veranderings wat nog 'n vaslegging moet word.
Aan die onderkant is 'n aansig van die gekose vaslegging; die kommentaar en pleister (patch) aan die linkerkant, en 'n opsommingsaansig aan die regterkant.
Tussenin is 'n versameling kontroles wat gebruik word om deur die geskiedenis te soek.

`git-gui`, aan die ander kant, is hoofsaaklik 'n hulpmiddel vir die samestelling (crafting) van vasleggings.
Dit is ook die maklikste om vanaf die opdragreël op te roep:

[source,console]

$ git gui

En dit lyk min of meer soos volg:

.Die `git-gui` vasleggingshulpmiddel
image::images/git-gui.png[The `git-gui` commit tool]

Aan die linkerkant is die indeks; onvoorbereide (unstaged) veranderings is bo, voorbereide (staged) veranderings is onder.
Jy kan hele lêers tussen die twee toestande skuif deur op hul ikone te klik, of jy kan 'n lêer kies om te besigtig deur op sy naam te klik.

Regs bo is die verskilaansig (diff view), wat die veranderings vir die tans gekose lêer wys.
Jy kan individuele stukke (hunks) of individuele reëls voorberei (stage) deur regs in hierdie area te klik.

Regs onder is die boodskap- en aksie-area.
Tik jou boodskap in die tekskassie en klik "`Commit`" om iets soortgelyks as `git commit` te doen.
Jy kan ook kies om die laaste vaslegging te wysig (amend) deur die "`Amend`" radioknoppie te kies, wat die "`Staged Changes`" area sal opdateer met die inhoud van die laaste vaslegging.
Dan kan jy bloot sommige veranderings voorberei of ongedaan maak, die vasleggingsboodskap verander, en weer "`Commit`" klik om die ou vaslegging met 'n nuwe een te vervang.

`gitk` en `git-gui` is voorbeelde van taakgeoriënteerde hulpmiddels.
Elkeen van hulle is aangepas vir 'n spesifieke doel (onderskeidelik die besigtiging van geskiedenis en die skep van vasleggings), en laat die kenmerke weg wat nie vir daardie taak nodig is nie.

==== GitHub vir macOS en Windows

(((GitHub vir macOS)))(((GitHub vir Windows)))
GitHub het twee werkvloeigeoriënteerde Git-kliënte geskep: een vir Windows, en een vir macOS.
Hierdie kliënte is 'n goeie voorbeeld van werkvloeigeoriënteerde hulpmiddels – eerder as om _al_ Git se funksionaliteit bloot te stel, fokus hulle eerder op 'n uitgesoekte stel algemeen gebruikte kenmerke wat goed saamwerk.
Hulle lyk soos volg:

.GitHub vir macOS
image::images/github_mac.png[GitHub for macOS]

.GitHub vir Windows
image::images/github_win.png[GitHub for Windows]

Hulle is ontwerp om baie dieselfde te lyk en te werk, so ons sal hulle as 'n enkele produk in hierdie hoofstuk hanteer.
Ons gaan nie 'n gedetailleerde oorsig van hierdie hulpmiddels gee nie (hulle het hul eie dokumentasie), maar 'n vinnige toer deur die "`changes`" (veranderings) aansig (wat is waar jy die meeste van jou tyd sal spandeer) is gepas.

* Aan die linkerkant is die lys van bewaarplekke wat die kliënt naspoor; jy kan 'n bewaarplek byvoeg (hetsy deur te kloon of plaaslik aan te heg) deur op die "`{plus}`" ikoon aan die bokant van hierdie area te klik.
* In die middel is 'n vasleggingsinvoer-area, wat jou toelaat om 'n vasleggingsboodskap in te voer en te kies watter lêers ingesluit moet word. Op Windows word die vasleggingsgeskiedenis direk hieronder vertoon; op macOS is dit op 'n aparte oortjie.
* Aan die regterkant is 'n verskilaansig (diff view), wat wys wat in jou werkgids verander het, of watter veranderings in die gekose vaslegging ingesluit was.
* Die laaste ding om op te let, is die "`Sync`" (sinchroniseer) knoppie regs bo, wat die primêre manier is waarop jy oor die netwerk interaksie het.

[NOTE]
====
Jy het nie 'n GitHub-rekening nodig om hierdie hulpmiddels te gebruik nie.
Alhoewel hulle ontwerp is om GitHub se diens en aanbevole werkvloei uit te lig, sal hulle gelukkig met enige bewaarplek werk, en netwerkbedrywighede met enige Git-gasheer doen.
====

===== Installasie (Installation)

GitHub vir Windows en macOS kan afgelaai word vanaf https://desktop.github.com/[^].
Wanneer die toepassings vir die eerste keer oopgemaak word, lei hulle jou deur die eenmalige Git-opstelling, soos die konfigurasie van jou naam en e-posadres, en beide stel sinvolle verstekwaardes (sane defaults) op vir baie algemene konfigurasie-opsies, soos aanmeldbewys-kasgeheues (credential caches) en CRLF-gedrag.

Beide is "`immergroen`" ("`evergreen`") – opdaterings word in die agtergrond afgelaai en geïnstalleer terwyl die toepassings oop is.
Dit sluit nuttig 'n gebundelde weergawe van Git in, wat beteken jy sal waarskynlik nie hoef te bekommer om dit ooit weer handmatig op te dateer nie.
Op Windows sluit die kliënt 'n kortpad in om PowerShell met Posh-git te loods, waaroor ons later in hierdie hoofstuk meer sal praat.

Die volgende stap is om die hulpmiddel 'n paar bewaarplekke te gee om mee te werk.
Die kliënt wys jou 'n lys van die bewaarplekke waartoe jy op GitHub toegang het, en kan hulle in een stap kloon.
As jy reeds 'n plaaslike bewaarplek het, sleep net sy gids vanaf die Finder of Windows Explorer in die GitHub-kliëntvenster in, en dit sal by die lys bewaarplekke aan die linkerkant ingesluit word.

===== Aanbevole Werkvloei (Recommended Workflow)

Sodra dit geïnstalleer en gekonfigureer is, kan jy die GitHub-kliënt vir baie algemene Git-take gebruik.
Die beoogde werkvloei vir hierdie hulpmiddel word soms die "`GitHub Flow`" genoem.
Ons dek dit in meer detail in <<ch06-github_flow>>, maar die algemene idee is dat (a) jy na 'n tak sal vaslê, en (b) jy redelik gereeld met 'n afgeleë bewaarplek sal sinchroniseer.

Takbestuur (Branch management) is een van die areas waar die twee hulpmiddels van mekaar verskil.
Op macOS is daar 'n knoppie aan die bokant van die venster om 'n nuwe tak te skep:

."Create Branch" (Skep Tak) knoppie op macOS
image::images/branch_widget_mac.png[“Create Branch” button on macOS]

Op Windows word dit gedoen deur die nuwe tak se naam in die tak-skakel-legstuk (branch-switching widget) te tik:

.Die skep van 'n tak op Windows
image::images/branch_widget_win.png[Creating a branch on Windows]

Sodra jou tak geskep is, is dit redelik eenvoudig om nuwe vasleggings te maak.
Maak 'n paar veranderings in jou werkgids, en wanneer jy oorskakel na die GitHub-kliëntvenster, sal dit jou wys watter lêers verander het.
Voer 'n vasleggingsboodskap in, kies die lêers wat jy wil insluit, en klik die "`Commit`" knoppie (ctrl-enter of ⌘-enter).

Die hoofmanier waarop jy interaksie het met ander bewaarplekke oor die netwerk, is deur die "`Sync`" (sinchroniseer) funksie.
Git het intern aparte bewerkings vir push, fetch, merge en rebase, maar die GitHub-kliënte vou al hierdie in een meerstap-funksie ineen.
Hier is wat gebeur as jy die Sync-knoppie klik:

. `git pull --rebase`.
  As dit misluk as gevolg van 'n saamsmeltingskonflik (merge conflict), val dit terug na `git pull --no-rebase`.
. `git push`.

Dit is die mees algemene volgorde van netwerkopdragte wanneer jy in hierdie styl werk, so om hulle in een opdrag saam te pers (squash) bespaar baie tyd.

===== Opsomming (Summary)

Hierdie hulpmiddels is uiters geskik vir die werkvloei waarvoor hulle ontwerp is.
Ontwikkelaars en nie-ontwikkelaars gelyk kan binne minute aan 'n projek saamwerk, en baie van die beste praktyke vir hierdie soort werkvloei is in die hulpmiddels ingebou.
As jou werkvloei egter verskil, of jy meer beheer wil hê oor hoe en wanneer netwerkbedrywighede gedoen word, beveel ons aan dat jy 'n ander kliënt of die opdragreël gebruik.

==== Ander GUI's (Other GUIs)

Daar is 'n aantal ander grafiese Git-kliënte, en hulle strek oor die hele spektrum, van gespesialiseerde enkeldoel-hulpmiddels tot by toepassings wat probeer om alles bloot te stel wat Git kan doen.
Die amptelike Git-webwerf het 'n saamgestelde lys van die gewildste kliënte by https://git-scm.com/downloads/guis[^].
'n Meer omvattende lys is beskikbaar op die Git-wiki-webwerf, by https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools.html#Graphical_Interfaces[^].

=== Git in Visual Studio

(((Visual Studio)))
Visual Studio has Git tooling built directly into the IDE, starting with Visual Studio 2019 version 16.8.

The tooling supports the following Git functionality:

* Create or clone a repository.
* Open and browse history of a repository.
* Create and checkout branches and tags.
* Stash, stage, and commit changes.
* Fetch, pull, push, or sync commits.
* Merge and rebase branches.
* Resolve merge conflicts.
* View diffs.
* ... and more!

Read the https://learn.microsoft.com/en-us/visualstudio/version-control/[official documentation^] to learn more.


=== Git in Visual Studio Code

(((Visual Studio Code)))
Visual Studio Code has Git support built in.
You will need to have Git version 2.0.0 (or newer) installed.

The main features are:

* See the diff of the file you are editing in the gutter.
* The Git Status Bar (lower left) shows the current branch, dirty indicators, incoming and outgoing commits.
* You can do the most common git operations from within the editor:
** Initialize a repository.
** Clone a repository.
** Create branches and tags.
** Stage and commit changes.
** Push/pull/sync with a remote branch.
** Resolve merge conflicts.
** View diffs.
* With an extension, you can also handle GitHub Pull Requests:
  https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github[^].

The official documentation can be found here: https://code.visualstudio.com/docs/sourcecontrol/overview[^].


=== Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine

(((JetBrains)))
JetBrains IDEs (such as IntelliJ IDEA, PyCharm, WebStorm, PhpStorm, RubyMine, and others) ship with a Git Integration plugin.
It provides a dedicated view in the IDE to work with Git and GitHub Pull Requests.

.Version Control ToolWindow in JetBrains IDEs
image::images/jb.png[Version Control ToolWindow in JetBrains IDEs]

The integration relies on the command-line Git client, and requires one to be installed.
The official documentation is available at https://www.jetbrains.com/help/idea/using-git-integration.html[^].


=== Git in Sublime Text

(((Sublime Text)))
From version 3.2 onwards, Sublime Text has Git integration in the editor.

The features are:

* The sidebar will show the `git status` of files and folders with a badge/icon.
* Files and folders that are in your `.gitignore` file will be faded out in the sidebar.
* In the status bar, you can see the current Git branch and how many modifications you have made.
* All changes to a file are now visible via markers in the gutter.
* You can use part of the Sublime Merge Git client functionality from within Sublime Text.
  This requires that Sublime Merge is installed.
  See: https://www.sublimemerge.com/[^].

The official documentation for Sublime Text can be found here: https://www.sublimetext.com/docs/git_integration.html[^].


=== Git in Bash

(((bash)))(((oortjie-voltooiing, bash)))(((dop-aanwysings, bash)))
As jy 'n Bash-gebruiker is, kan jy sommige van jou dop (shell) se kenmerke inspan om jou ervaring met Git baie vriendeliker te maak.
Git kom eintlik met inproppe (plugins) vir verskeie doppe, maar dit is nie by verstek aangeskakel nie.

Eerstens moet jy 'n kopie van die voltooiingslêer kry uit die bronkode van die Git-vrystelling wat jy gebruik.
Gaan jou weergawe na deur `git version` in te tik, en gebruik dan `git checkout tags/vX.Y.Z`, waar `vX.Y.Z` ooreenstem met die weergawe van Git wat jy gebruik.
Kopieer die `contrib/completion/git-completion.bash` lêer na 'n gerieflike plek, soos jou tuisgids (home directory), en voeg dit by jou `.bashrc`:

[source,console]
  1. ~/git-completion.bash

Sodra dit gedoen is, verander jou gids na 'n Git-bewaarplek en tik:

[source,console]

$ git chec<tab>

…en Bash sal outomaties voltooi na `git checkout`.
Dit werk met al Git se subopdragte, opdragreëlparameters, en afgeleë (remotes) en verwysingsname waar toepaslik.

Dit is ook nuttig om jou aanwysing (prompt) aan te pas om inligting oor die huidige gids se Git-bewaarplek te wys.
Dit kan so eenvoudig of kompleks wees as wat jy wil, maar daar is oor die algemeen 'n paar belangrike stukke inligting wat die meeste mense wil hê, soos die huidige tak en die status van die werkgids.
Om dit by jou aanwysing te voeg, kopieer net die `contrib/completion/git-prompt.sh` lêer vanaf Git se bronbewaarplek na jou tuisgids, en voeg so iets by jou `.bashrc`:

[source,console]
  1. ~/git-prompt.sh export GIT_PS1_SHOWDIRTYSTATE=1 export PS1='\w$(__git_ps1 " (%s)")\$ '

Die `\w` beteken druk die huidige werkgids, die `\$` druk die `$` gedeelte van die aanwysing, en `__git_ps1 " (%s)"` roep die funksie uit wat deur `git-prompt.sh` verskaf word met 'n formateringsargument.
Nou sal jou bash-aanwysing so lyk wanneer jy enige plek binne 'n Git-beheerde projek is:

.Gepasmaakte `bash` aanwysing
image::images/git-bash.png[Gepasmaakte `bash` aanwysing]

Beide hierdie skrippe kom met nuttige dokumentasie; kyk na die inhoud van `git-completion.bash` en `git-prompt.sh` vir meer inligting.

=== Git in Zsh

(((zsh)))(((oortjie-voltooiing, zsh)))(((dop-aanwysings, zsh)))
Zsh kom ook met 'n oortjie-voltooiing (tab-completion) biblioteek vir Git.
Om dit te gebruik, voer eenvoudig `autoload -Uz compinit && compinit` in jou `.zshrc` uit.
Zsh se koppelvlak is ietwat kragtiger as dié van Bash:

[source,console]

$ git che<tab> check-attr  — vertoon gitattributes inligting check-ref-format  — maak seker dat 'n verwysingsnaam goed gevorm is checkout  — trek 'n tak of paaie na die werkboom uit (checkout) checkout-index  — kopieer lêers van die indeks na die werkgids cherry  — vind vasleggings wat nie stroomop ingesmelt is nie cherry-pick  — pas veranderings toe wat deur sekere bestaande vasleggings ingestel is

Dubbelsinnige oortjie-voltooiings word nie net gelys nie; hulle het nuttige beskrywings, en jy kan grafies deur die lys navigeer deur herhaaldelik die oortjie-sleutel (tab) te druk.
Dit werk met Git-opdragte, hul argumente, en name van dinge binne die bewaarplek (soos verwysings en remotes), sowel as lêername en al die ander dinge wat Zsh weet hoe om met oortjies te voltooi.

Zsh kom met 'n raamwerk om inligting van weergawebeheerstelsels te kry, genaamd `vcs_info`.
Om die taknaam by die aanwysing (prompt) aan die regterkant in te sluit, voeg hierdie reëls by jou `~/.zshrc` lêer:

[source,console]

autoload -Uz vcs_info precmd_vcs_info() { vcs_info } precmd_functions+=( precmd_vcs_info ) setopt prompt_subst RPROMPT='${vcs_info_msg_0_}' # PROMPT='${vcs_info_msg_0_}%# ' zstyle ':vcs_info:git:*' formats '%b'

Dit lei tot 'n vertoning van die huidige tak aan die regterkant van die terminaalvenster, wanneer jou dop in 'n Git-bewaarplek is.
Die linkerkant word natuurlik ook ondersteun; verwyder net die opmerkingsteken by die toewysing aan `PROMPT`.
Dit lyk 'n bietjie soos volg:

.Gepasmaakte `zsh` aanwysing
image::images/zsh-prompt.png[Gepasmaakte `zsh` aanwysing]

Vir meer inligting oor `vcs_info`, kyk na die dokumentasie in die `zshcontrib(1)` handleidingsbladsy (manual page), of aanlyn by https://zsh.sourceforge.io/Doc/Release/User-Contributions.html#Version-Control-Information[^].

In plaas van `vcs_info`, verkies jy dalk die aanwysing-aanpassingskrip (prompt customization script) wat saam met Git kom, genaamd `git-prompt.sh`; kyk na https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh[^] vir besonderhede.
`git-prompt.sh` is versoenbaar met beide Bash en Zsh.

Zsh is kragtig genoeg dat daar hele raamwerke is wat daaraan toegewy is om dit beter te maak.
Een daarvan word "oh-my-zsh" genoem, en dit kan gevind word by https://github.com/ohmyzsh/ohmyzsh[^].
oh-my-zsh se inpropstelsel kom met kragtige Git-oortjie-voltooiing, en dit het 'n verskeidenheid aanwysingstemas ("themes"), waarvan baie weergawebeheerdata vertoon.
<<oh_my_zsh_git>> is net een voorbeeld van wat met hierdie stelsel gedoen kan word.

[[oh_my_zsh_git]]
.'n Voorbeeld van 'n oh-my-zsh tema
image::images/zsh-oh-my.png['n Voorbeeld van 'n oh-my-zsh tema]

[[_git_powershell]]
=== Git in PowerShell

(((PowerShell)))(((tab completion, PowerShell)))(((shell prompts, PowerShell)))
(((posh-git)))
The legacy command-line terminal on Windows (`cmd.exe`) isn't really capable of a customized Git experience, but if you're using PowerShell, you're in luck.
This also works if you're running PowerShell Core on Linux or macOS.
A package called posh-git (https://github.com/dahlbyk/posh-git[^]) provides powerful tab-completion facilities, as well as an enhanced prompt to help you stay on top of your repository status.
It looks like this:

.PowerShell with Posh-git
image::images/posh-git.png[PowerShell with Posh-git]

==== Installation

===== Prerequisites (Windows only)

Before you're able to run PowerShell scripts on your machine, you need to set your local `ExecutionPolicy` to `RemoteSigned` (basically, anything except `Undefined` and `Restricted`).
If you choose `AllSigned` instead of `RemoteSigned`, also local scripts (your own) need to be digitally signed in order to be executed.
With `RemoteSigned`, only scripts having the `ZoneIdentifier` set to `Internet` (were downloaded from the web) need to be signed, others not.
If you're an administrator and want to set it for all users on that machine, use `-Scope LocalMachine`.
If you're a normal user, without administrative rights, you can use `-Scope CurrentUser` to set it only for you.

More about PowerShell Scopes: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes[^].

More about PowerShell ExecutionPolicy: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy[^].

To set the value of `ExecutionPolicy` to `RemoteSigned` for all users use the next command:

[source,powershell]

Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned -Force

===== PowerShell Gallery

If you have at least PowerShell 5 or PowerShell 4 with PackageManagement installed, you can use the package manager to install posh-git for you.

More information about PowerShell Gallery: https://learn.microsoft.com/en-us/powershell/scripting/gallery/overview[^].

[source,powershell]

Install-Module posh-git -Scope CurrentUser -Force Install-Module posh-git -Scope CurrentUser -AllowPrerelease -Force # Newer beta version with PowerShell Core support

If you want to install posh-git for all users, use `-Scope AllUsers` instead and execute the command from an elevated PowerShell console.
If the second command fails with an error like `Module 'PowerShellGet' was not installed by using Install-Module`, you'll need to run another command first:

[source,powershell]

Install-Module PowerShellGet -Force -SkipPublisherCheck

Then you can go back and try again.
This happens, because the modules that ship with Windows PowerShell are signed with a different publishment certificate.

===== Update PowerShell Prompt

To include Git information in your prompt, the posh-git module needs to be imported.
To have posh-git imported every time PowerShell starts, execute the `Add-PoshGitToProfile` command which will add the import statement into your `$profile` script.
This script is executed everytime you open a new PowerShell console.
Keep in mind, that there are multiple `$profile` scripts.
E.g. one for the console and a separate one for the ISE.

[source,powershell]

Import-Module posh-git Add-PoshGitToProfile -AllHosts

===== From Source

Just download a posh-git release from https://github.com/dahlbyk/posh-git/releases[^], and uncompress it.
Then import the module using the full path to the `posh-git.psd1` file:

[source,powershell]

Import-Module <path-to-uncompress-folder>\src\posh-git.psd1 Add-PoshGitToProfile -AllHosts

This will add the proper line to your `profile.ps1` file, and posh-git will be active the next time you open PowerShell.

For a description of the Git status summary information displayed in the prompt see: https://github.com/dahlbyk/posh-git/blob/master/README.md#git-status-summary-information[^]
For more details on how to customize your posh-git prompt see: https://github.com/dahlbyk/posh-git/blob/master/README.md#customization-variables[^].


=== Summary

You've learned how to harness Git's power from inside the tools that you use during your everyday work, and also how to access Git repositories from your own programs.


[[B-embedding-git-in-your-applications]]
[appendix]
== Embedding Git in your Applications

If your application is for developers, chances are good that it could benefit from integration with source control.
Even non-developer applications, such as document editors, could potentially benefit from version-control features, and Git's model works very well for many different scenarios.

If you need to integrate Git with your application, you have essentially two options: spawn a shell and call the `git` command-line program, or embed a Git library into your application.
Here we'll cover command-line integration and several of the most popular embeddable Git libraries.

=== Command-line Git

One option is to spawn a shell process and use the Git command-line tool to do the work.
This has the benefit of being canonical, and all of Git's features are supported.
This also happens to be fairly easy, as most runtime environments have a relatively simple facility for invoking a process with command-line arguments.
However, this approach does have some downsides.

One is that all the output is in plain text.
This means that you'll have to parse Git's occasionally-changing output format to read progress and result information, which can be inefficient and error-prone.

Another is the lack of error recovery.
If a repository is corrupted somehow, or the user has a malformed configuration value, Git will simply refuse to perform many operations.

Yet another is process management.
Git requires you to maintain a shell environment on a separate process, which can add unwanted complexity.
Trying to coordinate many of these processes (especially when potentially accessing the same repository from several processes) can be quite a challenge.


=== Libgit2

(((libgit2)))((("C")))
Another option at your disposal is to use Libgit2.
Libgit2 is a dependency-free implementation of Git, with a focus on having a nice API for use within other programs.
You can find it at https://libgit2.org[^].

First, let's take a look at what the C API looks like.
Here's a whirlwind tour:

[source,c]

git_repository *repo; int error = git_repository_open(&repo, "/path/to/repository");

git_object head_commit; error = git_revparse_single(&head_commit, repo, "HEAD^{commit}"); git_commit *commit = (git_commit)head_commit;

printf("%s", git_commit_message(commit)); const git_signature *author = git_commit_author(commit); printf("%s <%s>\n", author→name, author→email); const git_oid *tree_id = git_commit_tree_id(commit);

git_commit_free(commit); git_repository_free(repo);

The first couple of lines open a Git repository.
The `git_repository` type represents a handle to a repository with a cache in memory.
This is the simplest method, for when you know the exact path to a repository's working directory or `.git` folder.
There's also the `git_repository_open_ext` which includes options for searching, `git_clone` and friends for making a local clone of a remote repository, and `git_repository_init` for creating an entirely new repository.

The second chunk of code uses rev-parse syntax (see <<_branch_references>> for more on this) to get the commit that HEAD eventually points to.
The type returned is a `git_object` pointer, which represents something that exists in the Git object database for a repository.
`git_object` is actually a "`parent`" type for several different kinds of objects; the memory layout for each of the "`child`" types is the same as for `git_object`, so you can safely cast to the right one.
In this case, `git_object_type(commit)` would return `GIT_OBJ_COMMIT`, so it's safe to cast to a `git_commit` pointer.

The next chunk shows how to access the commit's properties.
The last line here uses a `git_oid` type; this is Libgit2's representation for a SHA-1 hash.

From this sample, a couple of patterns have started to emerge:

* If you declare a pointer and pass a reference to it into a Libgit2 call, that call will probably return an integer error code.
  A `0` value indicates success; anything less is an error.
* If Libgit2 populates a pointer for you, you're responsible for freeing it.
* If Libgit2 returns a `const` pointer from a call, you don't have to free it, but it will become invalid when the object it belongs to is freed.
* Writing C is a bit painful.

(((Ruby)))
That last one means it isn't very probable that you'll be writing C when using Libgit2.
Fortunately, there are a number of language-specific bindings available that make it fairly easy to work with Git repositories from your specific language and environment.
Let's take a look at the above example written using the Ruby bindings for Libgit2, which are named Rugged, and can be found at https://github.com/libgit2/rugged[^].

[source,ruby]

repo = Rugged::Repository.new('path/to/repository') commit = repo.head.target puts commit.message puts "{commit.author[:name]} <{commit.author[:email]}>" tree = commit.tree

As you can see, the code is much less cluttered.
Firstly, Rugged uses exceptions; it can raise things like `ConfigError` or `ObjectError` to signal error conditions.
Secondly, there's no explicit freeing of resources, since Ruby is garbage-collected.
Let's take a look at a slightly more complicated example: crafting a commit from scratch

[source,ruby]

blob_id = repo.write("Blob contents", :blob) # <1>

index = repo.index index.read_tree(repo.head.target.tree) index.add(:path ⇒ 'newfile.txt', :oid ⇒ blob_id) # <2>

sig = { :email ⇒ "bob@example.com", :name ⇒ "Bob User", :time ⇒ Time.now, }

commit_id = Rugged::Commit.create(repo, :tree ⇒ index.write_tree(repo), # <3> :author ⇒ sig, :committer ⇒ sig, # <4> :message ⇒ "Add newfile.txt", # <5> :parents ⇒ repo.empty? ? [] : [ repo.head.target ].compact, # <6> :update_ref ⇒ 'HEAD', # <7> ) commit = repo.lookup(commit_id) # <8>

<1> Create a new blob, which contains the contents of a new file.
<2> Populate the index with the head commit's tree, and add the new file at the path `newfile.txt`.
<3> This creates a new tree in the ODB, and uses it for the new commit.
<4> We use the same signature for both the author and committer fields.
<5> The commit message.
<6> When creating a commit, you have to specify the new commit's parents.
    This uses the tip of HEAD for the single parent.
<7> Rugged (and Libgit2) can optionally update a reference when making a commit.
<8> The return value is the SHA-1 hash of a new commit object, which you can then use to get a `Commit` object.

The Ruby code is nice and clean, but since Libgit2 is doing the heavy lifting, this code will run pretty fast, too.
If you're not a rubyist, we touch on some other bindings in <<_libgit2_bindings>>.

==== Advanced Functionality

Libgit2 has a couple of capabilities that are outside the scope of core Git.
One example is pluggability: Libgit2 allows you to provide custom "`backends`" for several types of operation, so you can store things in a different way than stock Git does.
Libgit2 allows custom backends for configuration, ref storage, and the object database, among other things.

Let's take a look at how this works.
The code below is borrowed from the set of backend examples provided by the Libgit2 team (which can be found at https://github.com/libgit2/libgit2-backends[^]).
Here's how a custom backend for the object database is set up:

[source,c]

git_odb *odb; int error = git_odb_new(&odb); // <1>

git_odb_backend my_backend; error = git_odb_backend_mine(&my_backend, /…*/); // <2>

error = git_odb_add_backend(odb, my_backend, 1); // <3>

git_repository *repo; error = git_repository_open(&repo, "some-path"); error = git_repository_set_odb(repo, odb); // <4>

_Note that errors are captured, but not handled. We hope your code is better than ours._

<1> Initialize an empty object database (ODB) "`frontend,`" which will act as a container for the "`backends`" which are the ones doing the real work.
<2> Initialize a custom ODB backend.
<3> Add the backend to the frontend.
<4> Open a repository, and set it to use our ODB to look up objects.

But what is this `git_odb_backend_mine` thing?
Well, that's the constructor for your own ODB implementation, and you can do whatever you want in there, so long as you fill in the `git_odb_backend` structure properly.
Here's what it _could_ look like:

[source,c]

typedef struct { git_odb_backend parent;

    // Some other stuff
    void *custom_context;
} my_backend_struct;

int git_odb_backend_mine(git_odb_backend *backend_out, /…*/) { my_backend_struct *backend;

backend = calloc(1, sizeof (my_backend_struct));
backend->custom_context = …;
backend->parent.read = &my_backend__read;
backend->parent.read_prefix = &my_backend__read_prefix;
backend->parent.read_header = &my_backend__read_header;
// …
*backend_out = (git_odb_backend *) backend;
    return GIT_SUCCESS;
}
The subtlest constraint here is that ``my_backend_struct```'s first member must be a ``git_odb_backend`` structure; this ensures that the memory layout is what the Libgit2 code expects it to be.
The rest of it is arbitrary; this structure can be as large or small as you need it to be.

The initialization function allocates some memory for the structure, sets up the custom context, and then fills in the members of the `parent` structure that it supports.
Take a look at the `include/git2/sys/odb_backend.h` file in the Libgit2 source for a complete set of call signatures; your particular use case will help determine which of these you'll want to support.

[[_libgit2_bindings]]
==== Other Bindings

Libgit2 has bindings for many languages.
Here we show a small example using a few of the more complete bindings packages as of this writing; libraries exist for many other languages, including C++, Go, Node.js, Erlang, and the JVM, all in various stages of maturity.
The official collection of bindings can be found by browsing the repositories at https://github.com/libgit2[^].
The code we'll write will return the commit message from the commit eventually pointed to by HEAD (sort of like `git log -1`).

===== LibGit2Sharp

(((.NET)))(((C#)))(((Mono)))
If you're writing a .NET or Mono application, LibGit2Sharp (https://github.com/libgit2/libgit2sharp[^]) is what you're looking for.
The bindings are written in C#, and great care has been taken to wrap the raw Libgit2 calls with native-feeling CLR APIs.
Here's what our example program looks like:

[source,csharp]

new Repository(@"C:\path\to\repo").Head.Tip.Message;

For desktop Windows applications, there's even a NuGet package that will help you get started quickly.

===== objective-git

(((Apple)))(((Objective-C)))(((Cocoa)))
If your application is running on an Apple platform, you're likely using Objective-C as your implementation language.
Objective-Git (https://github.com/libgit2/objective-git[^]) is the name of the Libgit2 bindings for that environment.
The example program looks like this:

[source,objc]

GTRepository *repo = [[GTRepository alloc] initWithURL:[NSURL fileURLWithPath: @"/path/to/repo"] error:NULL]; NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message];

Objective-git is fully interoperable with Swift, so don't fear if you've left Objective-C behind.

===== pygit2

(((Python)))
The bindings for Libgit2 in Python are called Pygit2, and can be found at https://www.pygit2.org[^].
Our example program:

[source,python]

pygit2.Repository("/path/to/repo") # open repository .head # get the current branch .peel(pygit2.Commit) # walk down to the commit .message # read the message

==== Further Reading

Of course, a full treatment of Libgit2's capabilities is outside the scope of this book.
If you want more information on Libgit2 itself, there's API documentation at https://libgit2.github.com/libgit2[^], and a set of guides at https://libgit2.github.com/docs[^].
For the other bindings, check the bundled README and tests; there are often small tutorials and pointers to further reading there.


=== JGit

(((jgit)))(((Java)))
If you want to use Git from within a Java program, there is a fully featured Git library called JGit.
JGit is a relatively full-featured implementation of Git written natively in Java, and is widely used in the Java community.
The JGit project is under the Eclipse umbrella, and its home can be found at https://projects.eclipse.org/projects/technology.jgit[^].

==== Getting Set Up

There are a number of ways to connect your project with JGit and start writing code against it.
Probably the easiest is to use Maven – the integration is accomplished by adding the following snippet to the `<dependencies>` tag in your `pom.xml` file:

[source,xml]

<dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> <version>3.5.0.201409260305-r</version> </dependency>

The `version` will most likely have advanced by the time you read this; check https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit[^] for updated repository information.
Once this step is done, Maven will automatically acquire and use the JGit libraries that you'll need.

If you would rather manage the binary dependencies yourself, pre-built JGit binaries are available from https://projects.eclipse.org/projects/technology.jgit/downloads[^].
You can build them into your project by running a command like this:

[source,console]

javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App

==== Plumbing

JGit has two basic levels of API: plumbing and porcelain.
The terminology for these comes from Git itself, and JGit is divided into roughly the same kinds of areas: porcelain APIs are a friendly front-end for common user-level actions (the sorts of things a normal user would use the Git command-line tool for), while the plumbing APIs are for interacting with low-level repository objects directly.

The starting point for most JGit sessions is the `Repository` class, and the first thing you'll want to do is create an instance of it.
For a filesystem-based repository (yes, JGit allows for other storage models), this is accomplished using `FileRepositoryBuilder`:

[source,java]

Repository newlyCreatedRepo = FileRepositoryBuilder.create( new File("/tmp/new_repo/.git")); newlyCreatedRepo.create();

Repository existingRepo = new FileRepositoryBuilder() .setGitDir(new File("my_repo/.git")) .build();

The builder has a fluent API for providing all the things it needs to find a Git repository, whether or not your program knows exactly where it's located.
It can use environment variables (`.readEnvironment()`), start from a place in the working directory and search (`.setWorkTree(…).findGitDir()`), or just open a known `.git` directory as above.

Once you have a `Repository` instance, you can do all sorts of things with it.
Here's a quick sampling:

[source,java]

Ref master = repo.getRef("master");

ObjectId masterTip = master.getObjectId();

ObjectId obj = repo.resolve("HEAD^{tree}");

ObjectLoader loader = repo.open(masterTip); loader.copyTo(System.out);

RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1"); createBranch1.setNewObjectId(masterTip); createBranch1.update();

RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1"); deleteBranch1.setForceUpdate(true); deleteBranch1.delete();

Config cfg = repo.getConfig(); String name = cfg.getString("user", null, "name");

There's quite a bit going on here, so let's go through it one section at a time.

The first line gets a pointer to the `master` reference.
JGit automatically grabs the _actual_ `master` ref, which lives at `refs/heads/master`, and returns an object that lets you fetch information about the reference.
You can get the name (`.getName()`), and either the target object of a direct reference (`.getObjectId()`) or the reference pointed to by a symbolic ref (`.getTarget()`).
Ref objects are also used to represent tag refs and objects, so you can ask if the tag is "`peeled,`" meaning that it points to the final target of a (potentially long) string of tag objects.

The second line gets the target of the `master` reference, which is returned as an ObjectId instance.
ObjectId represents the SHA-1 hash of an object, which might or might not exist in Git's object database.
The third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any object specifier that Git understands, and JGit will return either a valid ObjectId for that object, or `null`.

The next two lines show how to load the raw contents of an object.
In this example, we call `ObjectLoader.copyTo()` to stream the contents of the object directly to stdout, but ObjectLoader also has methods to read the type and size of an object, as well as return it as a byte array.
For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data without pulling it all into memory at once.

The next few lines show what it takes to create a new branch.
We create a RefUpdate instance, configure some parameters, and call `.update()` to trigger the change.
Directly following this is the code to delete that same branch.
Note that `.setForceUpdate(true)` is required for this to work; otherwise the `.delete()` call will return `REJECTED`, and nothing will happen.

The last example shows how to fetch the `user.name` value from the Git configuration files.
This Config instance uses the repository we opened earlier for local configuration, but will automatically detect the global and system configuration files and read values from them as well.

This is only a small sampling of the full plumbing API; there are many more methods and classes available.
Also not shown here is the way JGit handles errors, which is through the use of exceptions.
JGit APIs sometimes throw standard Java exceptions (such as `IOException`), but there are a host of JGit-specific exception types that are provided as well (such as `NoRemoteRepositoryException`, `CorruptObjectException`, and `NoMergeBaseException`).

==== Porcelain

The plumbing APIs are rather complete, but it can be cumbersome to string them together to achieve common goals, like adding a file to the index, or making a new commit.
JGit provides a higher-level set of APIs to help out with this, and the entry point to these APIs is the `Git` class:

[source,java]

Repository repo; Git git = new Git(repo);

The Git class has a nice set of high-level _builder_-style methods that can be used to construct some pretty complex behavior.
Let's take a look at an example -- doing something like `git ls-remote`:

[source,java]

CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd"); Collection<Ref> remoteRefs = git.lsRemote() .setCredentialsProvider(cp) .setRemote("origin") .setTags(true) .setHeads(false) .call(); for (Ref ref : remoteRefs) { System.out.println(ref.getName() + " → " + ref.getObjectId().name()); }

This is a common pattern with the Git class; the methods return a command object that lets you chain method calls to set parameters, which are executed when you call `.call()`.
In this case, we're asking the `origin` remote for tags, but not heads.
Also notice the use of a `CredentialsProvider` object for authentication.

Many other commands are available through the Git class, including but not limited to `add`, `blame`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`.

==== Further Reading

This is only a small sampling of JGit's full capabilities.
If you're interested and want to learn more, here's where to look for information and inspiration:

* The official JGit API documentation can be found at https://help.eclipse.org/latest/topic/org.eclipse.egit.doc/help/JGit/User_Guide/User-Guide.html[^].
  These are standard Javadoc, so your favorite JVM IDE will be able to install them locally, as well.
* The JGit Cookbook at https://github.com/centic9/jgit-cookbook[^] has many examples of how to do specific tasks with JGit.


=== go-git

(((go-git)))(((Go)))
In case you want to integrate Git into a service written in Golang, there also is a pure Go library implementation.
This implementation does not have any native dependencies and thus is not prone to manual memory management errors.
It is also transparent for the standard Golang performance analysis tooling like CPU, Memory profilers, race detector, etc.

go-git is focused on extensibility, compatibility and supports most of the plumbing APIs, which is documented at https://github.com/go-git/go-git/blob/master/COMPATIBILITY.md[^].

Here is a basic example of using Go APIs:

[source, go]

import "github.com/go-git/go-git/v5"

r, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{ URL: "https://github.com/go-git/go-git", Progress: os.Stdout, })

As soon as you have a `Repository` instance, you can access information and perform mutations on it:

[source, go]

ref, err := r.Head()

commit, err := r.CommitObject(ref.Hash())

history, err := commit.History()

for _, c := range history { fmt.Println(c) }

==== Advanced Functionality

go-git has few notable advanced features, one of which is a pluggable storage system, which is similar to Libgit2 backends.
The default implementation is in-memory storage, which is very fast.

[source, go]

r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{ URL: "https://github.com/go-git/go-git", })

Pluggable storage provides many interesting options.
For instance, https://github.com/go-git/go-git/tree/master/_examples/storage[^] allows you to store references, objects, and configuration in an Aerospike database.

Another feature is a flexible filesystem abstraction.
Using https://pkg.go.dev/github.com/go-git/go-billy/v5?tab=doc#Filesystem[^] it is easy to store all the files in different way i.e by packing all of them to a single archive on disk or by keeping them all in-memory.

Another advanced use-case includes a fine-tunable HTTP client, such as the one found at https://github.com/go-git/go-git/blob/master/_examples/custom_http/main.go[^].

[source, go]

customClient := &http.Client{ Transport: &http.Transport{ // accept any certificate (might be useful for testing) TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, Timeout: 15 * time.Second, // 15 second timeout CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse // don’t follow redirect }, }

client.InstallProtocol("https", githttp.NewClient(customClient))

r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{URL: url})

==== Further Reading

A full treatment of go-git's capabilities is outside the scope of this book.
If you want more information on go-git, there's API documentation at https://pkg.go.dev/github.com/go-git/go-git/v5[^], and a set of usage examples at https://github.com/go-git/go-git/tree/master/_examples[^].


=== Dulwich

(((Dulwich)))(((Python)))
There is also a pure-Python Git implementation - Dulwich.
The project is hosted under https://www.dulwich.io/[^].
It aims to provide an interface to Git repositories (both local and remote) that doesn't call out to Git directly but instead uses pure Python.
It has an optional C extensions though, that significantly improve the performance.

Dulwich follows Git design and separate two basic levels of API: plumbing and porcelain.

Here is an example of using the lower level API to access the commit message of the last commit:

[source, python]

from dulwich.repo import Repo r = Repo('.') r.head() # '57fbe010446356833a6ad1600059d80b1e731e15'

c = r[r.head()] c # <Commit 015fc1267258458901a94d228e39f0a378370466>

c.message # 'Add note about encoding.\n'

To print a commit log using high-level porcelain API, one can use:

[source, python]

from dulwich import porcelain porcelain.log('.', max_entries=1)

#commit: 57fbe010446356833a6ad1600059d80b1e731e15 #Author: Jelmer Vernooij <jelmer@jelmer.uk> #Date: Sat Apr 29 2017 23:57:34 +0000

==== Further Reading

The API documentation, tutorial, and many examples of how to do specific tasks with Dulwich are available on the official website https://www.dulwich.io[^].



[[C-git-commands]]
[appendix]
== Git Commands

Throughout the book we have introduced dozens of Git commands and have tried hard to introduce them within something of a narrative, adding more commands to the story slowly.
However, this leaves us with examples of usage of the commands somewhat scattered throughout the whole book.

In this appendix, we'll go through all the Git commands we addressed throughout the book, grouped roughly by what they're used for.
We'll talk about what each command very generally does and then point out where in the book you can find us having used it.

[TIP]
====
You can abbreviate long options.
For example, you can type in `git commit --a`, which acts as if you typed `git commit --amend`.
This only works when the letters after `--` are unique for one option.
Do use the full option when writing scripts.
====

=== Setup and Config

There are two commands that are used quite a lot, from the first invocations of Git to common every day tweaking and referencing, the `config` and `help` commands.

==== git config

Git has a default way of doing hundreds of things.
For a lot of these things, you can tell Git to default to doing them a different way, or set your preferences.
This involves everything from telling Git what your name is to specific terminal color preferences or what editor you use.
There are several files this command will read from and write to so you can set values globally or down to specific repositories.

The `git config` command has been used in nearly every chapter of the book.

In <<_first_time>> we used it to specify our name, email address and editor preference before we even got started using Git.

In <<_git_aliases>> we showed how you could use it to create shorthand commands that expand to long option sequences so you don't have to type them every time.

In <<_rebasing>> we used it to make `--rebase` the default when you run `git pull`.

In <<_credential_caching>> we used it to set up a default store for your HTTP passwords.

In <<_keyword_expansion>> we showed how to set up smudge and clean filters on content coming in and out of Git.

Finally, basically the entirety of <<_git_config>> is dedicated to the command.

[[ch_core_editor]]
==== git config core.editor commands

Accompanying the configuration instructions in <<_editor>>, many editors can be set as follows:

.Exhaustive list of `core.editor` configuration commands
[cols="1,2",options="header"]
|==============================
|Editor | Configuration command
|Atom |`git config --global core.editor "atom --wait"`
|BBEdit (macOS, with command line tools) |`git config --global core.editor "bbedit -w"`
|Emacs |`git config --global core.editor emacs`
|Gedit (Linux) |`git config --global core.editor "gedit --wait --new-window"`
|Gvim (Windows 64-bit) |`git config --global core.editor "'C:\Program Files\Vim\vim72\gvim.exe' --nofork '%*'"` (Also see note below)
|Helix |`git config --global core.editor "hx"`
|Kate (Linux) |`git config --global core.editor "kate --block"`
|nano |`git config --global core.editor "nano -w"`
|Notepad (Windows 64-bit) |`git config core.editor notepad`
|Notepad++ (Windows 64-bit) |`git config --global core.editor "'C:\Program Files\Notepad+\+\notepad++.exe' -multiInst -notabbar -nosession -noPlugin"` (Also see note below)
|Scratch (Linux)|`git config --global core.editor "scratch-text-editor"`
|Sublime Text (macOS) |`git config --global core.editor "/Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl --new-window --wait"`
|Sublime Text (Windows 64-bit) |`git config --global core.editor "'C:\Program Files\Sublime Text 3\sublime_text.exe' -w"` (Also see note below)
|TextEdit (macOS)|`git config --global core.editor "open --wait-apps --new -e"`
|Textmate |`git config --global core.editor "mate -w"`
|Textpad (Windows 64-bit) |`git config --global core.editor "'C:\Program Files\TextPad 5\TextPad.exe' -m"` (Also see note below)
|UltraEdit (Windows 64-bit) | `git config --global core.editor Uedit32`
|Vim |`git config --global core.editor "vim --nofork"`
|Visual Studio Code |`git config --global core.editor "code --wait"`
|VSCodium (Free/Libre Open Source Software Binaries of VSCode) | `git config --global core.editor "codium --wait"`
|WordPad |`git config --global core.editor "'C:\Program Files\Windows NT\Accessories\wordpad.exe'"`
|Xi | `git config --global core.editor "xi --wait"`
|==============================

[NOTE]
====
If you have a 32-bit editor on a Windows 64-bit system, the program will be installed in `C:\Program Files (x86)\` rather than `C:\Program Files\` as in the table above.
====

==== git help

The `git help` command is used to show you all the documentation shipped with Git about any command.
While we're giving a rough overview of most of the more popular ones in this appendix, for a full listing of all of the possible options and flags for every command, you can always run `git help <command>`.

We introduced the `git help` command in <<_git_help>> and showed you how to use it to find more information about the `git shell` in <<_setting_up_server>>.

=== Getting and Creating Projects

There are two ways to get a Git repository.
One is to copy it from an existing repository on the network or elsewhere and the other is to create a new one in an existing directory.

==== git init

To take a directory and turn it into a new Git repository so you can start version controlling it, you can simply run `git init`.

We first introduce this in <<_getting_a_repo>>, where we show creating a brand new repository to start working with.

We talk briefly about how you can change the default branch name from "`master`" in <<_remote_branches>>.

We use this command to create an empty bare repository for a server in <<_bare_repo>>.

Finally, we go through some of the details of what it actually does behind the scenes in <<_plumbing_porcelain>>.

==== git clone

The `git clone` command is actually something of a wrapper around several other commands.
It creates a new directory, goes into it and runs `git init` to make it an empty Git repository, adds a remote (`git remote add`) to the URL that you pass it (by default named `origin`), runs a `git fetch` from that remote repository and then checks out the latest commit into your working directory with `git checkout`.

The `git clone` command is used in dozens of places throughout the book, but we'll just list a few interesting places.

It's basically introduced and explained in <<_git_cloning>>, where we go through a few examples.

In <<_getting_git_on_a_server>> we look at using the `--bare` option to create a copy of a Git repository with no working directory.

In <<_bundling>> we use it to unbundle a bundled Git repository.

Finally, in <<_cloning_submodules>> we learn the `--recurse-submodules` option to make cloning a repository with submodules a little simpler.

Though it's used in many other places through the book, these are the ones that are somewhat unique or where it is used in ways that are a little different.

=== Basic Snapshotting

For the basic workflow of staging content and committing it to your history, there are only a few basic commands.

==== git add

The `git add` command adds content from the working directory into the staging area (or "`index`") for the next commit.
When the `git commit` command is run, by default it only looks at this staging area, so `git add` is used to craft what exactly you would like your next commit snapshot to look like.

This command is an incredibly important command in Git and is mentioned or used dozens of times in this book.
We'll quickly cover some of the unique uses that can be found.

We first introduce and explain `git add` in detail in <<_tracking_files>>.

We mention how to use it to resolve merge conflicts in <<_basic_merge_conflicts>>.

We go over using it to interactively stage only specific parts of a modified file in <<_interactive_staging>>.

Finally, we emulate it at a low level in <<_tree_objects>>, so you can get an idea of what it's doing behind the scenes.

==== git status

The `git status` command will show you the different states of files in your working directory and staging area.
Which files are modified and unstaged and which are staged but not yet committed.
In its normal form, it also will show you some basic hints on how to move files between these stages.

We first cover `status` in <<_checking_status>>, both in its basic and simplified forms.
While we use it throughout the book, pretty much everything you can do with the `git status` command is covered there.

==== git diff

The `git diff` command is used when you want to see differences between any two trees.
This could be the difference between your working environment and your staging area (`git diff` by itself), between your staging area and your last commit (`git diff --staged`), or between two commits (`git diff master branchB`).

We first look at the basic uses of `git diff` in <<_git_diff_staged>>, where we show how to see what changes are staged and which are not yet staged.

We use it to look for possible whitespace issues before committing with the `--check` option in <<_commit_guidelines>>.

We see how to check the differences between branches more effectively with the `git diff A...B` syntax in <<_what_is_introduced>>.

We use it to filter out whitespace differences with `-b` and how to compare different stages of conflicted files with `--theirs`, `--ours` and `--base` in <<_advanced_merging>>.

Finally, we use it to effectively compare submodule changes with `--submodule` in <<_starting_submodules>>.

==== git difftool

The `git difftool` command simply launches an external tool to show you the difference between two trees in case you want to use something other than the built in `git diff` command.

We only briefly mention this in <<_git_diff_staged>>.

==== git commit

The `git commit` command takes all the file contents that have been staged with `git add` and records a new permanent snapshot in the database and then moves the branch pointer on the current branch up to it.

We first cover the basics of committing in <<_committing_changes>>.
There we also demonstrate how to use the `-a` flag to skip the `git add` step in daily workflows and how to use the `-m` flag to pass a commit message in on the command line instead of firing up an editor.

In <<_undoing>> we cover using the `--amend` option to redo the most recent commit.

In <<_git_branches_overview>>, we go into much more detail about what `git commit` does and why it does it like that.

We looked at how to sign commits cryptographically with the `-S` flag in <<_signing_commits>>.

Finally, we take a look at what the `git commit` command does in the background and how it's actually implemented in <<_git_commit_objects>>.

==== git reset

The `git reset` command is primarily used to undo things, as you can possibly tell by the verb.
It moves around the `HEAD` pointer and optionally changes the `index` or staging area and can also optionally change the working directory if you use `--hard`.
This final option makes it possible for this command to lose your work if used incorrectly, so make sure you understand it before using it.

We first effectively cover the simplest use of `git reset` in <<_unstaging>>, where we use it to unstage a file we had run `git add` on.

We then cover it in quite some detail in <<_git_reset>>, which is entirely devoted to explaining this command.

We use `git reset --hard` to abort a merge in <<_abort_merge>>, where we also use `git merge --abort`, which is a bit of a wrapper for the `git reset` command.

==== git rm

The `git rm` command is used to remove files from the staging area and working directory for Git.
It is similar to `git add` in that it stages a removal of a file for the next commit.

We cover the `git rm` command in some detail in <<_removing_files>>, including recursively removing files and only removing files from the staging area but leaving them in the working directory with `--cached`.

The only other differing use of `git rm` in the book is in <<_removing_objects>> where we briefly use and explain the `--ignore-unmatch` when running `git filter-branch`, which simply makes it not error out when the file we are trying to remove doesn't exist.
This can be useful for scripting purposes.

==== git mv

The `git mv` command is a thin convenience command to move a file and then run `git add` on the new file and `git rm` on the old file.

We only briefly mention this command in <<_git_mv>>.

==== git clean

The `git clean` command is used to remove unwanted files from your working directory.
This could include removing temporary build artifacts or merge conflict files.

We cover many of the options and scenarios in which you might used the clean command in <<_git_clean>>.

=== Branching and Merging

There are just a handful of commands that implement most of the branching and merging functionality in Git.

==== git branch

The `git branch` command is actually something of a branch management tool.
It can list the branches you have, create a new branch, delete branches and rename branches.

Most of <<ch03-git-branching>> is dedicated to the `branch` command and it's used throughout the entire chapter.
We first introduce it in <<_create_new_branch>> and we go through most of its other features (listing and deleting) in <<_branch_management>>.

In <<_tracking_branches>> we use the `git branch -u` option to set up a tracking branch.

Finally, we go through some of what it does in the background in <<_git_refs>>.

==== git checkout

The `git checkout` command is used to switch branches and check content out into your working directory.

We first encounter the command in <<_switching_branches>> along with the `git branch` command.

We see how to use it to start tracking branches with the `--track` flag in <<_tracking_branches>>.

We use it to reintroduce file conflicts with `--conflict=diff3` in <<_checking_out_conflicts>>.

We go into closer detail on its relationship with `git reset` in <<_git_reset>>.

Finally, we go into some implementation detail in <<ref_the_ref>>.

==== git merge

The `git merge` tool is used to merge one or more branches into the branch you have checked out.
It will then advance the current branch to the result of the merge.

The `git merge` command was first introduced in <<_basic_branching>>.
Though it is used in various places in the book, there are very few variations of the `merge` command -- generally just `git merge <branch>` with the name of the single branch you want to merge in.

We covered how to do a squashed merge (where Git merges the work but pretends like it's just a new commit without recording the history of the branch you're merging in) at the very end of <<_public_project>>.

We went over a lot about the merge process and command, including the `-Xignore-space-change` command and the `--abort` flag to abort a problem merge in <<_advanced_merging>>.

We learned how to verify signatures before merging if your project is using GPG signing in <<_signing_commits>>.

Finally, we learned about Subtree merging in <<_subtree_merge>>.

==== git mergetool

The `git mergetool` command simply launches an external merge helper in case you have issues with a merge in Git.

We mention it quickly in <<_basic_merge_conflicts>> and go into detail on how to implement your own external merge tool in <<_external_merge_tools>>.

==== git log

The `git log` command is used to show the reachable recorded history of a project from the most recent commit snapshot backwards.
By default it will only show the history of the branch you're currently on, but can be given different or even multiple heads or branches from which to traverse.
It is also often used to show differences between two or more branches at the commit level.

This command is used in nearly every chapter of the book to demonstrate the history of a project.

We introduce the command and cover it in some depth in <<_viewing_history>>.
There we look at the `-p` and `--stat` option to get an idea of what was introduced in each commit and the `--pretty` and `--oneline` options to view the history more concisely, along with some simple date and author filtering options.

In <<_create_new_branch>> we use it with the `--decorate` option to easily visualize where our branch pointers are located and we also use the `--graph` option to see what divergent histories look like.

In <<_private_team>> and <<_commit_ranges>> we cover the `branchA..branchB` syntax to use the `git log` command to see what commits are unique to a branch relative to another branch.
In <<_commit_ranges>> we go through this fairly extensively.

In <<_merge_log>> and <<_triple_dot>> we cover using the `branchA...branchB` format and the `--left-right` syntax to see what is in one branch or the other but not in both.
In <<_merge_log>> we also look at how to use the `--merge` option to help with merge conflict debugging as well as using the `--cc` option to look at merge commit conflicts in your history.

In <<_git_reflog>> we use the `-g` option to view the Git reflog through this tool instead of doing branch traversal.

In <<_searching>> we look at using the `-S` and `-L` options to do fairly sophisticated searches for something that happened historically in the code such as seeing the history of a function.

In <<_signing_commits>> we see how to use `--show-signature` to add a validation string to each commit in the `git log` output based on if it was validly signed or not.

==== git stash

The `git stash` command is used to temporarily store uncommitted work in order to clean out your working directory without having to commit unfinished work on a branch.

This is basically entirely covered in <<_git_stashing>>.

==== git tag

The `git tag` command is used to give a permanent bookmark to a specific point in the code history.
Generally this is used for things like releases.

This command is introduced and covered in detail in <<_git_tagging>> and we use it in practice in <<_tagging_releases>>.

We also cover how to create a GPG signed tag with the `-s` flag and verify one with the `-v` flag in <<_signing>>.

=== Sharing and Updating Projects

There are not very many commands in Git that access the network, nearly all of the commands operate on the local database.
When you are ready to share your work or pull changes from elsewhere, there are a handful of commands that deal with remote repositories.

==== git fetch

The `git fetch` command communicates with a remote repository and fetches down all the information that is in that repository that is not in your current one and stores it in your local database.

We first look at this command in <<_fetching_and_pulling>> and we continue to see examples of its use in <<_remote_branches>>.

We also use it in several of the examples in <<_contributing_project>>.

We use it to fetch a single specific reference that is outside of the default space in <<_pr_refs>> and we see how to fetch from a bundle in <<_bundling>>.

We set up highly custom refspecs in order to make `git fetch` do something a little different than the default in <<_refspec>>.

==== git pull

The `git pull` command is basically a combination of the `git fetch` and `git merge` commands, where Git will fetch from the remote you specify and then immediately try to merge it into the branch you're on.

We introduce it quickly in <<_fetching_and_pulling>> and show how to see what it will merge if you run it in <<_inspecting_remote>>.

We also see how to use it to help with rebasing difficulties in <<_rebase_rebase>>.

We show how to use it with a URL to pull in changes in a one-off fashion in <<_checking_out_remotes>>.

Finally, we very quickly mention that you can use the `--verify-signatures` option to it in order to verify that commits you are pulling have been GPG signed in <<_signing_commits>>.

==== git push

The `git push` command is used to communicate with another repository, calculate what your local database has that the remote one does not, and then pushes the difference into the other repository.
It requires write access to the other repository and so normally is authenticated somehow.

We first look at the `git push` command in <<_pushing_remotes>>.
Here we cover the basics of pushing a branch to a remote repository.
In <<_pushing_branches>> we go a little deeper into pushing specific branches and in <<_tracking_branches>> we see how to set up tracking branches to automatically push to.
In <<_delete_branches>> we use the `--delete` flag to delete a branch on the server with `git push`.

Throughout <<_contributing_project>> we see several examples of using `git push` to share work on branches through multiple remotes.

We see how to use it to share tags that you have made with the `--tags` option in <<_sharing_tags>>.

In <<_publishing_submodules>> we use the `--recurse-submodules` option to check that all of our submodules work has been published before pushing the superproject, which can be really helpful when using submodules.

In <<_other_client_hooks>> we talk briefly about the `pre-push` hook, which is a script we can setup to run before a push completes to verify that it should be allowed to push.

Finally, in <<_pushing_refspecs>> we look at pushing with a full refspec instead of the general shortcuts that are normally used.
This can help you be very specific about what work you wish to share.

==== git remote

The `git remote` command is a management tool for your record of remote repositories.
It allows you to save long URLs as short handles, such as "`origin`" so you don't have to type them out all the time.
You can have several of these and the `git remote` command is used to add, change and delete them.

This command is covered in detail in <<_remote_repos>>, including listing, adding, removing and renaming them.

It is used in nearly every subsequent chapter in the book too, but always in the standard `git remote add <name> <url>` format.

==== git archive

The `git archive` command is used to create an archive file of a specific snapshot of the project.

We use `git archive` to create a tarball of a project for sharing in <<_preparing_release>>.

==== git submodule

The `git submodule` command is used to manage external repositories within a normal repositories.
This could be for libraries or other types of shared resources.
The `submodule` command has several sub-commands (`add`, `update`, `sync`, etc) for managing these resources.

This command is only mentioned and entirely covered in <<_git_submodules>>.

=== Inspection and Comparison

==== git show

The `git show` command can show a Git object in a simple and human readable way.
Normally you would use this to show the information about a tag or a commit.

We first use it to show annotated tag information in <<_annotated_tags>>.

Later we use it quite a bit in <<_revision_selection>> to show the commits that our various revision selections resolve to.

One of the more interesting things we do with `git show` is in <<_manual_remerge>> to extract specific file contents of various stages during a merge conflict.

==== git shortlog

The `git shortlog` command is used to summarize the output of `git log`.
It will take many of the same options that the `git log` command will but instead of listing out all of the commits it will present a summary of the commits grouped by author.

We showed how to use it to create a nice changelog in <<_the_shortlog>>.

==== git describe

The `git describe` command is used to take anything that resolves to a commit and produces a string that is somewhat human-readable and will not change.
It's a way to get a description of a commit that is as unambiguous as a commit SHA-1 but more understandable.

We use `git describe` in <<_build_number>> and <<_preparing_release>> to get a string to name our release file after.

=== Debugging

Git has a couple of commands that are used to help debug an issue in your code.
This ranges from figuring out where something was introduced to figuring out who introduced it.

==== git bisect

The `git bisect` tool is an incredibly helpful debugging tool used to find which specific commit was the first one to introduce a bug or problem by doing an automatic binary search.

It is fully covered in <<_binary_search>> and is only mentioned in that section.

==== git blame

The `git blame` command annotates the lines of any file with which commit was the last one to introduce a change to each line of the file and what person authored that commit.
This is helpful in order to find the person to ask for more information about a specific section of your code.

It is covered in <<_file_annotation>> and is only mentioned in that section.

==== git grep

The `git grep` command can help you find any string or regular expression in any of the files in your source code, even older versions of your project.

It is covered in <<_git_grep>> and is only mentioned in that section.

=== Patching

A few commands in Git are centered around the concept of thinking of commits in terms of the changes they introduce, as though the commit series is a series of patches.
These commands help you manage your branches in this manner.

==== git cherry-pick

The `git cherry-pick` command is used to take the change introduced in a single Git commit and try to re-introduce it as a new commit on the branch you're currently on.
This can be useful to only take one or two commits from a branch individually rather than merging in the branch which takes all the changes.

Cherry picking is described and demonstrated in <<_rebase_cherry_pick>>.

==== git rebase

The `git rebase` command is basically an automated `cherry-pick`.
It determines a series of commits and then cherry-picks them one by one in the same order somewhere else.

Rebasing is covered in detail in <<_rebasing>>, including covering the collaborative issues involved with rebasing branches that are already public.

We use it in practice during an example of splitting your history into two separate repositories in <<_replace>>, using the `--onto` flag as well.

We go through running into a merge conflict during rebasing in <<ref_rerere>>.

We also use it in an interactive scripting mode with the `-i` option in <<_changing_multiple>>.

==== git revert

The `git revert` command is essentially a reverse `git cherry-pick`.
It creates a new commit that applies the exact opposite of the change introduced in the commit you're targeting, essentially undoing or reverting it.

We use this in <<_reverse_commit>> to undo a merge commit.

=== Email

Many Git projects, including Git itself, are entirely maintained over mailing lists.
Git has a number of tools built into it that help make this process easier, from generating patches you can easily email to applying those patches from an email box.

==== git apply

The `git apply` command applies a patch created with the `git diff` or even GNU diff command.
It is similar to what the `patch` command might do with a few small differences.

We demonstrate using it and the circumstances in which you might do so in <<_patches_from_email>>.

==== git am

The `git am` command is used to apply patches from an email inbox, specifically one that is mbox formatted.
This is useful for receiving patches over email and applying them to your project easily.

We covered usage and workflow around `git am` in <<_git_am>> including using the `--resolved`, `-i` and `-3` options.

There are also a number of hooks you can use to help with the workflow around `git am` and they are all covered in <<_email_hooks>>.

We also use it to apply patch formatted GitHub Pull Request changes in <<_email_notifications>>.

==== git format-patch

The `git format-patch` command is used to generate a series of patches in mbox format that you can use to send to a mailing list properly formatted.

We go through an example of contributing to a project using the `git format-patch` tool in <<_project_over_email>>.

==== git imap-send

The `git imap-send` command uploads a mailbox generated with `git format-patch` into an IMAP drafts folder.

We go through an example of contributing to a project by sending patches with the `git imap-send` tool in <<_project_over_email>>.

==== git send-email

The `git send-email` command is used to send patches that are generated with `git format-patch` over email.

We go through an example of contributing to a project by sending patches with the `git send-email` tool in <<_project_over_email>>.

==== git request-pull

The `git request-pull` command is simply used to generate an example message body to email to someone.
If you have a branch on a public server and want to let someone know how to integrate those changes without sending the patches over email, you can run this command and send the output to the person you want to pull the changes in.

We demonstrate how to use `git request-pull` to generate a pull message in <<_public_project>>.

=== External Systems

Git comes with a few commands to integrate with other version control systems.

==== git svn

The `git svn` command is used to communicate with the Subversion version control system as a client.
This means you can use Git to checkout from and commit to a Subversion server.

This command is covered in depth in <<_git_svn>>.

==== git fast-import

For other version control systems or importing from nearly any format, you can use `git fast-import` to quickly map the other format to something Git can easily record.

This command is covered in depth in <<_custom_importer>>.

=== Administration

If you're administering a Git repository or need to fix something in a big way, Git provides a number of administrative commands to help you out.

==== git gc

The `git gc` command runs "`garbage collection`" on your repository, removing unnecessary files in your database and packing up the remaining files into a more efficient format.

This command normally runs in the background for you, though you can manually run it if you wish.
We go over some examples of this in <<_git_gc>>.

==== git fsck

The `git fsck` command is used to check the internal database for problems or inconsistencies.

We only quickly use this once in <<_data_recovery>> to search for dangling objects.

==== git reflog

The `git reflog` command goes through a log of where all the heads of your branches have been as you work to find commits you may have lost through rewriting histories.

We cover this command mainly in <<_git_reflog>>, where we show normal usage to and how to use `git log -g` to view the same information with `git log` output.

We also go through a practical example of recovering such a lost branch in <<_data_recovery>>.

==== git filter-branch

The `git filter-branch` command is used to rewrite loads of commits according to certain patterns, like removing a file everywhere or filtering the entire repository down to a single subdirectory for extracting a project.

In <<_removing_file_every_commit>> we explain the command and explore several different options such as `--commit-filter`, `--subdirectory-filter` and `--tree-filter`.

In <<_git_p4>> we use it to fix up imported external repositories.

=== Plumbing Commands

There were also quite a number of lower level plumbing commands that we encountered in the book.

The first one we encounter is `ls-remote` in <<_pr_refs>> which we use to look at the raw references on the server.

We use `ls-files` in <<_manual_remerge>>, <<ref_rerere>> and <<_the_index>> to take a more raw look at what your staging area looks like.

We also mention `rev-parse` in <<_branch_references>> to take just about any string and turn it into an object SHA-1.

However, most of the low level plumbing commands we cover are in <<ch10-git-internals>>, which is more or less what the chapter is focused on.
We tried to avoid use of them throughout most of the rest of the book.