Конспекти лекцій та Лабораторні роботи з дисципліни "Проєктний практикум" для IV курсу спеціальності 121 "Інженерія програмного забезпечення" ОКР "Фаховий молодший бакалавр" Херсонського політехнічного фахового коледжу Державного університету "Одеська політехніка"
Кожна система управління версіями має свої специфічні особливості в наборі команд, порядок роботи користувачів і адмініструванні. Проте, загальний порядок роботи для більшості VCS абсолютно стереотипний.
Першою дією, яке повинен виконати розробник, є отримання робочої копії проекту або тієї його частини, з якою доведеться працювати за допомогою команди вилучення версії (зазвичай checkout або clone ). Розробник задає версію, яка повинна бути скопійована, за замовчуванням зазвичай копіюється остання (або обрана адміністратором в якості основної) версія.
За командою вилучення встановлюється з’єднання з сервером, і проект у вигляді дерева каталогів і файлів копіюється на комп’ютер розробника. Звичайною практикою є дублювання робочої копії: крім основного каталогу з проектом на локальний диск додатково записується ще одна його копія. Друга локальна копія зберігається в якості еталону, дозволяючи в будь-який момент без звернення до сервера визначити, які зміни внесені в конкретний файл або проект в цілому і від якої версії була «відбрунькувалися» робоча копія.
При деяких варіаціях, що визначаються особливостями системи і деталями прийнятого технологічного процесу, звичайний цикл роботи розробника протягом робочого дня виглядає наступним чином.
У міру внесення змін в основну версію проекту робоча копія на комп’ютері розробника старіє: розбіжність її з основною версією проекту збільшується. Це підвищує ризик виникнення конфліктних змін (див. Нижче ). Тому зручно підтримувати робочу копію в стані, максимально близькому до поточної основної версії, для чого розробник виконує операцію поновлення робочої копії ( update ) наскільки можливо часто (реальна частота оновлень визначається частотою внесення змін, що залежить від активності розробки і числа розробників, а також часом, витрачається на кожне оновлення - якщо воно велике, розробник змушений обмежувати частоту оновлень, щоб не втрачати час).
Розробник модифікує проект, змінюючи вхідні в нього файли в робочій копії відповідно до проектним завданням. Ця робота проводиться локально і не вимагає звернень до сервера VCS.
Завершивши черговий етап роботи над завданням, розробник фіксує ( commit ) свої зміни, передаючи їх на сервер (або в основну гілку, якщо робота над завданням повністю завершена, або в окрему гілку розробки даного завдання). VCS може вимагати від розробника перед фіксацією обов’язково виконати оновлення робочої копії. При наявності в системі підтримки відкладених змін ( shelving ) зміни можуть бути передані на сервер без фіксації. Якщо затверджена політика роботи в VCS це дозволяє, то фіксація змін може проводитися не щодня, а тільки по завершенні роботи над завданням; в цьому випадку до завершення роботи всі пов’язані із завданням зміни зберігаються тільки в локальній робочої копії розробника.
Робити дрібні виправлення в проект можна шляхом безпосередньої правки робочої копії і подальшої фіксації змін прямо в головній гілці (в стовбурі) на сервері. Однак при швидкості обробки великого об’єму робіт такий порядок стає незручним: відсутність фіксації проміжних змін на сервері не дозволяє працювати над чим-небудь в груповому режимі, крім того, підвищується ризик втрати змін при локальних аваріях і втрачається можливість аналізу і повернення до попередніх варіантів коду в межах даної роботи. Тому для таких змін звичайною практикою є створення гілок ( branch), Тобто «отпочковиваніе» від стовбура в якийсь версії нового варіанту проекту або його частини, розробка в якому ведеться паралельно зі змінами в основну версію. Гілка створюється спеціальною командою. Робоча копія гілки може бути створена заново звичайним чином (командою вилучення робочої копії, із зазначенням адреси або ідентифікатора гілки), або шляхом перемикання наявної робочої копії на задану гілку.
Базовий робочий цикл при використанні гілок залишається точно таким же, як і в загальному випадку: розробник періодично оновлює робочу копію (якщо з гілкою працює більше однієї людини) і фіксує в ній свою щоденну роботу. Іноді гілка розробки так і залишається самостійною (коли зміни породжують новий варіант проекту, який далі розвивається окремо від основного), але частіше за все, коли робота, для якої створена гілка, виконана, гілка реінтегрується в стовбур (основну гілку). Це може робитися командою злиття (зазвичай merge ), або шляхом створення патча ( patch ), що містить внесені в ході розробки гілки зміни і застосування цього патча до поточної основної версії проекту.
Три види операцій, які виконуються в системі управління версіями, можуть призводити до необхідності об’єднання змін. це:
У всіх випадках ситуація принципово однакова і має такі характерні риси:
Цілком очевидно, що при невиконанні умови (2) (тобто якщо зміни були внесені тільки в оригінал або тільки в копію) об’єднання елементарно - достатньо скопіювати змінену частину туди, де змін не було. В іншому випадку злиття змін перетворюється в нетривіальну задачу, у багатьох випадках вимагає втручання розробника. В цілому механізм автоматичного злиття змін працює, грунтуючись на наступних принципах:
У всіх випадках базовою версією для злиття є версія, в якій було вироблено поділ продуктів, які зливаються версій. Якщо це операція фіксації змін, то базовою версією буде версія останнього оновлення перед фіксацією, якщо оновлення - то версія попереднього поновлення, якщо злиття гілок - то версія, в якій була створена відповідна гілка. Відповідно, зіставляються наборами змін будуть набори змін, зроблених від базової до поточної версії у всіх поєднуваних варіантах.
Абсолютна більшість сучасних систем управління версіями орієнтоване, в першу чергу, на проекти розробки програмного забезпечення, в яких основним видом вмісту файлу є текст. Відповідно, механізми автоматичного злиття змін орієнтуються на обробку текстових файлів, тобто файлів, що містять текст , що складається з рядків букв і цифр, пробілів і табуляцій, розділених символами переведення рядка .
При визначенні допустимості злиття змін в межах одного і того ж текстового файлу працює типовий механізм порядкового порівняння текстів (прикладом його реалізації є системна утиліта GNU diff), який порівнює об’єднуються версії з базовою та будує список змін, тобто доданих, віддалених і замінених наборів рядків . Мінімальною одиницею даних для цього алгоритму є рядок, навіть найменше відміну робить рядки різними. З урахуванням того, що символи-роздільники, в більшості випадків, не несуть смислового навантаження, механізм злиття може ігнорувати ці символи при порівнянні рядків.
Ті знайдені набори змінених рядків, які не перетинаються між собою, вважаються сумісними і їх злиття робиться автоматично. Якщо у зливних файлах знаходяться зміни, що зачіпають одну і ту ж рядок файлу, це призводить до конфлікту. Такі файли можуть бути об’єднані тільки вручну. Будь-які файли, окрім текстових, з точки зору VCS є бінарними і не допускають автоматичного злиття.
Ситуацію, коли при злитті кількох версій зроблені в них зміни перетинаються між собою, називають конфліктом . При конфлікті змін система управління версіями не може автоматично створити об’єднаний проект і змушена звертатися до розробника. Як вже говорилося вище, конфлікти можуть виникати на етапах фіксації змін, поновлення або злиття гілок. У всіх випадках при виявленні конфлікту відповідна операція припиняється до його дозволу.
Для вирішення конфлікту система, в загальному випадку, пропонує розробнику три варіанти конфліктуючих файлів: базовий, локальний і серверний. Конфліктуючі зміни або показуються розробнику в спеціальному програмному модулі об’єднання змін (в цьому випадку там демонструються зливаються варіанти і динамічно змінюється в залежності від команд користувача об’єднаний варіант файлу), або просто позначаються спеціальною розміткою прямо в тексті об’єднаного файлу (тоді розробник повинен сам сформувати бажаний текст в спірних місцях і зберегти його).
Конфлікти в файлової системі вирішуються простіше: там може конфліктувати тільки видалення файлу з однієї з інших операцій, а порядок файлів в каталозі не має значення, так що розробнику залишається лише вибрати, яку операцію потрібно зберегти в зливається версії.
Механізм блокування дозволяє одному з розробників захопити в монопольне використання файл або групу файлів для внесення в них змін. На той час, поки файл заблокований, він залишається доступним всім іншим розробникам тільки на читання, і будь-яка спроба внести в нього зміни відкидається сервером. Технічно блокування може бути організована по-різному. Типовим для сучасних систем є наступний механізм.
Масове використання блокувань, коли все або більшість файлів в проекті є блокуємими і для будь-яких змін необхідно заблокувати відповідний набір файлів, називається ще стратегією «блокованого вилучення». [3] Ранні системи управління версіями підтримували виключно цю стратегію, запобігаючи таким способом поява конфліктів на корені. В сучасних VCS кращим є використання неблокірующіх витягів, блокування же вважаються швидше неминучим злом, яке потрібно по можливості обмежувати. Недоліки використання блокувань очевидні:
З іншого боку, в деяких випадках використання блокувань цілком виправдано. Очевидним прикладом є організація роботи з бінарними файлами, для яких немає інструментальних засобів злиття змін або таке злиття принципово неможливо (як, наприклад, для файлів зображень). Якщо автоматичне злиття неможливо, то при звичайному порядку роботи будь-паралельне зміна подібних файлів буде призводити до конфлікту. В даному випадку набагато зручніше зробити такий файл блокується, щоб гарантувати, що будь-які зміни до нього будуть вноситися тільки послідовно.
Саме поняття «версії» в різних системах може трактуватися двояко.
Одні системи підтримують версійність файлів. Це означає, що будь-який файл, який з’являється в проекті, отримує власний номер версії. При кожній фіксації розробником змін, які зачіпають файл, відповідна частина фіксуються змін застосовується до файлу і файл отримує новий, зазвичай наступний усе своєю чергою, номер версії.
Для інших систем поняття «версія» відноситься не до окремого файлу, а до сховища цілком. Новостворений порожній репозиторій має версію 1 або 0, будь-яка фіксація змін призводить до збільшення цього номера.
Однак номер версії сховища зазвичай не несе інформації про значущі зміни в проекті, про те, наскільки довго і інтенсивно над ним працювали. Для більш зручної позначки версій проекту (або його частин) системи управління версіями підтримують поняття тегів .
Тег (tag) - це символічна мітка, яка може бути пов’язана з певною версією файлу та / або каталогу в репозиторії. За допомогою відповідної команди всім або частині файлів проекту, що відповідає певним умовам (наприклад, що входять до головний версію головної гілки проекту на певний момент часу) може бути присвоєна задана мітка. Таким чином можна ідентифікувати версію проекту (версія «XX.XXX.XXX» - це набір версій файлів сховища, що мають тег «XX.XXX.XXX»)