Git
Chapters ▾ 2nd Edition

3.1 Гранење во Git - Гранење објаснето

Речиси секој VCS има некаква форма на разгранување. Подружницата значи дека се движите од главната линија на развој и продолжувате да работите без да се мешате со таа главна линија. Во многу VCS алатки, ова е малку скап процес, често бара да креирате нова копија од директориумот за изворен код, кој може да потрае долго време за големи проекти.

Некои луѓе се однесуваат на моделот на разгранување на Гит како нејзина "функција на убијци", и тоа сигурно го поставува Git одделно во заедницата на VCS. Зошто е толку посебен? Начинот на кој Git гранките е неверојатно лесен, правејќи разгранување операции речиси моментално, и префрлање напред и назад меѓу гранки обично толку брзо. За разлика од многу други VCS-и, Git ги поттикнува работните процеси кои се разгрануваат и често се спојуваат, дури и повеќе пати во еден ден. Разбирање и мастеринг на оваа функција ви дава моќна и уникатна алатка и целосно може да го промени начинот на кој се развивате.

Гранење објаснето

За да го разбереме начинот на кој Git прави разгранување, треба да направиме чекор назад и да испитаме како Git ги чува своите податоци.

Како што можеби се сеќавате од Почеток, Git не ги зачувува податоците како серија на промени или разлики, туку наместо како серија на снимки.

Кога ќе направите залог, Git зачувува објект за извршување кој содржи покажувач кон моменталната слика на содржината што ја изведе. Овој објект исто така го содржи името на авторот и е-поштата, пораката што ја внесовте и укажува на извршување или извршува кои непосредно дојдоа пред оваа заложба (нејзиниот родител или родители): нула родители за почетната обврска, еден родител за нормално извршување, и повеќекратни родители за посетување што резултира од спојување на две или повеќе гранки.

За да го визуелизираме ова, да претпоставиме дека имате директориум во кој се наоѓаат три датотеки, и ги прикажувате сите и извршите. Поставувањето на датотеките пресметува контролна сума за секој од нив (SHA-1 hash споменавме во Почеток), ја зачувува таа верзија на датотеката во Git складиштето (Git ги нарекува како blobs), и додава таа проверка во областа на стоп:

$ git add README test.rb LICENSE
$ git commit -m 'The initial commit of my project'

Кога ќе ја креирате извршувањето со извршување на git commit, Git ги проверува сите поддиректориуми (во овој случај, само директориумот на root проект) и ги зачувува тие дрво објекти во Git репозиториумот. Git потоа создава објект за извршување кој ги има метаподатоците и покажувачот кон дрвото на коренот на проектот, за да може повторно да го креира тој снимка кога е потребно.

Вашето складиште на Git сега содржи пет објекти: еден blob за содржината на секоја од трите датотеки, едно дрво кое ја наведува содржината на директориумот и одредува кои имиња на датотеки се зачувуваат како што се blobs, и еден изврши со покажувачот кон тоа root и сите метаподатоци на извршување.

A commit and its tree.
Figure 9. A commit and its tree

Ако направите некои промени и повторно извршите, следнава заложба складира покажувач кон извршувањето што се случи веднаш пред него.

Commits and their parents.
Figure 10. Commits and their parents

Гранката во Git е едноставно лесен подвижен покажувач на една од овие обврски. Стандардното име на гранка во Git е master. Откако ќе почнете да правите обврски, добивате "master" гранка што укажува на последната посветеност што сте ја направиле. Секој пат кога ќе извршите, се движи напред автоматски.

Гранката "master" во Git не е специјална гранка. Исто како и секоја друга гранка. Единствената причина што скоро секое складиште има едно е тоа што командата git init ја создава стандардно и повеќето луѓе не се мачат да ја променат.

A branch and its commit history.
Figure 11. A branch and its commit history

Креирање на нова гранки

Што се случува ако креирате нова гранка? Па, тоа создава нов покажувач за да се движите наоколу. Да речеме да креирате нова гранка наречена тестирање. Ова го правите со командата git branch:

$ git branch testing

Ова создава нов покажувач на истата обврска во која сте моментално вклучени.

Two branches pointing into the same series of commits.
Figure 12. Two branches pointing into the same series of commits

