Git
Chapters ▾ 2nd Edition

3.1 Галуження в git - Гілки у кількох словах

Майже кожна система контролю версій підтримує гілки (branches) в певній мірі. Галуження - це відмежування від основної лінії розробки для продовження своєї частини роботи та уникнення конфліктів з основною лінією. В багатьох системах контролю версій цей процес "дорогий", часом вимагає створювати копію коду, що може зайняти багато часу для великих проектів.

Дехто вважає гілки Git вбивчою особливістю, що вирізняє Git від інших систем. Що ж в них такого особливого? Гілки Git надзвичайно легкі, операції галуження майже миттєві, перехід між гілками зазвичай теж. На відміну від інших систем, Git заохочує схеми, де гілки часто створюються та зливаються, навіть кілька разів на день. Розуміння та вміння працювати з цією "фішкою" дає вам потужний та унікальний інструмент, що може кардинально змінити ваш процес розробки.

Гілки у кількох словах

Щоб дійсно зрозуміти як Git працює з гілками, нам треба повернутись назад та розібратись, як Git зберігає дані.

Як ви можете пам’ятати з Вступ, Git зберігає дані не як послідовність змін, а як послідовність знімків.

Коли ви фіксуєте зміни, Git зберігає об’єкт фіксації, що містить вказівник на знімок змісту, який ви додали. Цей об’єкт також містить ім’я та поштову адресу автора, набране вами повідомлення та вказівники на фіксацію або фіксації, що були прямо до цієї фіксації (батько чи батьки): нуль для першої фіксації, одна фіксація для нормальної фіксації, та декілька фіксацій для фіксацій, що вони є результатом злиття двох чи більше гілок.

Щоб це уявити, припустимо, що у вас є тека з трьома файлами, які ви додали та зафіксували. Додання файлів обчислює контрольну суму для кожного (SHA-1 хеш про котрий ми згадували в Вступ), зберігає версію файлу в сховищі Git (Git називає їх блобами), та додає їх контрольні суми до області додавання:

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

Коли ви створили фіксацію за допомогою git commit, Git обчислив контрольну суму кожної теки (у цьому випадку, тільки кореневої теки) та зберігає ці об’єкти дерева в сховищі Git. Потім Git створює об’єкт фіксації, що зберігає метадані та вказівник на корінь дерева проекту, щоб він міг відтворити цей знімок, коли потрібно.

Ваше Git сховище тепер зберігає п’ять об’єктів: по одному блобу зі змістом на кожен з трьох файлів, одне дерево, що перелічує зміст теки та вказує, які файли зберігаються у яких блобах, та одну фіксацію, що вказує на корінь дерева, та зберігає метадані фіксації.

Фіксація та її дерево.
Figure 9. Фіксація як дерево

Якщо ви зробите якісь зміни та зафіксуєте знову, наступна фіксація буде зберігати вказівник на попередню.

Фіксації та їх батьки.
Figure 10. Фіксації та їх батьки

Гілка в Git це просто легкий вказівник, що може пересуватись, на одну з цих фіксацій. Загальноприйнятим ім’ям першої гілки в Git є master. Коли ви почнете робити фіксації, вам надається гілка master, що вказує на останню зроблену фіксацію. Щоразу ви фіксуєте, вона переміщується вперед автоматично.

Note

Гілка “master” у Git не має нічого особливого. Вона нічим не відрізняється від інших. Єдина причина, чому майже кожне сховище має таку гілку — команда git init автоматично її створює, і більшість людей не мають клопоту змінити її.

Гілка та її історія фіксацій.
Figure 11. Гілка та її історія фіксацій

Створення нової гілки

Що відбувається, якщо ви створюєте нову гілку? Ну, це створює новий вказівник, щоб ви могли пересуватися. Припустімо, ви створюєте нову гілку під назвою testing. Ви це робите за допомогою команди git branch:

$ git branch testing

Це створює новий вказівник на фіксацію, в якій ви зараз знаходитесь.

Дві гілки вказують на одну послідовність фіксацій.
Figure 12. Дві гілки вказують на одну послідовність фіксацій

