Chapters ▾ 2nd Edition

3.1 Git Branching - Takke in 'n Neutedop (Branches in a Nutshell)

Nearly every VCS has some form of branching support. Branching means you diverge from the main line of development and continue to do work without messing with that main line. In many VCS tools, this is a somewhat expensive process, often requiring you to create a new copy of your source code directory, which can take a long time for large projects.

Some people refer to Git’s branching model as its “killer feature,” and it certainly sets Git apart in the VCS community. Why is it so special? The way Git branches is incredibly lightweight, making branching operations nearly instantaneous, and switching back and forth between branches generally just as fast. Unlike many other VCSs, Git encourages workflows that branch and merge often, even multiple times in a day. Understanding and mastering this feature gives you a powerful and unique tool and can entirely change the way that you develop.

Takke in 'n Neutedop (Branches in a Nutshell)

Om werklik te verstaan hoe Git vertakking (branching) hanteer, moet ons 'n tree teruggee en ondersoek hoe Git sy data stoor.

Soos jy dalk onthou uit [what_is_git_section], stoor Git nie data as 'n reeks veranderingstelle (changesets) of verskille (differences) nie, maar eerder as 'n reeks momentopnames (snapshots).

Wanneer jy 'n vaslegging (commit) maak, stoor Git 'n vasleggingsobjek (commit object) wat 'n wyser (pointer) bevat na die momentopname van die inhoud wat jy voorberei (staged) het. Hierdie objek bevat ook die outeur se naam en e-posadres, die boodskap wat jy getik het, en wysers na die vaslegging of vasleggings wat direk voor hierdie vaslegging gekom het (sy ouer of ouers): nul ouers vir die aanvanklike vaslegging, een ouer vir 'n normale vaslegging, en veelvuldige ouers vir 'n vaslegging wat die resultaat is van 'n saamsmelting (merge) van twee of meer takke (branches).

Om dit te visualiseer, kom ons aanvaar jy het 'n gids (directory) wat drie lêers bevat, en jy berei hulle almal voor (stage) en lê dit vas (commit). Die voorbereiding (staging) van die lêers bereken 'n kontrolesom (checksum) vir elkeen (die SHA-1 huts (hash) wat ons in [what_is_git_section] genoem het), stoor daardie weergawe van die lêer in die Git-bewaarplek (repository) (Git verwys na hulle as blobs), en voeg daardie kontrolesom by die voorbereidingsarea (staging area):

$ git add README test.rb LICENSE
$ git commit -m 'Initial commit'

Wanneer jy die vaslegging skep deur git commit uit te voer, bereken Git die kontrolesom vir elke subgids (in hierdie geval, net die wortel-projekgids / root project directory) en stoor hulle as 'n boom-objek (tree object) in die Git-bewaarplek. Git skep dan 'n vasleggingsobjek (commit object) wat die metadata het, sowel as 'n wyser na die wortel-projekboom sodat dit daardie momentopname (snapshot) kan herskep wanneer nodig.

Jou Git-bewaarplek (repository) bevat nou vyf objekte: drie blobs (waarvan elkeen die inhoud van een van die drie lêers verteenwoordig), een boom (tree) wat die inhoud van die gids lys en spesifiseer watter lêername as watter blobs gestoor is, en een vaslegging (commit) met die wyser na daardie wortelboom en al die vasleggings-metadata.

A commit and its tree
Figure 9. 'n Vaslegging (commit) en sy boom (tree)

As jy 'n paar veranderings maak en weer vaslê (commit), stoor die volgende vaslegging 'n wyser na die vaslegging wat direk voor dit gekom het.

Commits and their parents
Figure 10. Vasleggings (commits) en hul ouers

'n Tak (branch) in Git is bloot 'n liggewig, beweegbare wyser na een van hierdie vasleggings (commits). Die verstektaknaam (default branch name) in Git is master. Soos jy begin om vasleggings te maak, word jy 'n master tak gegee wat na die laaste vaslegging wys wat jy gemaak het. Elke keer as jy vaslê (commit), skuif die master tak-wyser outomaties vorentoe.

