Mercurial архитектура

Криейтив комънс. Преводът е направен под лиценз Creative Commons. Българската версия на лиценза можете да намерите тук.

Mercurial е модерна разпределена система за контрол на версиите (VCS), написана главно на Python и частично на C (където производителността е критична). В тази глава ще говоря за някои от решенията, взети при писането на алгоритмите и структурите от данни на Mercurial. Първо, позволете ми да опиша накратко историята на системите за контрол на версиите, така че средата, в която е роден Mercurial, да е ясна.

12.1. Кратка история на контрола на версиите

Въпреки че този текст се фокусира основно върху архитектурата на Mercurial, много от концепциите, които описва, са подобни на други системи за контрол на версиите. За ползотворно въведение в Mercurial, бих искал да опиша някои от тези концепции, използвани в други системи. За да дам обща перспектива, ще дам и кратка история на тези програми.

Системите за контрол на версиите са измислени, за да помогнат на разработчиците да си сътрудничат по проекти, без да се налага ръчно да проследяват промените във файловете и да прехвърлят пълни копия на проекта. В този текст няма да говоря за изходния код на проекта, а като цяло за произволно файлово дърво. Една от основните функции на програмите за контрол на версиите е да разпространяват промени в такова дърво. Типичният работен цикъл изглежда така:

  1. Получаване на най-новата версия на файловата структура от някого.
  2. Работи върху тази версия на структурата, създавайки набор от модифицирани файлове.
  3. Публикуване на тези промени, така че другите да могат да ги използват.

12.1.1. Централизиран контрол на версиите

Първата система за контрол на версиите беше Source Code Control System, SCCS,се появява през 1975 г. Основно вършеше работата по запазване на промените между кодовите файлове в отделни файлове, което беше по-ефективно от простото запазване на копия, но не помогна с изпращането на тези промени към останалата част от работния процес.

Тя беше заменена през 1982 г. от Revision Control System, RCS, която беше по-развита и безплатна алтернатива на SCCS (и която все още се поддържа от проекта GNU).

След RCS дойде CVS, системата за паралелно управление на версиите, пусната за първи път през 1986 г. като набор от скриптове за работа с файлове с версии на RCS в групи. Голяма иновация в CVS е, че в CVS множество потребители могат да редактират файл едновременно и промените ще бъдат обединени по-късно (едновременно редактиране). Появата на такава възможност изискваше обработка на конфликти при редактиране. Разработчиците могат да изпращат нова версия на файл в хранилището само ако е базирана на най-новата версия на този файл, налична в хранилището. Ако има разлики между хранилището и моето работно копие, трябва да разреша всички конфликти между файловете в тях (т.е. от редакции, които засягат едни и същи редове).

CVS също въвежда идеята заклонове(клонове), които позволяват на разработчиците да работят паралелно върху различни части от кода, и тагове, които позволяват последователно създаване на версии, така че да може лесно да се препраща към него. Докато промените в CVS първоначално бяха прокарани през хранилище, разположено на споделена файлова система, в някакъв момент CVS беше внедрен като клиент-сървър архитектура за използване в големи мрежи (като Интернет).

През 2000 г. трима разработчици се събраха, за да напишат нова система за контрол на версиите, която елиминира някои от основните недостатъци на CVS.Беше наречен Subversion. Една от основните разлики с новата система е, че Subversion работи върху цели дървета наведнъж, което означава, че промените във версиите трябва да бъдат атомарни, инкрементални, изолирани и постоянни. Работните копия на Subversion също така запазват оригиналните копия на промените, получени от хранилището, така че обичайната операция за разлика (сравняване на локалното дърво с оригиналното) е много бърза.

Една от интересните концепции в Subversion е, че етикетите и разклоненията са част от дървото на проекта. Един проект в Subversion обикновено се разделя на три части:тагове,клоновеиствол(ствол). Това решение се оказа интуитивно за потребители, които не бяха запознати със системите за контрол на версиите, въпреки че гъвкавостта, присъща на този дизайн, доведе до много проблеми за инструментите за преобразуване, тъй като таговете и разклоненията имат по-структурирано представяне в други системи.

Всички горепосочени системи сацентрализирани; започвайки с CVS, всички те знаят как да споделят промените помежду си, докато използват конкретен компютър, който следи хронологията на промените в хранилището. Вместо товаРазпределенатасистема за контрол на версиите пази копие на цялата (или повечето) от хронологията от хранилището на всяка машина, която има нейно работно копие.

12.1.2. Разпределен контрол на версиите