Звідки Git знає, на якій гілці ви зараз знаходитесь? Він зберігає особливий вказівник під назвою HEAD. Завважте, що це геть інша концепція HEAD, ніж в інших СКВ, з якими ви могли працювати, таких як Subversion чи CVS. У Git це просто вказівник на локальну гілку, на якій ви знаходитесь. В даному випадку, ви досі на гілці master. Команда git branch тільки створює нову гілку — вона не переключає на цю гілку.

HEAD вказує на гілку.
Figure 13. HEAD вказує на гілку

Ви легко можете це побачити за допомогою простої опції команди 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” прямо поруч з фіксацією f30ab.

Переключення гілок

Щоб переключитися на існуючу гілку, треба виконати команду git checkout. Переключімося на нову гілку testing:

$ git checkout testing

Це пересуває HEAD, щоб він вказував на гілку testing.

HEAD вказує на поточну гілку.
Figure 14. HEAD вказує на поточну гілку

Чому це важливо? Ну, давайте зробимо ще одну фіксацію:

$ vim test.rb
$ git commit -a -m 'Зробив зміни'
Гілка HEAD пересувається уперед при фіксації.
Figure 15. Гілка HEAD пересувається уперед при фіксації

Це цікаво, бо тепер ваша гілка testing пересунулась уперед, а ваша гілка master досі вказує на фіксацію, що й у момент виконання git checkout для переключення гілок. Переключімося назад до гілки master:

$ git checkout master
HEAD пересувається
Figure 16. HEAD пересувається, коли ви отримуєте (checkout)

Ця команда зробила дві речі. Вона пересунула вказівник HEAD назад на гілку master, та повернула файли у вашій робочій теці до стану знімку, на який вказує master. Це також означає, що якщо ви зараз зробите нові зміни, вони будуть походити від ранішої версії проекту. Вона, суттєво, перемотує працю, що ви зробили у гілці testing, щоб ви могли працювати в іншому напрямку.

Note
Переключення між гілками змінює файли у вашій робочій теці

Важливо зауважити, що коли ви переключаєте гілки в Git, файли у вашій робочій теці змінюються. Якщо ви переключаєтесь до старшої гілки, ваша робоча тека буде повернута до того стаку, який був на момент останнього фіксування у тій гілці. Якщо Git не може зробити це без проблем, він не дасть вам переключитися взагалі.

Зробимо декілька змін та знову зафіксуємо:

$ vim test.rb
$ git commit -a -m 'Зробив інші зміни'

Тепер історія вашого проекту розбіглася (diverged) (дивіться Історія, що розбіглася). Ви створили гілку, дещо в ній зробили, переключились на головну гілку та зробили там щось інше. Обидві зміни ізольовані в окремих гілках. Ви можете переключатись між цими гілками та злити їх, коли вони будуть готові. І все це ви зробили за допомогою простих команд branch, checkout та commit.

Історія
Figure 17. Історія, що розбіглася

Ви також можете легко це побачити за допомогою команди git log. Якщо ви виконаєте git log --oneline --decorate --graph --all, вона надрукує історію ваших фіксацій, покаже куди вказують ваші гілки та як розбіглася ваша історія.

$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) Зробив інші зміни
| * 87ab2 (testing) Зробив зміни
|/
* 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 — це насправді простий файл, що містить 50 символів контрольної суми SHA-1 коміту, на який вказує, гілки дешево створювати та знищувати. Створити гілку так же швидко, як записати 41 байт до файлу (40 символів та символ нового рядка).

Це вражаюча відмінність від того, як більшість інших СВК працюють з гілками — зазвичай це потребує копіювання усіх файлів проекту в другу теку. Це може зайняти декілька секунда, або навіть хвилин, в залежності від розміру проекту, у той час як у Git процес завжди миттєвий. Також, оскільки ми записуємо батьків кожної фіксації, пошук відповідної бази для злиття може бути зроблено автоматично та зазвичай дуже просто. Ці можливості допомагають заохотити розробників створювати та використовувати гілки часто.

Подивимось, чому і вам варто так робити.