Note

Die “master” tak in Git is nie 'n spesiale tak nie. Dit is presies soos enige ander tak. Die enigste rede hoekom byna elke bewaarplek (repository) een het, is dat die git init opdrag dit by verstek (by default) skep en die meeste mense nie die moeite doen om dit te verander nie.

A branch and its commit history
Figure 11. 'n Tak en sy vasleggingsgeskiedenis

'n Nuwe tak skep (Creating a New Branch)

Wat gebeur wanneer jy 'n nuwe tak skep? Wel, deur dit te doen, word 'n nuwe wyser (pointer) geskep vir jou om rond te skuif. Kom ons sê jy wil 'n nuwe tak genaamd testing skep. Jy doen dit met die git branch opdrag:

$ git branch testing

Dit skep 'n nuwe wyser na dieselfde vaslegging (commit) waarop jy tans is.

Two branches pointing into the same series of commits
Figure 12. Twee takke wat na dieselfde reeks vasleggings wys

Hoe weet Git op watter tak jy tans is? Dit hou 'n spesiale wyser genaamd HEAD. Let op dat dit baie verskil van die konsep van HEAD in ander VCS’e waaraan jy dalk gewoond is, soos Subversion of CVS. In Git is dit 'n wyser na die plaaslike tak (local branch) waarop jy tans is. In hierdie geval is jy steeds op master. Die git branch opdrag het slegs 'n nuwe tak geskep — dit het nie na daardie tak oorgeskakel (switched) nie.

HEAD pointing to a branch
Figure 13. HEAD wat na 'n tak wys

Jy kan dit maklik sien deur 'n eenvoudige git log opdrag uit te voer wat vir jou wys waarna die tak-wysers (branch pointers) wys. Hierdie opsie word --decorate genoem.

$ git log --oneline --decorate
f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface
34ac2 Fix bug #1328 - stack overflow under certain conditions
98ca9 Initial commit

Jy kan die master en testing takke sien wat net daar langs die f30ab vaslegging (commit) is.

Oorskakel tussen takke (Switching Branches)

Om oor te skakel (switch) na 'n bestaande tak, voer jy die git checkout opdrag uit. Kom ons skakel oor na die nuwe testing tak:

$ git checkout testing

Dit skuif HEAD om na die testing tak te wys.

HEAD points to the current branch
Figure 14. HEAD wys na die huidige tak

Wat is die betekenis daarvan? Wel, kom ons doen nog 'n vaslegging (commit):

$ vim test.rb
$ git commit -a -m 'Make a change'
The HEAD branch moves forward when a commit is made
Figure 15. Die HEAD-tak skuif vorentoe wanneer 'n vaslegging gemaak word

Dit is interessant, want nou het jou testing tak vorentoe geskuif, maar jou master tak wys steeds na die vaslegging (commit) waarop jy was toe jy git checkout uitgevoer het om tussen takke te skakel. Kom ons skakel terug na die master tak:

$ git checkout master
Note
git log wys nie altyd al die takke nie

As jy nou dadelik git log sou uitvoer, mag jy dalk wonder waarheen die "testing" tak wat jy so pas geskep het, verdwyn het, aangesien dit nie in die afvoer sou verskyn nie.

Die tak het nie verdwyn nie; Git weet net nie dat jy in daardie tak belangstel nie en dit probeer vir jou wys waarin dit dink jy belangstel. Met ander woorde, by verstek sal git log slegs die vasleggingsgeskiedenis (commit history) wys wat direk onder die tak lê wat jy uitgecheck (checked out) het.

Om die vasleggingsgeskiedenis vir die verlangde tak te wys, moet jy dit eksplisiet spesifiseer: git log testing. Om al die takke te wys, voeg --all by jou git log opdrag.

HEAD moves when you checkout
Figure 16. HEAD skuif wanneer jy 'n checkout doen