Въпреки че Subversion очевидно превъзхождаше CVS, той все още имаше редица недостатъци.

Първо, във всички централизирани системи за контрол на версиите извършването на промени (операцияcommit) и публикуването им са по същество еднакви, тъй като историята на хранилището се съхранява централно на едно място. Това означава, че подаването на променибез достъп до мрежата не е възможно.

Второ, достъпът до хранилища в централизираните системи винаги изисква прехвърляне на данни през мрежата към сървъра, което прави такива системи относително бавни в сравнение с локалния достъп в разпределените системи.

Трето, системите, описани по-рано, имаха определени слабости в проследяването на сливания (въпреки че някои от тях оттогава са подобрили поддръжката си). За големи екипи от разработчици, работещи по едно и също време, е важно системата за контрол на версиите да записва какви промени са включени в новите версии на кода, така че нищо да не се губи и последващите сливания да могат да използват тази информация.

Четвърто, централизацията, изисквана от традиционните системи за контрол на версиите, изглежда изкуствена и изисква единно пространство за интеграция. Привържениците на разпределените системи за контрол на версиите твърдят, че разпределените системи позволяват по-безпроблемна организация на работата: разработчиците могат да прехвърлят и интегрират промени, както се изисква от проекта във всеки един момент.

За решаване на проблемите, описани по-горе, се появиха няколко инструмента. От моята позиция (позицията на разработчик с отворен код) най-важните за 2011 г. бяха Git, Mercurial и Bazaar. Проектите Git и Mercurial започнаха през 2005 г., когато разработчиците на ядрото на Linux решиха да не използват повече патентованата система BitKeeper. И двете бяха стартирани от разработчици на Linux (съответно Линус Торвалдс и Мат Макол) с цел създаване на системи за контрол на версиите, които могат да обработват стотици хиляди промени в десетки хиляди файлове (например ядрото на Linux). И Мат, и Линус бяха повлияни от Monotone VCS. Bazaar е разработен отделно, но става широко използван приблизително по същото време,тъй като беше използван от Canonical за всички техни проекти.

Създаването на разпределена система за контрол на версиите, разбира се, създава определени трудности, много от които са присъщи на всички разпределени системи. Като за начало, докато в централизираните системи винаги има канонична версия на хронологията на промените на сървъра, в разпределените системи няма такава версия. Промените могат да се извършват паралелно, което прави невъзможно сортирането на промените по време във всяко отделно хранилище.

Почти универсално се използва графика на насочена ациклична промяна (DAG) за решаване на този проблем вместо линейно подреждане (Фигура 1). Това означава, че добавената и ангажирана промяна на кода е потомък на версията на кода, върху която е направена, и никоя версия не може да зависи от себе си или от своите потомци. В тази схема имаме три специални типа ревизии на код:основна ревизия, която няма предшественици (едно хранилище може да има множество корени),обединяваща ревизия(която има множество предшественици) иглавна ревизия, която няма наследници. Всяко хранилище започва с празна основна версия на кода и продължава оттам по няколко реда за промяна, завършвайки с една или повече основни версии. Ако двама потребители независимо са извършили промените си и единият от тях иска да получи промени в кода от другия, тогава той ще трябва изрично да обедини промените, направени от другия потребител, в нова версия, която след това ангажира като версия за сливане.

Фигура 12.1: Насочена графика на ациклична версия

Имайте предвид, че този графичен модел помага за решаването на някои от проблемите, които причиняват трудности в централизираните системи:версиите за сливане се използват за запис на информация за новослети клонове на графика. Получената графика може също така полезно да представлява голяма група от паралелни клонове, свързани в по-малки групи, които в крайна сметка ще бъдат свързани в един специален клон, считан за каноничен.

Всичко това може да бъде доста сложно за хора, които преди са използвали само централизирани VCS: няма нито едно цяло число за версията, а само шестнадесетичен низ от 40 знака. Освен това вече няма глобално сортиране, а само локално; вместо глобално линейно сортиране, има само насочена подредена графика. Случайното създаване на нов път на разработка, когато натискате промяна в родителска версия, която вече има един дъщерен път, може да бъде объркващо, ако сте свикнали да получавате предупреждение от контрола на източника, когато тази ситуация се е случвала преди.

За щастие има инструменти, които помагат да се визуализира дървото, а Mercurial предоставя възможността да се използват кратки версии на хеша, както и числа за идентифициране на локални промени. Последният използва нарастващо цяло число, което представлява реда, в който промените са добавени към копието. Тъй като този ред може да е различен от копие до копие, той не може да се използва в нелокални операции.