Како Git знае што работи во моментов? Го задржува специјалниот покажувач наречен HEAD. Имајте на ум дека ова е многу поинакво од концептот на HEAD во другите VCS со кои може да се навикнете, како што е Subversion или CVS. Во Git, ова е покажувач за локалната филијала во која сте моментално вклучени. Во овој случај, сеуште сте на "господар". Командата git branch само created нова гранка - не се префрли на таа гранка.

HEAD pointing to a branch.
Figure 13. HEAD pointing to a branch

Можете лесно да го видите ова со извршување на едноставна команда git log која ви покажува каде покажувачите на гранка. Оваа опција се нарекува --decorate.

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

Можете да ги видите гранките “master” и 'testing' кои се наоѓаат веднаш до commit f30ab`.

Менување на гранка

За да се префрлите на постоечка гранка, ја извршувате командата git checkout. Ајде да преминеме во новата гранка за testing:

$ git checkout testing

Ова го движи HEAD за да покажува на гранката testing.

HEAD points to the current branch.
Figure 14. HEAD points to the current branch

Кое е значењето на тоа? Па, ајде да направиме друга обврска:

$ vim test.rb
$ git commit -a -m 'made a change'
The HEAD branch moves forward when a commit is made.
Figure 15. The HEAD branch moves forward when a commit is made

Ова е интересно, затоа што сега вашата гранка за тестирање се придвижи напред, но вашата "master" гранка сè уште укажува на обврската на која сте биле вклучени кога извршувате git checkout за да ги префрлите гранките. Ајде да се вратиме назад во master гранката:

$ git checkout master
HEAD moves when you checkout.
Figure 16. HEAD moves when you checkout

Таа команда направи две работи. Го премести назад стрелчето HEAD за да укаже на гранката master, и ги враќаше датотеките во вашиот работен директориум назад кон слика што го покажува` master`. Ова исто така значи дека промените што ќе ги направите од оваа точка напред ќе се разликуваат од постара верзија на проектот. Тоа во суштина ја превртува работата што сте ја направиле во гранката за тестирање, за да можете да одите во друга насока.

  1. Свичувањето на филијалите ги менува датотеките во вашиот работен директориум

Важно е да се напомене дека кога ќе го вклучите гранките во Git, ќе се променат датотеките во вашиот работен директориум. Ако се префрлите на постара гранка, вашиот работен директориум ќе биде вратен за да изгледа како последниот пат кога сте го извршиле во таа гранка. Ако Git не може да го направи тоа чисто, нема да дозволи да се префрлиш на сите.

Ајде да направиме неколку промени и да извршиме повторно:

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

Сега вашата историја на проектот се одвои (видете Divergent history). Вие креиравте и се префрливте на гранка, дали некои работат на тоа, а потоа се вративте на вашата главна гранка и направивте друга работа. И двете од овие промени се изолирани во одделни гранки: може да се префрлите напред и назад помеѓу гранките и да ги споите заедно кога сте подготвени. И направи сето тоа со едноставни branch,` checkout` и commit команди.

Divergent history.
Figure 17. Divergent history

Исто така лесно можете да го видите со командата git log. Ако ја стартувате git log -oneline -decorate -graph -all, ќе ја отпечати историјата на вашите обврски, покажува каде се вашите покажувачи за филијали и како се разликува вашата историја.

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

Бидејќи гранката во Git всушност е едноставна датотека која содржи 40-каратен SHA-1 контролна сума на обврските што ги посочува, гранките се ефтини за создавање и уништување. Создавањето нова гранка е толку брзо и едноставно како пишување 41 бајт во датотека (40 карактери и нова линија).

Ова е во контраст со начинот на кој повеќето постари VCS алатки гранка, која вклучува копирање на сите датотеки на проектот во вториот директориум. Ова може да потрае неколку секунди или дури минути, во зависност од големината на проектот, додека во Git процесот е секогаш моментален. Исто така, бидејќи ние ги снимаме родителите кога ќе извршуваме, наоѓањето на соодветна база за спојување за спојување автоматски се прави за нас и обично е многу лесно да се направи. Овие функции помагаат да се поттикнат програмерите да креираат и користат гранки често.

Ајде да видиме зошто треба да го сторите тоа.