Daardie opdrag het twee dinge gedoen. Dit het die HEAD-wyser teruggestoot om na die master tak te wys, en dit het die lêers in jou werkgids (working directory) teruggerol (reverted) na die momentopname (snapshot) waarna master wys. Dit beteken ook dat die veranderings wat jy van hierdie punt af vorentoe maak, sal afwyk (diverge) van 'n ouer weergawe van die projek. Dit draai in wese die werk wat jy in jou testing tak gedoen het terug, sodat jy in 'n ander rigting kan gaan.

Note
Oorskakeling van takke verander lêers in jou werkgids

Dit is belangrik om daarop te let dat wanneer jy tussen takke in Git skakel (switch), lêers in jou werkgids (working directory) sal verander. As jy na 'n ouer tak oorslaan, sal jou werkgids teruggerol (reverted) word om te lyk soos die laaste keer toe jy op daardie tak vasgelê (committed) het. As Git dit nie skoon kan doen nie, sal dit jou hoegenaamd nie laat oorskakel nie.

Kom ons maak 'n paar veranderings en lê weer vas (commit):

$ vim test.rb
$ git commit -a -m 'Make other changes'

Nou het jou projekgeskiedenis afgewyk (diverged) (sien Afgewykte geskiedenis (Divergent history)). Jy het 'n tak geskep en daarheen oorgeskakel, bietjie werk daarop gedoen, en toe teruggeskakel na jou hooftak (main branch) en ander werk gedoen. Albei daardie veranderings is geïsoleer in aparte takke: jy kan heen en weer skakel tussen die takke en hulle saamsmelt (merge) wanneer jy gereed is. En jy het dit alles gedoen met eenvoudige branch, checkout, en commit opdragte.

Divergent history
Figure 17. Afgewykte geskiedenis (Divergent history)

Jy kan dit ook maklik met die git log opdrag sien. As jy git log --oneline --decorate --graph --all uitvoer, sal dit die geskiedenis van jou vasleggings (commits) uitdruk, en wys waar jou tak-wysers (branch pointers) is en hoe jou geskiedenis afgewyk het.

$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) Make other changes
| * 87ab2 (testing) Make a change
|/
* f30ab Add feature #32 - ability to add new formats to the central interface
* 34ac2 Fix bug #1328 - stack overflow under certain conditions
* 98ca9 Initial commit of my project

Omdat 'n tak in Git eintlik 'n eenvoudige lêer is wat die 40-karakter SHA-1 kontrolesom (checksum) bevat van die vaslegging (commit) waarna dit wys, is takke goedkoop om te skep en te vernietig. Die skep van 'n nuwe tak is so vinnig en eenvoudig as om 41 grepe (bytes) na 'n lêer te skryf (40 karakters en 'n nuwelyn).

Dit staan in skerp kontras met die manier waarop die meeste ouer VCS-nutsmiddels takke skep, wat behels dat al die projek se lêers in 'n tweede gids gekopieer word. Dit kan 'n paar sekondes of selfs minute neem, afhangend van die grootte van die projek, terwyl die proses in Git altyd onmiddellik is. Omdat ons ook die ouers (parents) opneem wanneer ons vaslê (commit), word die vind van 'n behoorlike saamsmeltingsbasis (merge base) outomaties vir ons gedoen en is dit oor die algemeen baie maklik om te doen. Hierdie kenmerke help om ontwikkelaars aan te moedig om gereeld takke te skep en te gebruik.

Kom ons kyk hoekom jy dit behoort te doen.

Note
Skep van 'n nuwe tak en gelyktydige oorskakeling daarnatoe

Dit is tipies om 'n nuwe tak te skep en terselfdertyd na daardie nuwe tak te wil oorskakel — dit kan in een operasie gedoen word met git checkout -b <newbranchname>.

Note

Vanaf Git weergawe 2.23 en verder kan jy git switch in plaas van git checkout gebruik om:

  • Oor te skakel na 'n bestaande tak: git switch testing-branch.

  • 'n Nuwe tak te skep en daarheen oor te skakel: git switch -c new-branch. Die -c vlag staan vir create, jy kan ook die volle vlag gebruik: --create.

  • Terug te keer na jou vorige uitgecheckte (checked out) tak: git switch -.