Системы контроля версий (VCS)
Выбери формат для чтения
Загружаем конспект в формате pdf
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Системы контроля
версий (VCS)
Курс «Разработка ПО систем управления»
Кафедра управления и информатики НИУ «МЭИ»
Осень 2017 г.
Проблема: управление кодом
▪ Написан новый код, проект перестал работать.
• Как вернуться к прежней версии?
• Резервные копии, в которых трудно искать и легко запутаться.
• Как узнать, что именно изменилось (файлы и строки)?
• Вручную («глазами»), программой fc (для каждой пары файлов).
▪ Двое пишут разные части одной программы.
• Как проверить, что они не изменили одно и то же?
• Как совместить изменения?
• Вручную — сложно, долго, есть риск ошибиться.
▪ Код пишут несколько человек долгое время.
• Как обмениваться версиями?
• Флэшки, почта, «облака» — всё сложно.
• Как уследить за тем, какие были версии и что менялось?
• Почта и т. п., файл-журнал — разобщенно, ненадежно, трудоемко.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
2
Решение: система контроля версий
▪ Написан новый код, проект перестал работать.
• Как вернуться к прежней версии?
• Есть перечень версий (история, журнал), можно вернуться к любой.
• Как узнать, что именно изменилось (файлы и строки)?
• Можно сравнить версии и представить изменения наглядно.
▪ Двое пишут разные части одной программы.
• Как проверить, что они не изменили одно и то же? (См. выше).
• Как совместить изменения?
• Автоматически; когда невозможно — будет ясно, что и почему.
▪ Код пишут несколько человек долгое время.
• Как обмениваться версиями?
• Есть общее хранилище всех версий и средства синхронизации.
• Как уследить за тем, какие были версии и что менялось?
• У версий есть дата создания, автор, примечания.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
3
Почему нужно специальное
решение, а не «облако»?
Разработка программ
• Автоматическое
ведение истории
любых изменений.
• Автоматическая
синхронизация.
• Одновременное
редактирование
в реальном времени.
Осень 2017 г.
• Явное создание
пунктов истории:
• составление набора
сохраняемых изменений;
• комментарии.
• Раздельное редактирование.
• Явное совмещение
наборов изменений.
© Кафедра УиИ НИУ «МЭИ»
4
Git — конкретная СКВ
• Сам Git — консольная программа.
• В поставке для Windows работает в Git Bash,
более удобном терминале, чем cmd.exe.
• Многие работают с Git из терминала:
• Одинаково на любой ОС и любом компьютере.
• Удобно делиться рецептами, копируя команды.
• TortoiseGit — расширение «Проводника» Windows
для работы с Git; есть в лаборатории.
• Отдельные программы: SourceTree, GitG, …
• Внутри IDE: Visual Studio, CLion, QtCreator.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
5
Основные понятия VCS
• Хранилище (repository, сокр. repo), или репозитарий, —
место хранения всех версий и служебной информации.
• Версия (revision), или ревизия, —
состояние всех файлов на определенный момент времени,
сохраненное в репозитарии, с дополнительной информацией
• Коммит (commit; редко переводится как «слепок») —
1) синоним версии;
2) создание новой версии («сделать коммит», «закоммитить»).
• Рабочая копия (working copy или working tree) —
текущее состояние файлов проекта, основанное на версии
из хранилища (обычно на последней).
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
6
Основы Git: инициализация
• Будем работать в пустом каталоге project:
$ mkdir project
$ cd project
(Здесь и далее $ означает ввод в консоль, его не пишут.)
• Инициализируем хранилище:
$ git init
Initialized empty Git repository in /tmp/project/.git/
Теперь project/ — рабочая копия (пустая).
• Просмотрим содержимое каталога:
$ ls -A
.git /
Осень 2017 г.
Это хранилище. Содержимым управляет Git,
не следует ничего там менять.
© Кафедра УиИ НИУ «МЭИ»
7
Основы Git: просмотр состояния
$ git status
On branch master
Initial commit
История не содержит еще коммитов.
nothing to commit (create/copy files and use
"git add" to track)
1. В новый (первый) коммит ничего
не планируется добавить.
2. В рабочей копии нет ничего,
что можно было бы добавить.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
8
Основы Git: пустой коммит
Обычно Git не допускает пустых коммитов,
но в данном случае именно это и нужно.
Комментарий к коммиту
(-m от --message)
$ git commit --allow-empty -m 'начало'
[master (root-commit) 5179fab] начало
Хэш коммита — его уникальный идентификатор,
по которому коммит можно найти:
$ git show 5179fab
commit 5179fab9f3344f6963f474da399fc9c1fe76e41a
Author: Dmitry Kozliuk
Date: Sun Mar 12 15:12:46 2017 +0300
начало
Осень 2017 г.
Берется из настроек Git,
подробнее на ЛР.
© Кафедра УиИ НИУ «МЭИ»
9
Основы Git: обычный коммит
$ echo 'первая строка' > file.txt
$ git status
On branch master
Untracked files:
(use "git add ..." to include in what will be
committed)
file.txt
В рабочей копии замечен файл,
но Git его не отслеживает.
nothing added to commit but untracked files present
(use "git add" to track)
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
10
Основы Git: занесение под СКВ
Файл добавляется в индекс (index) —
$ git add file.txt
набор изменений для будущего коммита.
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
Git начал отслеживать файл.
new file: file.txt
$ git commit -m 'добавлена первая строка'
[master 6c81949] добавлена первая строка
1 file changed, 1 insertion(+)
create mode 100644 file.txt
Сводная статистика изменений.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
11
Основы Git: просмотр истории
Новые коммиты
идут в начале
$ git log --stat
commit 6c81949f524b0ecad60fe02222d9642db0b99120
Author: Dmitry Kozliuk
Date: Sun Mar 12 17:43:18 2017 +0300
добавлена первая строка
file.txt | 1 +
1 file changed, 1 insertion(+)
Ключ --stat показывает
затронутые коммитом файлы.
commit 5179fab9f3344f6963f474da399fc9c1fe76e41a
Author: Dmitry Kozliuk
Date: Sun Mar 12 15:12:46 2017 +0300
начало
Осень 2017 г.
Можно фильтровать по дате, автору,
тексту сообщения, затронутым файлам.
© Кафедра УиИ НИУ «МЭИ»
12
Что такое «branch master»?
короткий формат вывода
показывать ветки
$ git log --oneline --decorate
6c81949 (HEAD -> master) добавлена первая строка
5179fab начало
• Ветвь (branch) — это линейный участок истории.
• Ветвь по умолчанию называется master.
• О том, зачем нужны другие ветви
и как история может быть нелинейной, см. далее.
• В выводе git log отмечен конец ветви.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
13
Устройство Git: объекты и хэши
• Git позволяет сохранить объект (object) и получить
хэш (hash), по которому его затем можно извлечь.
• Объекты могут быть связаны (объект-коммит и объект-файл).
• Хэш подобен адресу в C++.
данные
Git
хэш
Git
данные
хранилище
объект
• Хэш-функция принимает данные любого размера,
а возвращает шестнадцатеричное число (SHA1 в Git: 40 бит).
Вероятность того, что у разных объектов будут одинаковые
хэши (коллизии), исчезающе мала.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
14
Устройство Git: ссылки
• Хэшу можно дать имя (например, master).
Оно называется ссылкой (reference, или ref).
• Ссылка подобна
переменной в C++:
HEAD
master
понятное имя
для ячейки памяти хэша.
• Особая ссылка HEAD указывает не на объект,
а на другую ссылку (а та — на объект).
• HEAD подобна указателю в C++:
позволяет обращаться к переменной объекту,
не зная его имени.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
6c81949
5179fab
15
Устройство Git: операции
$ git commit
• Создать и связать объекты-файлы
и объект-коммит.
• «Передвинуть» ссылку-ветку,
на которую указывает HEAD.
HEAD
master
6c81949
master
5179fab
• HEAD двигать не нужно —
она по-прежнему указывает на master.
• Ветка — ссылка, которая перемещается
при коммитах; по ней можно найти
всю цепочку коммитов.
• Если до коммита нельзя добраться
(по стрелкам) ни от какой ссылки, он «потерян» (невидим).
• Но доступен по хэшу, пока не сделано git gc.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
16
Откат изменений
▪ Сделаны ненужные изменения.
• Коммита еще не было, нужно вернуться к последнему:
$ git reset --hard HEAD
HEAD is now at 6c81949 добавлена первая строка
• То же самое, но для одного файла:
$ git checkout -- file.txt
• Коммит был сделан, нужно вернуться к известному:
$ git reset --hard 6c81949
▪ Сделан негодный коммит; нужно его убрать,
но оставить изменения:
$ git reset HEAD~1
Unstaged changes after reset:
M
file.txt
Осень 2017 г.
Refspec — обозначение
коммита относительно ссылки.
Здесь: на один коммит
назад от HEAD
© Кафедра УиИ НИУ «МЭИ»
17
Создание веток и откат к ним
▪ Нужно перейти к известному коммиту, не удаляя имеющиеся.
1. Создать ветку на нужном коммите:
$ git branch имя-ветки хэш-коммита
2. Переключиться на неё:
$ git checkout имя-ветки
• Создать и переключиться в одно действие:
$ git checkout -b имя-ветки хэш-коммита
3. Переключиться обратно (если стояли на master):
$ git checkout master
Reset («сбросить»)
Checkout («забрать»)
a) перемещает текущую ветвь;
a) меняет текущую ветвь;
b) сбрасывает рабочую копию
к известному состоянию.
b) восстанавливает
состояние отдельного
файла.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
18
Общее хранилище:
централизованная VCS
Рабочая
копия
Сервер СКВ
Общее
хранилище
Сеть
4
3
Рабочая
копия
2
1
Машины разработчиков
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
19
Отдельные хранилища:
распределенная VCS (DVCS)
commit
Рабочая
копия
Локальное
хранилище
Сервер СКВ
checkout
Общее
хранилище
3
2
Машины
разработчиков
Осень 2017 г.
1
© Кафедра УиИ НИУ «МЭИ»
20
Виды систем контроля версий
Централизованные
Распределенные
• Простота использования.
• Двухфазный commit:
• Вся история — всегда в едином
общем хранилище.
• Нужно подключение к сети.
• Резервное копирование нужно
только одному хранилищу.
• Удобство разделения прав
доступа к хранилищу.
• Почти все изменения навсегда
попадают в общее хранилище.
Осень 2017 г.
1) запись в локальную историю;
2) пересылка изменений другим.
• Подключение к сети не нужно.
• Локальные хранилища могут
служить резервными копиями.
• Локальное хранилище
контролирует его владелец,
• но общее — администратор.
• Возможна правка локальной
истории перед отправкой
на сервер.
© Кафедра УиИ НИУ «МЭИ»
21
Удаленное хранилище:
что это и где его взять?
▪ Технически:
1.
2.
Сервер с доступом по сети (HTTPS, SSH).
Само хранилище (например, переименованный .git / )
без рабочей копии (т. н. bare repository).
▪ Доступ к удаленному хранилищу может быть ограничен
администратором на уровне сервера (т. е. в Git это не входит).
▪ Практические решения (изучаются на ЛР):
• Бесплатные или арендуемые хранилища в интернете:
GitHub.com, BitBucket.org, GitLab.com и другие.
• На собственном сервере:
• Просто Git и доступ по сети.
• GitLab, Jira, Gogs, Gitolite, Upsource и другие.
• Большинство решений имеют также web-интерфейс.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
22
Git: загрузка кода в хранилище (1)
Задача. Есть код под Git и адрес хранилища, куда его нужно отправить.
• Сохранить адрес под именем origin (традиционно):
$ git remote add origin https://github.com/user/repo.git
• Отправить коммиты ветви master на сервер,
указав, что она и на сервере будет называться master:
$ git push --set-upstream origin master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 462 bytes | 0 bytes/s, done.
Total 5 (delta 0), reused 0 (delta 0)
Здесь может
понадобиться
ввести пароль.
To https://github.com/user/repo.git
* [new branch]
master -> master
Branch master set up to track remote branch master from origin.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
23
Git: загрузка кода в хранилище (2)
• Задача. Сделаны новые коммиты, нужно добавить их
в удаленное хранилище.
$ git push
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 325 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/user/repo.git
6c81949..10891c2 master -> master
• В соответствующей ветви удаленного хранилища
не должно быть коммитов, которых нет локально.
(Локальная история должна опережать удаленную.)
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
24
Git: загрузка кода из хранилища
• Нужно скопировать с сервера всё:
$ git clone https://github.com/user/repo.git
Cloning into 'repo'...
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 8 (delta 0), reused 8 (delta 0), pack-reused 0
Unpacking objects: 100% (8/8), done.
Каталог, в который
будет загружена
рабочая копия
и хранилище.
• На сервере (origin) появились коммиты,
нужно скачать их в локальное хранилище:
• git fetch origin
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From https://github.com/user/repo
10891c2..0cfc640 master -> origin/master
• Для всех веток: git fetch origin --all.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
25
Обновление: проблема
ПК разработчика
Сервер СКВ
Общее
хранилище
E
Как совместить?
master
origin/master
D
C
Локальное
хранилище
E
G
D
F
fetch
C
B
B
A
A
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
master
рабочая
копия
(G)
26
Обновление: решение (I)
C
G
D
E
C
master
B
F
F’
D
E
G’
origin/master
• История остается линейной, ветвление исчезает.
• История искажается: изменяются коммиты и их порядок.
• Возможны ошибки программиста при переносе коммитов.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
27
Git: перенос ветви
• Текущая ветвь — master. Нужно перенести из master коммиты,
которых нет в origin/master, поверх последней.
$ git rebase origin/master
(вывод зависит от состояния истории)
• Работает для любых ветвей, не только при обновлении.
• Возможны конфликты (когда наложить изменения нельзя).
$ git rebase --abort
• В master нет коммитов, которых нет
в origin/master (т. е. локальных изменений нет).
• git pull --ff-only
Updating 10891c2..0cfc640
Fast-forward
file.txt | 1 +
1 file changed, 1 insertion(+)
• Если локальные изменения есть, не сработает.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
28
Обновление: решение (II)
B
C
F
G
D
E
M
master
• История становится нелинейной:
возникают merge commits (M).
• Если работа велась параллельно,
это остается видно.
• Совмещаются только последние версии — меньше риск
ошибиться программисту.
• Все версии неприкосновенны.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
29
Git: слияние ветвей
$ git merge origin/master
(вывод зависит от состояния истории)
• Если можно сделать fast-forward, Git так и поступит.
• Если автоматическое слияние возможно,
Git создаст новый коммит с отдельным сообщением.
• Возможны конфликты.
$ git merge --abort
• Или разрешение конфликта вручную, затем:
$ git add файл-с-разрешенным-конфликтом
$ git commit
• Изучается на ЛР.
• Работает для любых ветвей, не только при обнолении.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
30
Сравнение версий
Просмотр различий между версиями:
diff (C, B)
diff (C, A)
$ git diff хэш-или-ветвь-A хэш-или-ветвь-B
diff (C, B)
patch (C, M)
Одинаковые
изменения A и B
B
Уникальные
изменения A
A
C
M
diff (C, A)
Уникальные
изменения B
Конфликтующие
изменения A и B
patch (C, M)
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
31
Формат unified diff
заголовок
--- a/main.cpp
+++ b/main.cpp
Обозначение места
изменений в файле.
@@ -7,5 +7,6 @@ int main()
Контекст
(обычно
3 строки)
cout << "Enter A and B: ";
cin >> a >> b;
cout << "A + B = " << a + b << '\n'
+
+
<< "A - B = " << a - b << '\n';
<< "A - B = " << a - b << '\n'
<< "A / B = " << a / b << '\n';
}
Осень 2017 г.
Измененная
функция
(для удобства
чтения).
Удаленные (-) и добавленные (+) строки.
© Кафедра УиИ НИУ «МЭИ»
32
Понятия VCS
• Слияние (merge) —
объединение двух версий в единую;
слияние ветвей — объединение их последних версий.
• Конфликт (conflict) —
ситуация, когда VCS не может автоматически слить внесённые
изменения (т. е. когда были по-разному изменены одни и те же
места в файлах).
• Разность (difference, diff) —
построчные различия между файлами (разных версий).
• Заплатка (patch), патч —
файл-инструкция, какие правки нужно внести (по сути, это diff).
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
33
Основные понятия DVCS
• Загрузка изменений (fetch) —
загрузка наборов изменений (commit-ов) из удаленного хранилища.
• Обновление, «подтягивание» (pull) —
загрузка изменений и немедленное слияние с локальным
хранилищем (pull = fetch + merge).
• Отправка изменений (push) —
передача наборов изменений в удаленное хранилище
с немедленным слиянием.
• Если при слиянии возникает конфликт, происходит ошибка.
• Возможна, но не рекомендуется, force push — принудительная
перезапись удаленной истории (git push --force).
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
34
Ветки и метки
• Зачем нужны несколько веток?
• Параллельная разработка разных
частей программы.
Версия
2.0
• Альтернативные варианты развития:
• экспериментальные наработки;
• правки в старых версиях.
• Обычно есть главная ветка (master),
или ствол (trunk).
• Метка (tag) — отмеченная версия.
Отличие от ветки в том, что тэг
не перемещается при добавлении
коммитов.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
Версия
1.0
master
v1
9
10
7
8
6
Версия
1.1
feature
5
4
2
3
1
35
Git Stash
Несохраненные изменения можно спрятать в специальную
невидимую, строго локальную область — stash. Например:
• Чтобы скачать последние изменения в процессе написания кода.
• Чтобы временно переключиться на другую ветвь.
• Сохранить изменения в stash:
$ git stash save [возможно, примечание]
• Извлечь изменения из stash в рабочую копию:
$ git stash pop
• Stash работает как стек (стопка): можно вызвать save
несколько раз, pop извлекает последние изменения.
• Можно просматривать элементы stash,
удалять их, извлекать не последний.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
36
Модели ветвлений (branching models),
или рабочие процессы (workflows)
Договоренность о ветках внутри команды.
• Кем, когда и зачем создаются?
a) по одной каждым разработчиком для своих задач
b) по ветке на задачу,
c) по ветке на группу связанных задач…
• Что содержат?
• ветка со стабильным кодом,
• ветка с нововведениями…
• Кем, когда, куда и по каким критериям сливаются?
• когда код в ветке протестирован, она сливается в master,
• раз в неделю master сливается во все ветки…
• Как называются?
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
37
Какими должны быть коммиты?
▪ Гранулярность — насколько крупными должны
быть коммиты?
• Большие сложно оценить, задачи смешаны.
• Мелкие неудобно читать, теряется контекст.
• Хорошая идея: размер — одно логическое изменение.
▪ Код в коммитах должен быть компилируемым.
• Git этого не требует, но иначе неудобно на практике.
▪ Сообщения должны отражать цель и суть правок.
• Что именно поменялось, покажет diff.
• Иногда уместны объемные пояснения.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
38
Осталось за рамками
• Настройки Git (изучается на ЛР), в т. ч. .gitignore.
• Staging (Git):
• детальный контроль содержимого очередного commit;
• можно включить в коммит часть файла (hunk).
• Cherry-pick (Git) —
копирование commit-ов между ветвями.
• Pull/merge requests —
запросы администратору (главному разработчику)
на слияние ветки в главную. Применяется в открытых
проектах и дисциплинированных командах.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
39
Прочие VCS и их особенности
• Subversion (SVN):
• Perforce:
o одна из старейших,
и потому все еще популярна;
o Основана на Git, но требует
центрального хранилища;
o централизованная.
o улучшенная работа с файлами
не-кода (документы и т. п.);
• Git:
o распределенная,
популяризовала этот тип;
o самая распространенная
на сегодня (GitHub, BitBucket).
o коммерческая лицензия.
• CVS:
o морально устарела;
• Mercurial (Hg):
o http://SourceForge.net
o распределенная;
o основной конкурент Git,
имеет ряд принципиальных
отличий в дизайне.
Осень 2017 г.
o ядро комплексной системы
ведения проекта;
o имела механизм locks: файл
мог редактировать только один
человек в момент времени.
© Кафедра УиИ НИУ «МЭИ»
40
Ресурсы к лекции
• Scott Chacon, Ben Straub. Pro Git.
$ git help <команда>
• Joel Spolsky. Hg Init: a Mercurial Tutorial.
• Ben Collins-Sussman et al. Version Control with Subversion.
• Хостинги хранилищ:
• GitHub:
• самый популярный;
• больше функций, но только Git;
• бесплатно — только открытые хранилища.
• BitBucket:
• Git, Mercurial;
• есть бесплатные закрытые хранилища;
• я им пользуюсь и смогу подсказать :-).
• Все ссылки есть на странице курса.
Осень 2017 г.
© Кафедра УиИ НИУ «МЭИ»
41