3.3 Галуження в git – Управління гілками

Тепер, коли ви вже вмієте створювати гілки, зливати їх та видаляти, розгляньмо те, як ними управляти, та на інструменти, які можуть в цьому допомогти.

Команда git branch насправді вміє більше ніж просто створювати та знищувати гілки. Запустіть її без параметрів і ви побачите просто список ваших гілок:

$ git branch iss53 * master testing

Зверніть увагу на символ * перед master : це вказівник на вашу поточно вибрану гілку (тобто ту, на котру вказує HEAD ). Це означає, що якщо ви зараз захочете зробити коміт, master оновиться вашими новими змінами. Щоб побачити ваші останні коміти – запустіть git branch -v :

$ git branch -v iss53 93b412c fix javascript issue * master 7a98805 Merge branch 'iss53' testing 782fd34 add scott to the author list in the readmes

Опції –merged та –no-merged корисні для фільтрування списку гілок залежно від того чи вони були злиті з поточною гілкою. Для списку гілок, що були злиті з поточною гілкою виконайте git branch –merged :

$ git branch --merged iss53 * master

Ви бачите iss53 в цьому списку тому, що раніше її злили з master . Взагалі, гілки без * із цього списку можна вже видаляти (за допомогою git branch -d ), адже ми вже інтегрували ті зміни, тому не втратимо їх.

Команда git branch –no-merged покаже гілки, які ви не зливали з поточною гілкою:

$ git branch --no-merged testing

Тут ви бачите свою іншу гілку. Оскільки дана гілка містить роботу, що не зливалася, спроба видалити її за допомогою git branch -d не буде успішною:

$ git branch -d testing error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'.

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

Описані вище опції –merged і –no-merged , якщо не надати команді хеш коміту чи назву гілки як аргумент, покажуть, що, відповідно, було чи не було залите до поточної гілки.

Завжди можна додати ще один аргумент, щоб дізнатися про стан злиття відносно якоїсь іншої гілки — немає потреби спочатку на неї переходити. Наприклад, що не було залите до гілки master ?

$ git checkout testing $ git branch --no-merged master topicA featureB

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 сховище тепер зберігає п’ять об’єктів: по одному блобу зі змістом на кожен з трьох файлів, одне дерево, що перелічує зміст теки та вказує, які файли зберігаються у яких блобах, та одну фіксацію, що вказує на корінь дерева, та зберігає метадані фіксації.

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

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

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

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

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

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

Звідки Git знає, на якій гілці ви зараз знаходитесь? Він зберігає особливий вказівник під назвою HEAD . Завважте, що це геть інша концепція HEAD , ніж в інших СКВ, з якими ви могли працювати, таких як Subversion чи CVS. У Git це просто вказівник на локальну гілку, на якій ви знаходитесь. В даному випадку, ви досі на гілці master . Команда git 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” прямо поруч з фіксацією f30ab .

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

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

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

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

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

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

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

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

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

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

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

Ви також можете легко це побачити за допомогою команди 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 процес завжди миттєвий. Також, оскільки ми записуємо батьків кожної фіксації, пошук відповідної бази для злиття може бути зроблено автоматично та зазвичай дуже просто. Ці можливості допомагають заохотити розробників створювати та використовувати гілки часто.

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