FishVCS.svg

Виталий Филиппов, CUSTIS

Контроль версий: Зачем?

  • Бэкап на случай утери кода
    спонсоры: rm -rf /, Джамшуты, школоло с вирусами
  • Неблокирующие совместные правки, синхронизация
  • Поиск виновного (annotate/blame)
  • Code review
  • Поддержка старых версий

История VCS

…по большей части свободных.

[svg]

Терминология

Метка tag именованная версия проекта
Ветка branch «метка, имеющая историю развития»
Репозиторий repository хранилище версий
Рабочая копия work copy копия проекта, связанная с репозиторием
Коммит, фиксация commit, checkin сохранение изменений в репозитории
Чекаут, извлечение checkout получение рабочей копии (без истории)
Push, pull отправка/получение изменений в/из другого репозитория
cvs HEAD
svn trunk
git master
Основная ветка

На заметку: интерфейсы

  • $ командная строка
  • Web-интерфейсы (для просмотра и поиска).
  • GUI, обычные и встроенные в IDE.

Локальные VCS

Простейший вариант — архивы или папочки со старыми версиями.
(не надо так делать)

SCCS (1972), RCS (1985).

[svg]

Diff, patch, merge

Diff-screenshot.png
  • diff (1970) — подсчёт разницы между текстовыми файлами (алгоритм)
  • patch (1984) — применение этих разниц — патчей
    Автор — Лэрри Уолл (создатель Perl’а)
  • rcsmerge (1982), diff3 (поновее) — слияние изменений

Как это было в RCS

Команды RCS называются просто co и ci.

«Репозиторий» для каждого файла «свой» — файл.txt,v является «репозиторием» для файла.txt. Лежит либо прямо рядом, либо в подпапке RCS.

<создали файл.txt>
$ ci -t-'В этом файле содержится мудрость Господня' файл.txt
файл.txt,v  <--  файл.txt
initial revision: 1.1
done
$ co файл.txt # на посмотреть
файл.txt,v  -->  файл.txt
revision 1.1
done
$ co -l файл.txt # блокируем файл (хотим править)
файл.txt,v  -->  файл.txt
revision 1.1 (locked)
done
<...правим...>
$ ci -m'Мудрость исправлена' файл.txt
файл.txt,v  <--  файл.txt
new revision: 1.2; previous revision: 1.1
done  

Централизованные VCS

  • История версий хранится на центральном сервере
  • Рабочие копии создаются на компьютерах разработчиков

CVS (1990), Subversion (2000).

CVS: прикрученный к RCS сервер

Справедливо решили, что файлы и репозиторий вперемешку — не дело!

Репозиторий теперь хранится отдельно, а то и удалённо. Однако, всё равно пофайлово.

$ export CVSROOT=/path/to/new/repo # задаём путь к репозиторию
$ cvs init # создаём репозиторий
cvs init: Repository /path/to/new/repo initialised
$ cvs import module custis # импорт текущей папки
N module/file
...

No conflicts created by this import
$ cvs co module # извлекаем
cvs checkout: Updating module
U module/file
<...правим файлы...>
cd module
$ cvs ci -m 'Сообщение об исправлении'
cvs commit: Examining .
Checking in file;
/path/to/repo/mod/file,v  <--  file
new revision: 1.2; previous revision: 1.1
done  

CVS: и даже…

TortoiseCVS.png
  • …умеет annotate (blame).
  • …умеет ветвиться и сливаться, хоть и криво.
  • …умеет хуки.
  • …имеет ГУИ — например, TortoiseCVS.

Однако…

  • Репозиторий пофайловый на основе RCS
    версии у файлов отдельные (и дурацкие типа 1.128.2.5)
    коммиты неатомарны
  • Протокол сервера неудобен
  • Устарел в целом (различные мелкие недостатки)
    Маразм: порядок аргументов в командной строке влияет на результат

Subversion: «CVS Done Right»

Apache Software Foundation Logo.svg
Subversion-logo.jpg

Всё поновее, пошустрее, поудобнее (форматы, протоколы…)
Общий номер ревизии, атомарные коммиты
Права доступа**
UTF-8, mime типы, свойства файлов
? Копирование вместо веток/меток; mergeinfo

Web: Viewvc-logo.png

ГУИ: RabbitVCS-rabbit.png RabbitVCS, TortoiseSVN-tort.png TortoiseSVN
(для конченых виндузятников) VisualSVN, AnkhSVN


