Неодноразово отримував запити від початківців про статтю, де буде наведено основи роботи з репозиторієм коду. Нарешті дійшли руки і ось ЛікБез по репозиторію Git готовий!

Storage
@spradlinrelocation.com

В даній статті розберемо:

  • що таке репозиторій коду і для чого його придумали
  • необхідний мінімум термінів при роботі з репозиторієм коду
  • основи використання репозиторію коду Git

Отже,

Що таке репозиторій коду і для чого він потрібен?

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

Що ви для цього робили б, якщо не було репозиторію коду?

Заархівували якимось чином увесь ваш код (файлики та папки), закинули на віддалений продакшин сервер (через ssh або ftp), розпакували і поклали у потрібне місце, щоб новий код вступив у дію.

Тепер уявіть, що випадково ви поредагували код на продакшині, щось поламали і тепер треба це пофіксити.

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

Ще уявіть, що ви зробили зміни до вашого коду, але потім передумали і захотіли все повернути. Без репозиторія коду, у кращому випадку, вам прийшлось би використовувати функцію вашого редактора (якщо зміни не розтягнуті у кілька днів чи тижнів) Відкотити Зміни. У гіршому – ще раз переписувати код.

А тепер уявіть ще один сценарій. Над вашою бібліотекою окрім вас працює ще 10 ваших друзів. Одночасно. Кожен працює над власним модулем (файликом) чи пакетом (цілою папочкою коду), а дехто працює над різними частинами коду в межах одного файлика. Що робити, коли усі закінчили власну частину коду?

Хтось один сідає, збирає архів бібліотеки від 10-ти розробників та об’єднує усі архіви в один. При цьому намагаючись порівняти чи часом не були змінені однакові рядочки коду різними розробниками.

І на засипку. Цей нещасний, хто збирав усі архіви докупи, побачив, що бібліотека чомусь не працює, навіть не запускається. Розпитує кожного із розробників про потенційну причину. А кожен відповідає, що у нього працювало і що це мабуть проблема у неправильному об’єднанні усіх архівів коду.

Ух… Аж страшно стало! 🙂

Щоб уникнути подібних сценаріїв придумали репозиторії коду. Репозиторій коду – це програмний інструмент, основне завдання якого – зберігання коду та історії змін до даного коду. Також його ще називають Системою Контролю Версій (VCS). Маються на увазі версії коду.

Що репозиторій нам дає? З вище наведених жахливих сценаріїв можемо здогадатися, що репозиторій полегшує життя розробника у кожному із них. А саме, репозиторій коду дозволяє:

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

Одним словом, в сучасному IT світі без репозиторія нікуди. В більшості випадків хоча б одним із рипозиторіїв повинні володіти не лише програмісти, але й і верстальщики, QA-ї і інші спеціалісти, які працюють у вашій команді та мають доступ до коду, тестів та документації проекту.

Тому, тепер давайте до діла. Які бувають типи репозиторіїв:

Види Репозиторіїв Коду

Є два типи репозиторіїв.

1. Централізовані Репозиторії Коду (Version Control System, VCS)

Старіші та простіші, які зараз практично не використовуються у нових проектах. Приклад: SVN, CSV.

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

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

2. Розподілені Репозиторії Коду (Distributed Version Control System, DVCS)

На щастя з часом придумали так звані Розподілені (англ. Distributed) репозиторії коду, які дозволяють нам, окрім центральльного репозиторія, також мати кожному розробнику власний локальний репозиторій, і взагалі скільки завгодно копій/клонів репозиторію і працювати з кожним із них автономно. Деколи навіть важко розібратися, а який з них центральний 😉

Таким чином для регулярних комітів вам не потрібен постійний доступ до інтернету. Ви можете робити записи у локальний репозиторій, а вже коли з’явиться інтернет – закинути усі зміни на віддалені необхідні репозиторії.

Найбільш поширеними розподіленими репозиторіями коду вважаються Git та Mercurial. Якщо використовуєте Git, тоді також можете користуватися онлайн сервісом для своїх публічних чи приватних репозиторіїв github.com. Якщо ж Mercurial, тоді його підтримку знайдете у сервісі bitbucket.com.

На мою думку github.com на порядок популярніший. На даний час у своїй роботі використовую лише Git репозиторій (приватні сервери для клієнтських проектів) та  github.com для OpenSource проектів.

На даному малюнку відображена різниця між централізованим та розподіленим репозиторієм коду SVN та Git:

Git vs SVN

Різниця між Централізованим (SVN) та Розподіленим (Git) репозиторіями

Концепція та Термінологія Git

Ось як виглядають усі етапи вашого коду від вашої папочки локальної і аж до кінцевого місця зберігання коду, яким користуються усі розробники у вашій команді:

Git Workflow

Чотири Етапи Вашого Коду: Workspace, Staging (Index), Local, and Remote Репозиторії

Якщо зовсім коротко, то:

Ви працюєте у своїй Робочій Папці (workspace), потім закидаєте ваші зміни у так званий Перевалочний Пункт (index або staging), звідки кладете код у ваш Локальний Репозиторій (local repository), і вже при потребі, у Віддалені Репозиторії (remote repository), щоб інші також мали доступ до ваших змін.

Тобто локальний репозиторій складаєтьс із трьох так званих дерев (tree):

  1. робоча папочка (working space) – там ви працюєте,
  2. індекс (staging, index) – перевалочний пункт між робочою папкою та локальним репозиторієм,
  3. head – вказівник на ваш останній коміт в локальному репозиторії.

Тепер давайте розберемося детальніше в термінах:

Робоча Папка (Working Directory) – це ваша локальна папка у файловій системі, яка відображає певний стан коду в репозиторії + ваші локальні зміни (якщо такі є). Ви весь час працюєте над кодом будучи всередині вашої робочої папки.

Коміт (commit) – запис змін коду у репозиторій.

Мердж (merge) – об’єднання змін з однієї гілки коду в іншу.

Гілка (branch) – версія коду, яку створють всередині того ж репозиторію, і ведуть розробку зазвичай до моменту поки не зроблять мердж (об’єднання) змін даної версії коду із основною гілкою (зазвичай master).  Гілки використовують для роботи над окремими завданнями одночасно, не заважаючи один одному. Дефолтна гілка у будь-якому git репозиторії – це master.

Пул (pull) – отримання останніх змін з віддаленого репозиторію у ваш власний локальний репозиторій.

Push (push) – закинути зміни локального репозиторію у віддалений репозиторій.

Ремоут (remote) – один із віддалених репозиторіїв. Один код може мати багато клонів та копій на вашому та зовнішніх серверах. Кожна така копія, окрім вашої локальної, називається ремоутом (віддаленим репозиторієм).

Індекс (Stage або Index) – підготовче місце ваших файлів з робочої папки перед тим як закинути зміни робочої папки у локальний репозиторій. Зазвичай коміт включає у себе лише ті зміни, що є в індексі. Давайте для простоти називати дане місце Перевалочним Пунктом, кращого терміну поки не придумав.

Локальний репозиторій – ваша власна копія репозиторію, у яку безпосередньо йдуть коміти з вашої робочої папочки (насправді все йде через Перевалочний Пункт – Stage (Index)). Для роботи з даним репозиторієм вам не потрібно інтернету.

Git HEAD – вказівник на коміт в репозиторії, на якому зараз перебуває ваш локальний репозиторій і гілка у цьому репозиторії. Вказівник по дефолтну вказує на останній коміт, але його можна вручну “переміщати” між комітами, гілками і навіть тегами (у цьому випадку його називають Detached Head – від’єднаний вказівник).

Тег (tag) – фіксація стану коду для подальшого використання його при релізах. Фіксуємо зазвичай код під тегом з певною назвою, як от: 1.0, 2.0.1, 3.0alpha. Нові зміни у теги не записуються! Тому вони ще носять назву Фіксовані Гілки.

Встановлюємо Git на свій комп’ютер

Взалежності від того, яку операційну систему ви використовуєте обираєте один із наступних варіантів завантаження Git системи:

Кожна із вище наведених інсталяцій включає у себе графічний інтерфейc. Тому, якщо ви більше любите користуватись мишкою, ніж “колупатись” в командній стрічці, можете попрактикуватись з графічними клієнтами.

Далі ж ми розберемо основні команди та користування репозиторієм Git на прикладі командної стрічки.

Основні команди Git

Конфігуруємо Git

Мінімальна конфігурація Git репозиторію включає налаштування власного імені (воно згадуватиметься в кожному вашому коміті, так само як і ваш емейл):

та власної емейл адреси:

Зауважте використання опції “-global”. Вона встановлює ваші дані глобально для усіх репозиторіїв на вашому комп’ютері. Якщо для певного репозиторію вам потрібно інші ваші дані встановити, тоді заходите у папочку репозиторію, забираєте опцію global і ваші дані будуть встановлені локально лише для поточного репозиторію.

Також варта одразу встановити список файлів, які git повинен ігнорувати. Зазвичай усі генеровані файли не повинні попадати в репозиторій. Для цього я створюю файл .gitignore_global будь-де у себе на комп’ютері. Ось приклад мого:

Даний файл заставить git ігнорувати файлики, що закінчуються на .pyc, ~, .egg-info і т.д. Більшість має безпосереднє відношення до розробки на мові Python. Під ваше конкретне розробницьке середовище вам може знадобитись кілька додаткових типів файлів включити у даний файл.

І даємо вказівку git-у записати даний список шаблонів у ігнор:

Опцій для конфігурації репозиторію багато, але необхідний мінімум ми оглянули.

Клонуємо існуючий репозиторій

Найпростіший випадок. Десь уже існує репозиторій з кодом, і вам треба його собі скопіювати для подальшої роботи:

Знаючи посилання на репозиторій коду можемо скористуватися командою clone, щоб отримати локальний репозиторій (клон) і робочу папочку + перевалочний пункт. Все необхідне для початку роботи з кодом.

В результаті вище описаної команди у вас локально з’явиться папка wxpython_calculator з кодом всередині. А також службова папка під назвою ‘.git’. Не рекомендую туди заходити і щось змінювати без додаткових знань, які в даній статті не описані.

Створюємо новий репозиторій

Створюємо локально папочку, заходимо всередину та ініціалізуємо її як git репозиторій:

Ось і все, папочка тепер не проста, а Золота Локальний Репозиторій 😉

Закидуємо локальні зміни у Локальний Репозиторій

Продовжуємо роботу з нашою щойно створеною та ініціалізованою папочкою.

Створюємо всередині необхідні файли (модулі) з кодом, підпапки при необхідності і додаємо їх усіх у Індекс – перевалочний пункт перед комітом (записом у локальний репозиторій):

Команда git add додасть рекурсивно усі файли та підпапки даної папки.

Зауважте, у лінуксових командних стрічках команда git add може поскаржитись, що деякі файлики містять не лінуксовий, а DOS закінчення файлів. У такому випадку скористайтесь утилітами як от dos2unix для переформатування проблемних файлів, і повторно спробуйте команду git add аж допоки усі необхідні файли не опиняться у нашому Перевалочному Пункті.

Також рекомендую завжди перед тим, як закидувати файли в Перевалочний Пункт перевіряти, що саме ви закидуєте. Команда status:

Ця команда показує на якій гілці коду ви знаходитесь. У даному випадку це дефолтна гілка – master. А також список змінених, нових та видалених файлів. Також дана команда дає підказки, що і з кожним із даних файлів можна робити далі.

У даному випадку команда показує, що новий файл з’явився test.txt, а також був змінений calculator.py.

Закидуємо зміни з Індекса (staging) у Локальний Репозиторій. Це якраз і називається Зробити Коміт:

У вище наведеному прикладі ми додали усі змінені та нові файли до індексу. А потім закомітили стан індексу в локальний репозиторій командою commit.

Щоб зменшити кількість команд для коміту і пропустити Перевалочний Пункт та одразу закинути ваші локальні зміни у Локальний репозиторій, можна скористатись опцією ‘-a’ команди commit, яка позбирає усі змінені файли та включить їх у коміт:

Зауважте, що нові файли чи видалені не будуть враховуватись опцією ‘-a’. Для нових файлів потрібно їх додавати окремою командою:

І ще, якщо був видалений файл, то ці зміни також треба занести в Індекс окремою командою, інакше Локальний Репозиторій проігнорує видалення вашого файлу у вашій робочій папці:

І на закінчення даної секції. Якщо ви в робочій папочці зробили випадкові зміни у файл, або просто хочете відкотити локальні зміни до стану такого як в репозиторії. Або якщо потрібно відновити випадково видалений файл у робочій папці, тоді користуйтесь наступною командою:

Ця команда відновить стан даного файлу у такий самий, яким він є у Локальному Репозиторії. Її також можна застосовувати до цілої папки одразу.

Закидуємо зміни Локального Репозиторію у Віддалені

Зміни наші пішли щойно у Локальний репозиторій. Але тепер, щоб інші могли користуватись нашими оновленнями, нам треба їх закинути у один із існуючих зовнішніх репозиторіїв (ремоутів).

Дефолтний віддалений репозиторій називається origin. Якщо ви початково клонували існуючий репозиторій, тоді origin у вас уже налаштований разом з гілкою коду, звідки ви клонували. У такому випадку наступної команди буде достатньо, щоб синхронізувати ваш Локальний Репозиторій з Віддаленим:

Ця команда закидає усі коміти Локального Репозорію поточної гілки у Віддалений репозиторій під назвою origin в гілку master (дефолтна гілка).

Зазвичай при клонуванні репозиторію ремоут + гілка уже запам’ятовуються для вас, тому достатньо наступної команди:

Якщо ж ми хочемо закинути на зовні наш новостворений Локальний репозиторій, тоді треба спочатку додати дефолтний ремоунт і вказати його адресу:

Ми сказали нашому репозиторію локальному, що під адресою http://your-git-server.com/some_repository_name знаходиться наш віддалений репозиторій під назвою origin.

Тепер можемо тією ж командою закинути зміни у даний репозиторій у дефолтну гілку master:

Ок. Маємо 2 репозиторії у синхронізованому стані: локальний та origin.

Оновлюємо локальний репозиторій та робочу папку

Уявимо, що наш товариш зробив зміни у код та закинув із власного локального репозиторію у віддалений. І тепер ми хочемо отримати його зміни у свій локальний репозиторій, ну і потім відповідно у робочу папочку, щоб працювати над актуальною версією коду.

Для цього можна скористатися однією командою:

Ця команда складається із двох етапів:

  • синхронізує віддалений репозиторій із вашим локальним ($ git fetch)
  • мерджить (об’єднує) нові зміни, що прийшли щойно в локальний репозиторій, із вашою робочою папочкою ($ git merge)

Ці два етапи можна виконувати самому, окремо у вигляді вище наведених в дужках командах.

При мерджі можуть виникнути конфлікти, у цьому випадку приходиться їх вручну розбирати та додавати виправлені файли в Перевалочний Пункт, а потім як новий коміт. Про це далі.

Робота з Гілками

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

Ось як наглядно можна продемонструвати ідею гілок в репозиторії:

Git Branches

Розгалужуємо з певного моменту код, працюємо в ньому ізольовано, а тоді об’єднуємо назад у головну гілку, де всі можуть бачити і використовувати ваші зміни.

 

З певного моменту (коміту) ми відгалужуємо власну версію коду (гілку), працюємо над нею (робимо коміти та пуші), а коли закінчено – об’єднуємо назад у головну гілку. Таким чином один одному не заважаючи.

Створюємо нову гілку:

Переключаємось у існуючу гілку:

Тобто опція ‘-b’ створює нову гілку, якщо її ще не має.

Але на даний момент гілка, якщо говорити про новостворену, існує лише у вашому локальному репозиторії. Щоб загнати її у віддалений треба застосувати наступну команду:

Відповідно отримати нові зміни з віддаленого репозиторію у власний та оновити робочу папочку:

Щоб видалити гілку з локального репозиторію:

Щоб видалити гілку з віддаленого репозиторію:

Щоб отримати список усіх гілок Локального та Віддалених репозиторіїв:

Як бачите, гілки у віддалених репозиторіях позначені як remotes/origin/. Зірочкою промаркована поточна використовувана гілка у вашій робочій папці.

Коли закінчили роботу на кодом у вашій гілці і пора об’єднувати готовий кусок роботи з основним поточним кодом проекту (зазвичай гілкою master), тоді використовуємо команду:

Тобто при мерджі в поточну гілку вказуємо з якої гілки хочемо взяти код. У даному випадку з new_branch.

Якщо при об’єднанні виникли конфлікти, тоді вручну правите файли до потрібного вигляду, маркуєте їх як виправлені:

Робите окремий коміт:

І тепер синхронізуєте зміни локального репозиторію у віддалений:

Якщо при об’єднанні гілок конфліктів не виникає, тоді коміту додаткового не потрібно, а лише одразу git push.

Робота з Тегами

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

Щоб переглянути список існуючих тегів:

Щоб створити новий тег (анотований, є й інші види, але їх тут ми не розглядаємо):

Даною командою створюємо новий тег, називаючи його 1.0.0 та додаючи супроводжуючий коментар ‘release 1.0.1’ – коментар також обов’язковий аргумент.

Щоб видалити існуючий тег з Локального репозиторію:

Щоб закинути усі теги і синхронізувати їз з Локального на Віддалений репозиторій:

Тобто команда git tag створює тег лише в локальному репозиторії, а вже push знову нам допомагає, щоб закинути теги у необхідний список зовнішніх репозиторіїв.

Додаткові корисні команди та підказки

Щоб глянути на історію комітів розробників у репозиторії, можна скористатись наступною командою, яка надасть розширений запис усіх змін:

Додаткові Матеріали

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

Надіюсь після ознайомлення з даною статею ви зрозуміли, що без репозиторію нікуди (якщо ще ним не користуєтесь), а також отримали базове розуміння що таке репозиторій, для чого він, та розібрались із основними командами та принципом його роботи.

Якщо знайшли неточності, маєте доповнення та побажання – прошу дописувати в коментарях.

А ви уже використовуєте репозиторій коду активно у власній роботі? Якщо так, тоді який саме?

P. S. Як завжди, приймаються теми для наступних постів. Пишіть, що вам було б цікаво почитати на програмістську тематику – будемо розбирати.