![]() |
Системы контроля версий |
![]() |
Понятие системы управления версиями
Системой управления версиями (Version Control System, VCS; реже - Revision Control System, RCS) называется программное обеспечение, позволяющее хранить историю изменения одного или нескольких файлов. VCS применяются, в первую очередь, при разработке крупных программных продуктов для того, чтобы отслеживать кто из разработчиков и когда именно внес те или иные изменения в код проекта. Помимо функции журналирования, VCS позволяют возвращаться к предыдущим состояниям отслеживаемых файлов. Это используется, например, когда необходимо определить из-за какого именно изменения программа перестала работать правильно. Наконец, VCS автоматизирует процесс получения и передачи изменений между разработчиками: каждый раз, когда разработчик фиксирует изменение, другие участники могут автоматически применить их к своей копии проекта. Необходимо отметить, что системы управления версиями эффективны лишь при обработке простых текстовых документов (plain text). Это обусловлено тем, что для файлов, использующих двоичные форматы хранения данных, практически невозможно создать алгоритм для вычисления разницы между двумя версиями. Как следствие, в этом случае VCS может обеспечить лишь журналирование изменений и переключение между версиями, причем система будет хранить не разницу между файлами, а всё содержимое целиком.
В настоящее время выделяются два подхода к организации систем управления версиями:
- Централизованные VCS.
- Распределенные VCS (DVCS).
Первые VCS использовали централизованную архитектуру. При использовании такой архитектуры, VCS представляет из себя классическое клиент-серверное приложение. Центральный сервер VCS непосредственно хранит файлы проекта и их историю, а клиентские приложения запрашивают у сервера необходимые им версии интересующих их файлов. Одним из главных недостатков такого подхода является необходимость наличия доступа к сети при совершении операций с репозиторием. Каждый раз, когда разработчику требуется переключиться на другую версию файла, просмотреть историю изменений или даже зафиксировать собственные изменения, клиент VCS должен соединяться с сервером. Это ограничивает возможности разработчиков и замедляет их работу.
Децентрализованные VCS, как следует из названия, не требуют доступа к серверу при совершении операций с репозиторием. Рабочая копия репозитория у каждого из разработчиков является, по своей сути, отдельным сервером. С одной стороны это позволяет фиксировать изменения и просматривать историю, не подключаясь к сети, однако с другой стороны, децентрализация порождает ряд проблем, с которыми невозможно столкнуться в традиционных системах. К таким проблемам относятся большой размер рабочей копии (т.к. VCS необходимо хранить всю информацию о репозитории), а так же сложности при обмене изменениями с другими участниками.
Тем не менее, на сегодняшний день, можно утверждать, что распространенность централизованных VCS постоянно уменьшается, и всё больше open-source проектов используют децентрализованные VCS.
Централизованные системы управления версиями
Одной из первых централизованных систем управления версиями является проект CVS (Concurrent Versioning System). Она была разработана в 1986 г. и переписана на языке С в 1990 г. Главной особенностью CVS было то, что система хранила информацию о текущей ревизии файла в самом файле, в виде комментария. Как следствие, CVS могла применяться только для управления исходным кодом, т.к. для двоичных файлов не существует возможности вставки комментариев в произвольные участки.
Вслед за CVS в 2000 г. была разработана система SVN (Subversion), исправившая многие проблемы CVS. Помимо хранения метаданных отдельно от управляемых файлов, SVN позволяла создавать копии ветвей файловой системы, не занимая при этом дополнительного места на жестком диске сервера. Как и CVS, исходный код Subversion открыт и лицензирован под свободной лицензией Apache 2. На данный момент, Subversion осталась практически единственным представителем централизованных VCS, которая все еще используется в реальных проектах.
Клиент системы Subversion представляет из себя утилиту командной строки. Все операции с репозиторием и локальной рабочей копией совершаются путем ввода определенных комбинаций команд и флагов. Помимо консольного клиента существует ряд альтернативных графических клиентских приложений (TortoiseSVN, KDESVN и др.). Они представляют функционал, аналогичный консольному клиенту, но являются более дружелюбными по отношению к начинающему пользователю. Также, существуют задачи, которые принципиально удобнее решать с помощью графических клиентов, например просмотр построчной истории изменения файла (т.н. blame).
После Subversion был разработан ряд проприетарных VCS, которые не получили особой популярности как ввиду закрытости исходного кода, так и по причине появления нового, децентрализованного, подхода к организации подобных систем.
Децентрализованные системы управления версиями
Первые децентрализованные VCS являлись экспериментальными проектами, т.е. площадками, на которых испытывались новые идеи по управлению версиями файлов. Среди ранних DVCS можно отметить Darcs, в которой была применена формальная математическая модель для обработки изменений файлов. Darcs написана на языке Haskell, и не смотря на небольшую популярность, все еще поддерживается и используется в ряде проектов сообщества Haskell.
Главный толчок к развитию DVCS, приведший к появлению двух наиболее используемых на сегодняшний день систем, произошел в 2005 г., когда компания BitMover, занимающаяся разработкой DVCS под названием BitKeeper, объявила о приостановке выпуска бесплатных версий. В тот момент BitKeeper применялся для разработки ядра Linux, крупнейшего open-source проекта того времени. После недолгих споров, сообщество Linux во главе с главным ее разработчиком Линусом Торвальдсом приняли решение о начале разработки новой DVCS под названием git. Параллельно с git, другой группой разработчиков, была начата разработка еще одной DVCS - Mercurial.
На сегодняшний день, git и Mercurial являются наиболее популярными распределенными системами контроля версий. Mercurial сильно уступает git по популярности, однако обе DVCS имеют свои сильные стороны и уникальные особенности.
Отметим еще раз, что под децентрализованностью VCS в данном случае понимается не факт принципиального отсутствия сервера VCS, а то что каждый участник проекта сам по себе является полноправным сервером. Теоретически, это позволяет разработчикам обмениваться изменениями напрямую друг с другом. Однако, на практике бывает удобнее организовать отдельный сервер, играющий роль концентратора. Функционально, такой концентратор ничем не отличается от сервера обычного разработчика, и играет роль общего “места встречи”. Каждый раз, когда разработчику требуется получить самую последнюю версию проекта, он обращается за ней на сервер-концентратор, а не к одному из своих коллег. Аналогичным образом, когда разработчик хочет поделиться своими изменениями с коллегами, он отправляет их на тот же сервер-концентратор.
С развитием DVCS стала актуальной разработка web-обвязок к серверам репозиториев. Такая обвязка представляет собой, с одной стороны графический клиент VCS, оформленный в виде web-приложения, а с другой стороны - административную панель, позволяющую управлять доступом пользователей и непосредственно репозиториями. Примерами таких систем с открытым исходным кодом могут служить проекты Phabricator и GitLab. К коммерческим продуктам, предоставляющим тот же функционал относятся BitBucket и GitHub.
Основные понятия систем управления версиями
Центральным понятием любой VCS является репозиторий. В зависимости от внутреннего устройства VCS, под репозиторием может пониматься:
- Ветвь файловой системы и связанная с ней история её изменения.
- Множество файлов, где для каждого файла хранится как текущая, так и все предыдущие версии
В централизованных VCS помимо понятия репозитория используется еще один термин - рабочая копия. В этом случае репозиторием называется информация, хранимая на сервере VCS, а рабочей копией - информация, которой располагает отдельный разработчик. Таким образом, рабочая копия содержит лишь часть той информации, которая содержится в репозитории.
История изменений хранится в виде последовательности правок (или зафиксированных изменений, англ. commit). Каждую правку можно рассматривать как информацию об изменениях в одном или нескольких файлах. Под термином ревизия (revision) нужно понимать состояние файлов проекта после применения определенных правок. Однако, на бытовом уровне этот термин чаще используется для обозначения идентификатора правки. В Subversion ревизии идентифицируются обычными числами, которые возрастают по мере добавления правок. В распределенных VCS в качестве ревизий используется результат применения некоторой хэш-функции (в git и Mercurial - SHA) к содержимому правки. Работать с хэш-идентификаторами несколько сложнее, чем с номерами ревизий. Их труднее запомнить, а так же нельзя оценить “на глаз” какая из двух правок была сделана раньше, а какая - позже.
В простейшем случае, правки следуют друг за другом, образуя ветвь. Если в репозитории присутствует только одна ветвь, это означает, что у каждой правки существует строго одна правка-предшественник и строго одна правка-последователь (разумеется, кроме самой первой и самой последней правок). Любая VCS позволяет добавлять к правкам комментарии, причем Mercurial и git требуют обязательного наличия непустого комментария. Комментарии обычно содержат описание изменений, содержащихся в правке, в свободной форме. Считается хорошим тоном, когда комментарий начинается с единственного предложения, кратко описывающего правку, за которым отдельным абзацем следует более развернутое описание:
Привел модуль DatabaseConnector к современному виду.
- устаревшие вызовы connect() и disconnect() заменены на новые connect2() и disconnect2()
- переименовал приватные поля в camelCase
- отформатировал код в соответствии со стандартом
- функциональные изменения отсутствуют
На практике, в репозиториях более-менее крупных проектов возникает множество ветвей. В Subversion создание ветви сводится к копированию файловой иерархии в другую директорию внутри того же самого репозитория. Разработчики, скачивая рабочую копию, указывают директорию и, таким образом, выбирают ветвь, над которой собираются работать. В Mercurial и git ветвление реализуется более естественным образом, благодаря тому, что каждая правка может иметь несколько предшественников и последователей. Тем не менее, существуют важные отличия в принципах ветвления между этими DVCS, о которых будет сказано ниже.
Процесс получения новых правок с удаленного репозитория называется обновлением (update) в Subversion и затягиванием (pull) в большинстве DVCS. Полученные правки иногда содержат изменения, не совместимые с локальными правками разработчика - например, разработчик переименовал какую-либо переменную, а в обновленной версии эта переменная была удалена. Такое положение вещей называется конфликтом. Конфликты, как явление, неизбежны, и не являются недоработкой какой-нибудь отдельно взятой VCS. Однако, современные VCS содержат механизмы, позволяющие автоматически разрешать конфликты, снижая таким образом объем ручной работы.
Наконец, с распределенными VCS связано понятие проталкивания (pull) - процесса, обратного затягиванию. Как уже было сказано, в централизованных VCS большинство операций совершаются на сервере. Это относится и к операции фиксации изменений, commit, что означает, что при работе с Subversion, не может возникнуть ситуации, когда рабочая копия содержит правки, которые еще не присутствуют на сервере. В распределенных же VCS новые правки создаются локально, причем разработчик может продолжать вносить все новые и новые правки, накапливая их в своем репозитории. Для того, чтобы поделиться ими с другими участниками и используется операция проталкивания (push). Аналогично затягиванию, при проталкивании может возникнуть конфликт, в результате которого правки не будут приняты удаленной стороной. Чтобы разрешить конфликт, разработчику будет необходимо сперва затянуть несовместимые правки, затем объединить их с локальными, разрешая конфликты, и только после этого повторить операцию проталкивания.
Вычисление и применение разниц
Как уже было сказано ранее, правка представляет собой разницу между старой и новой версией одного или нескольких файлов. Существует несколько форматов, описывающих разницу текстовых файлов, однако наиболее часто используется формат, называемый unified diff (от англ. universal difference). В unified diff измененные части файла обрамляются неизмененными (называемые контекстом), что позволяет накладывать изменения даже в случае несовпадения номеров строк.
На Unix-подобных ОС для создания файлов-разниц применяется утилита diff
.
Рассмотрим принцип ее работы на следующем примере. Допустим, у нас имеется
текстовый файл a.txt
со следующим содержимым:
a
b
c
d
e
f
g
h
i
Изменим в этом файле букву c
на z
, сохраним его под именем b.txt
, а затем
выполним команду diff -u a.txt b.txt
, для того чтобы отобразить разницу между
этими файлами:
--- a.txt 2021-01-27 18:58:58.484818000 +0300
+++ b.txt 2021-01-27 18:59:04.372783000 +0300
@@ -1,6 +1,6 @@
a
b-c
+z
d
e f
Первые две строки вывода команды являются заголовком. Информация, содержащаяся в заголовке говорит о том, между какими файлами, а так же в какое время вычислялась разница. Перед заголовком может следовать вообще любая текстовая информация, чем зачастую пользуются разработчики, для того чтобы снабдить файл разницы каким-либо комментарием.
Область файла, начинающаяся с @@ -1,6 +1,6 @@
называется диапазоном (англ.
hunk). Утилита diff
генерирует по диапазону для каждого отдельного
изменения внутри файла. Пара чисел перед знаком -
относится к исходному файлу,
а пара перед знаком +
- к измененному. В каждой паре первое число указывает
число измененных строк в диапазоне, а второе - номер строки, с которой
начинается диапазон изменений.
Вывод команды diff
можно сохранить в файл и передать другому пользователю,
который может объединить его со своей версией файла a.txt
. Для операции
наложения разницы применяется другая утилита, называемая patch
. Благодаря
строкам контекста, patch
способен применять изменения даже в том случае, если
номера изменямых строк в файле разницы не совпадает с исходным файлом.
При работе с современными VCS не всегда требуется напрямую вызывать утилиты
diff
и patch
. Вместо этого, при отображении содержимого правок, или
сравнении ревизий, VCS автоматически создает временные файлы нужных версий и
сравнивает их. Тем не менее, каждому разработчику необходимо уметь читать
формат unified diff, например для того, чтобы визуально оценивать насколько
две ветви правок разошлись друг от друга.
Базовые приемы работы с распределенными VCS
Создание нового репозитория
Команды hg init
и git init
создают новый Mercurial или git репозиторий в
текущей папке. Фактически, эти команды создают скрытые каталоги .hg
или
.git
, соответственно, которые будут содержать все данные репозитория. Сразу
после создания репозиторий не содержит ни одной правки, и все файлы, которые
уже существовали на момент создания, необходимо добавлять в репозиторий вручную.
Клонирование существующего репозитория
Чтобы получить копию уже существующего репозитория используются команды
hg clone URL
и git clone URL
. В качестве URL могут выступать:
- HTTP и HTTPS ссылки (
http://somesite.org/repository
) - SSH ссылки (
ssh://somesite.org/repository
) - Локальные файловые пути (
C:\\repository
)
git
имеет собственный протокол передачи данных, и поэтому поддерживает еще
один вид ссылок - git://somesite.org/repository
.
В результате выполнения команды клонирования, в текущей папке будет создана директория, содержащая клон удаленного репозитория.
Просмотр текущего состояния репозитория
Команды hg status
и git status
позволяют просмотреть текущее положение дел
в репозитории. Информация, выводимая этими командами содержит:
- наименование текущей ветки.
- номер (или хэш-идентификатор) последней правки.
- список файлов, измененных с последней правки. В этот список входят также удаленные и добавленные файлы.
В Mercurial для обозначения статуса файлов используются однобуквенные коды. Например, в выводе
% hg status
M bsdisks.conf.5
R bsdisks.h
A camcontrol2.c
? README
! main.c
Код M
означает, что файл bsdisks.conf.5
был изменен, bsdisks.h
- удален,
а camcontrol2.c
- добавлен. Код ?
означает, что файл README
еще не
добавлен в репозиторий, и не будет включен в следующую правку. Необходимо
выполнить команду hg add README
, чтобы переключить состояние ?
в A
. Код
!
означает, что файл был удален пользователем, но не был помечен для удаления
в репозитории. Команда hg rm main.c
переключает состояние !
в R
.
В отличие от Subversion и Mercurial, в git необходимо вручную помечать все
изменения, подлежащие включению в создаваемую правку. Если выполнить команду
git status
после редактирования файлов проекта, можно увидеть такую картину:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: CMakeLists.txt
modified: test/Feature/SolverTimeout.c
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
Здесь, строки в первой секции содержат измененные и удаленные файлы, а строки
во второй секции - файлы, еще не добавленные в репозиторий. Однако, в результате
выполнения команды git commit
ничего не произойдет, т.к. все перечисленные
изменения не были помечены как подлежащие включению в правку. В этом состоит
важное отличие git от других систем контроля версий.
Индекс git
Индексом (англ. index или stage) в git называется промежуточная
область хранения данных между рабочей копией (файлами проекта на диске) и
зафиксированными правками, добавленными в историю репозитория. Команда git add
переносит изменения из рабочей копии в индекс. Например, если для предыдущего
примера выполнить git add test/Feature/SolverTimeout.c
, а затем снова
отобразить статус файлов, мы увидим следующее:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test/Feature/SolverTimeout.c
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: CMakeLists.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
Файл test/Feature/SolverTimeout.c
теперь занесён в индекс, и при выполнении
команды git commit
, будет создана правка, содержащая изменения лишь этого файла.
Остальные файлы из вывода git status
не будут зафиксированы в правке, и
продолжат фигурировать в выводе. Можно сказать, что git commit
переносит
изменения из индекса в историю, а git add
- из рабочей директории в индекс.
Удаленные файлы переносятся в индекс командой git rm
. В примере выше, нам
понадобится эта команда для переноса удаленного файла CMakeLists.txt
. Наконец,
та же команда git add
используется и для добавления новых файлов в репозиторий.
Таким образом, чтобы занести все изменения из нашего примера в индекс, необходимо
выполнить git add README
и git rm CMakeLists.txt
. В результате, git status
вернет следующий результат:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: CMakeLists.txt
new file: README
modified: test/Feature/SolverTimeout.c
Секция “Untracked files” исчезла из вывода. Это означает, что все изменения были внесены в индекс и будут зафиксированы в следующей правке.
Откат незафиксированных изменений
В процессе работы с кодом часто возникает необходимость отменить изменения,
произведенные с момента последней правки. Такое действие называется откатом
(англ. revert). В Mercurial эта операция производится с помощью команды
hg revert
. В качестве аргументов команды перечисляются файлы, изменения которых
необходимо отменить. Иначе говоря, эта команда исключает файлы, помеченные кодами
M
, R
и !
из последующего вывода hg status
. Если не указан флаг
--no-backups
, перед откатом каждого файла создаётся резервная копия с
расширением .orig
. Если у рабочей директории имеется более одной родительской
ревизии, команде hg revert
необходимо указывать номер той из них, к которой
совершается откат, с помощью флага -r
.
В VCS git операцию отката можно производить не только над рабочей директорией,
но и над индексом. Команда git restore
без дополнительных флагов повторяет
поведение hg revert
, т.е. она восстанавливает состояние файлов рабочей
директории. Например, git restore test/Feature/SolverTimeout.c
, выполненная
для первого примера приведет к исчезновению строчки
modified: test/Feature/SolverTimeout.c
из вывода git status
. Для того, чтобы откатить изменения в индексе git, в
команде git restore
применяется флаг --cached
. Так, выполнение
git restore --cached test/Feature/SolverTimeout.c
для второго примера приведет
к удалению файла из индекса, и в результате он будет исключен из следующей правки.
Откат индекса не затрагивает никаких файлов в рабочей директории.
Откат правок
Может возникнуть ситуация, когда нежелательные изменения уже были зафиксированы в виде правки. Из-за распределенной архитектуры рассматриваемых VCS, редактирование правок в общем случае является нежелательным. Как следствие, общепринятым способом решения подобных проблем является создание еще одной правки, исправляющей ошибки предыдущей.
Команда hg backout <rev>
создает новую правку, отменяющую изменения правки
<rev>
. Это достигается путем обращения (“отзеркаливания”) всех интервалов
разницы из ошибочной правки. Например, если в ошибочной правке присутствовал
интервал
-- somefile
++ somefile
@@ -1,1 +1,1 @@
-a
+b
то его обратная версия будет иметь вид
-- somefile
++ somefile
@@ -1,1 +1,1 @@
-b
+a
Если между последней правкой, и правкой, которую требуется откатить, имеются другие правки, то при попытке отката может возникнуть конфликт изменений. В этом случае разработчик должен вручную разрешить конфликт, однако правка-откат уже не будет “зеркальной” копией предыдущей.
В git для отката правок используется команда git revert
, аналог которой в
Mercurial применяется для отката незафиксированных изменений. Необходимо
помнить об этом различии.
Редактирование истории изменений
В централизованных системах контроля версий внесение изменений в историю правок не вызывает трудностей. Большая часть информации, которой оперируют клиенты, хранится на сервере, и запрашивается ими по мере необходимости. Это позволяет, например, изменить комментарий уже существующей правки, не нарушая работу остальных клиентов. При следующем обновлении рабочей копии, другой клиент получит обновленную информацию о правке и отразит это изменение локально.
Децентрализированные VCS сильно ограничены в возможностях редактирования
истории изменений. Любая правка, измененная локально одним разработчик, будет
выглядеть как совершенно новая для других разработчиков. При этом старая,
неизменённая правка так же будет присутствовать в репозитории, что неизбежно
приведет к путанице и конфликту правок. Тем не менее, и git и Mercurial обладают
набором команд, позволяющих редактировать не только сами правки, но и порядок
их следования. Чтобы избежать негативных эффектов при применении этих команд,
необходимо следить за тем, чтобы обрабатываемые правки присутствовали только в
локальном репозитории. Другими словами, нельзя редактировать те правки, которые
уже были отправлены хотя бы на один удаленный репозиторий командой push
.
В Mercurial существует дополнительный механизм безопасности, предотвращающий
редактирование уже опубликованных правок, называемый Phases. Суть его
состоит в том, что к каждой правке прикрепляется свойство, устанавливающее ее
“фазу”. На данный момент, существует три фазы: secret
, draft
и public
. По
умолчанию, созданные правки имеют фазу draft
, а при выполнении операции push
фазы всех переданных правок заменяются на public
. Главная идея механизма фаз
заключается в том, что переключение свойства может осуществляться только в одну
сторону. Секретная правка может быть сделана черновой, так же как черновая -
публичной, однако фазу публичной правки изменить уже нельзя. В свою очередь,
операции по редактированию истории могут сверяться со значением свойства перед
выполнением опасных действий.
Редактирование последней правки
Чаще всего возникает необходимость отредактировать самую последнюю сделанную
правку. Для этого случая используются команды
hg commit --amend
/git commit --amend
, добавляющие текущие изменения в
рабочей директории или индексе не в новую, а в последнюю сделаннаю правку.
Чтобы изменить только комментарий к правке, необходимо выполнить команду, не
изменяя никаких файлов проекта.
Перенос ветвей
Другой распространенной причиной редактирования истории в DVCS является “пересадка” ветвей правок. Например, если некоторый разработчик ведет работу в собственной локальной ветви, то его ветвь будет неизбежно отставать от основной, в которой ведут работу все остальные участники проекта. Чтобы затянуть изменения из основной ветви в локальную, разработчик может выполнить “пересадку” своей ветви на новую верхушку основной ветви. Не смотря на то, что содержание правок при этом не всегда изменяется, такая операция, тем не менее, является операцией редактирования истории, т.к. у всех правок изменяются ссылки на родительские/дочерние правки.
Перенос ветвей осуществляется с помощью команды hg rebase
/git rebase
. Для
того, чтобы перенести ветвь A
на ветвь B
, необходимо сначала переключиться
на ветвь A
, а затем выполнить команду rebase
, передав ей B
в качестве
аргумента. В процессе переноса могут возникнуть конфликты, так же как в процессе
слияния. В этом случае перенос остановится на конфликтной правке и VCS предложит
вам разрешить конфликт вручную. По успешном разрешении, необходимо выполнить
команду rebase
с параметром --continue
, чтобы продолжить процесс. Чтобы
отменить всю операцию переноса, можно воспользоваться параметром --abort
.
Редактирование произвольных правок
Задача редактирования правок, находящихся в произвольном месте истории изменений, в Mercurial и git решается различными путями.
В Mercurial достаточно переключиться на проблемную ревизию (hg update
), а
затем отредактировать правку с помощью рассмотренной ранее hg commit --amend
.
Отредактировав все правки таким образом, неоходимо выполнить команду hg evolve
,
чтобы разрешить возможные конфликты, возникшие между новыми изменениями.
В git задачи редактирования, объединения и удаления правок решаются с помощью
одного и того же инструмента - интерактивного переноса. Команда
git rebase -i
запустит текстовый редактор, содержащий строки вида
pick 31d4d083 Descr1
pick 0de67b9f Descr1
pick ebd3eb0e Descr1
...
Редактируемый файл представляет собой сценарий процесса переноса, где каждая строка соответствует отдельной правке. Действие, которое будет совершено над правкой определяется ключевым словом в начале строки:
pick
означает, что правку не нужно изменять никаким образомreword
предложит пользователю изменить комментарий к правкеedit
приведет к тому, что процесс переноса остановится на данной правке, для того чтобы пользователь мог отредактировать как комментарий, так и содержимое правкиsquash
объединяет правку с предыдущей - как сами изменения, так и комментарииfixup
аналогичноsquash
, но отбрасывает комментарий текущей правкиexec
позволяет выполнить произвольную команду в директории с репозиторием в момент обработки текущей правкиbreak
подобноedit
, однако остановка происходит до применения текущей правкиdrop
удаляет данную правку- полное удаление строки из файла сценария так же приводит к удалению правки
По завершению редактирования файла сценария необходимо сохранить его и закрыть
текстовый редактор. git
начнет выполнять операцию переноса, интерпретируя
сценарий построчно. При остановке процесса, вызванного обработкой строк с edit
или break
(а так же при возникновении конфликтов), продолжить его можно с
помощью git rebase --continue
. Для того чтобы вернуть репозиторий в состояние
до переноса используется команда git rebase --abort
.
Контрольные вопросы
- Что такое системы контроля версий и для чего они предназначены?
- В чем преимущества распределенных VCS перед централизованными?
- Какие основные операции можно производить над репозиторием DVCS?
- Что такое индекс в git?
- В чем отличия в процессе отката правок в Mercurial и git?
- Какие действия можно производить в процессе интерактивного переноса в git?
Задание на лабораторную работу
Mercurial
При выполнении заданий по VCS Mercurial допускается использовать графическую оболочку TortoiseHG или SourceTree.
- Склонируйте проект apokatastasis.
- Включите расширения Mercurial evolve, topic и rebase.
- Произведите слияние веток default и bugfix, корректно разрешая возникающие конфликты. Результат слияния необходимо расположить в ветке default, а ветвь bugfix необходимо закрыть.
- Создайте новую ветвь и дополните функции из модуля наладка,
помеченные
TODO:
, разбив изменения на несколько отдельных правок. - В этой же ветви создайте еще один файл с кодом в модуле наладка и добавьте его в репозиторий.
- Вернитесь к ветви default и создайте правку, обновляющую год копирайта на новый во всех файлах проекта.
- Вернитесь к своей ветви, и используя команды расширения rebase, перебазируйте правки на новую вершину ветки default.
- С помощью команд расширения evolve отредактируйте свои правки таким образом, чтобы они включали в себя корректные копирайты.
- Слияние последней ветки производить не следует.
- Сохраните разницу между своей ветвью и основной ветвью в файл разницы.
- Удалите свою ветвь и используйте файл разницы из предыдущего пункта, чтобы внести изменения из своей ветви в основную.
git
При выполнении заданий по VCS git необходимо использовать консольный клиент.
- Создайте новое решение на языке C# с помощью Visual Studio. Решение должно содержать файл README, а так же как минимум два проекта (например, библиотеку классов и консольное или графическое приложение).
- Скомпилируйте все проекты решения.
- Создайте репозиторий git, добавьте в него файлы вашего проекта и создайте первую правку. Важно не добавлять файлы, являющимися продуктами сборки, а только исходные файлы проекта.
- Создайте новую ветвь и внесите в нее несколько правок.
- Произведите слияние новой ветви с существующей.
- Создайте еще одну ветвь и внесите в нее несколько правок.
- Переключитесь на основную ветвь и внесите в нее несколько правок.
- Вернитесь к вашей ветви и перебазируйте ее на основную ветвь.
- Измените содержимое или описание одной или нескольких правок с помощью интерактивного перебазирования.
- Слияние этой ветки с основной производить не следует.
- Сохраните разницу между своей ветвью и основной ветвью в файл разницы.
- Удалите свою ветвь и используйте файл разницы из предыдущего пункта, чтобы внести изменения из своей ветви в основную.