** Благодаря оным — горячо любим компаниями, в том числе и Этой.

Subversion: однако…

Нет контроля целостности
Не очень удобные ветвления/слияния
Нет родного Web-интерфейса
☹ (?) Централизованная
Торвальдс: «There is no way to do CVS right»

Распределённые VCS

[svg]

  • Каждая копия содержит всю историю ревизий
  • Возможен обмен между любыми участниками
  • Лёгкость ветвления и слияния

TLA / GNU Arch (2001); Monotone, Darcs (2003); Git, Mercurial (2005); Bazaar (2007).

GNU Arch.png Monotone.png Darcs.png Git.png Mercurial.png Bazaar.png

* Ещё были выкидыши типа SVK

Пример ветвления — Feature Branches

Смысл: каждая доработка в отдельной ветке.

Создаются → правятся → сливаются обратно в trunk.

TN-IShop-Revision-Graph.svg

Нюанс

Слияние отменить невозможно!
разрешайте конфликты в ветке «фичи», а не в «мастере».

CantRedoMerge.svg

Как можно обмениваться: дерево доверия

(Репозитории или ветки)

[svg]

Эмуляция централизации

Можно работать с DVCS, почти* как с централизованной!

[svg]


* Вынеся за скобки отсутствие пофайловости.

Минусы DVCS

  • Репозиторий пухнет
    Хочешь Андроид? Слей 6 гигов!
  • Отсутствие пофайловости (и , и )
  • Бывает нужно переписывать историю всех репозиториев в Москве

Откуда ноги растут?

Из разработки ядра Linux!

Tux.svg

Linux

  • 1992—2002: тарболлы и патчи
    «и это была лучшая система контроля версий, чем CVS»
  • 2002—2005 — BitKeeper
    проприетарщики такие проприетарщики
    обиделись на «реверс-инжиниринг» — команду help на сервере
  • Monotone и Darcs уже тоже были
    но первый O(n3), второй O(en)

Из идей Monotone и BitKeeper родились Git (Linus Torvalds) и Mercurial (Matt Mackall).

Linus-torvalds-fuck-nvidia.jpgGit.png         Matt Mackall.jpgMercurial.png

Git и Mercurial

  • Git: Tracking Branches (и , и )
  • Mercurial: Гораздо интиутивнее система команд (см. сюда)
  • Git: В целом быстрее, но не всегда, плюс имеет задержки GC
  • Git: Хранит эффективнее в 1.5-2 раза (в нём граф объектов)
  • Мощность функционала
  • Mercurial: Python, вместо Gitовского микса C+Bash+Perl
  • Git: Есть Gerrit!

Bazaar

Bazaar — творение Ubuntu (с БДж и Ш)

1 клон = 1 ветка ☹☹☹
Принудительные слияния, один HEAD, пляски ревизий ☹☹☹
Есть легковесные Checkout’ы а-ля SVN
Не умеет ASCII-графы рисовать :-D
Зато успешно хавает жирные текстовые файлы.

Rebase

Когда не хочется или невозможно мержить.

Rebase.svg

Очередь патчей (Patch Queue)

Стандартная тема: приём сторонних патчей в свободный проект.

  • Вася пофиксил баг в Mercurial и ещё добавил фичу
  • Сказал hg commit всего вместе
  • Отправляет Мэтту по почте результат hg export
  • А Мэтт говорит:
    1. поправь вот тут и вот там
    2. а ещё раздели патч на багфикс и фичу!
  • …и что делать Васе — клонировать заново?

На помощь идёт MQ!

Mercurial Queues, аналоги — StGIT, bzr-loom. Все по мотивам quilt.

Разделение патчей:

$ hg qimport -n feature -r . # превратить текущую правку в патч
<...выделяем и удаляем багфикс...>
$ hg diff --reverse > P2
$ hg qrefresh # из feature убран багфикс
$ hg qimport -n bugfix -r P2 -P # создаём патч-багфикс  

Правка патчей

Для работы над одним из патчей:

$ hg qpop # временно убираем багфикс для работы над фичей
<...вносим правки Мэтта...>
$ hg qrefresh # сохраняем правки
$ hg qpush # возвращаем багфикс

Если проект по пути обновится:

$ hg qpop -a; hg up; hg qpush -a

Мэтт тем же MQ импортирует (qimport) и принимает (qfinish) патчи.