Learning Platform
Глоссарий Troubleshooting
Урок 03.01 · 18 мин
Начальный
GitVCSИсторияCVSSubversionLinus Torvalds

История систем контроля версий — от tar.gz до Git

Прежде чем разбираться, как устроен Git, полезно понять, почему он вообще выглядит именно так. Многие странности Git — git add перед git commit, отдельный index, концепт staging area, distributed-модель — это не «странные дизайн-решения», а конкретные ответы на конкретные боли предыдущих систем контроля версий. Если вы знаете, какие боли решал Git, то поведение Git становится логичным.

Этот урок — короткая история контроля версий. Не для развлечения — а потому что Git унаследовал кое-что хорошее (от CVS и Subversion), отказался от кое-чего плохого (от тех же CVS и Subversion), и придумал нечто принципиально новое (distributed модель), что переломило индустрию. К концу урока вы будете понимать, чем Git отличается от того, что было до него.


Эра до VCS: 1970-е — начало 1980-х

Представьте: 1975 год, мейнфрейм, программисты пишут код на FORTRAN или COBOL, в команде 10 человек. Как они работали с версиями?

Контроль версий до VCS (1970-е)
Изменил кодПрограммист редактирует файл foo.f на ленте или диске
перед изменением
cp foo.f foo.f.bakДелает резервную копию вручную. Имена варьируются: foo.f.old, foo.f.20.may, foo.f.bak.2
Координация«Алло, Бо́б? Я сейчас правлю foo.f, не трогай». Реально по телефону или у кулера
КонфликтыДвое редактировали один файл одновременно -> один теряет работу. Это считалось НОРМОЙ

Координация была голосовой: «Боб, я редактирую файл, не трогай». Бэкапы — ручное копирование с суффиксом .bak, .old, .20-may. Конфликты решались «кто последний сохранил, тот и прав». При смене программиста никто не знал, какие изменения вносил предыдущий — комментарии в коде типа «// Mike: rewrote this on May 12 because date was wrong» были единственной формой истории.

Это, очевидно, не масштабируется. Когда команда больше 10 человек или проект длиннее 6 месяцев — нужна автоматизация.


SCCS и RCS (1972, 1982): первые VCS

В 1972 году в Bell Labs появилась SCCS (Source Code Control System) — первая система контроля версий. Она хранила историю файла как набор delta (изменений) от первой версии до текущей. Файлы версионировались по одному: sccs get foo.c забирало последнюю версию, sccs delta foo.c фиксировало изменения.

В 1982 году в Purdue University появилась RCS (Revision Control System) — улучшенная SCCS, бесплатная, более удобная в использовании. RCS хранила обратные дельты: текущая версия в чистом виде, а старые — как diff от текущей. Это было быстрее при работе с актуальной версией.

RCS — каждый файл отдельно
foo.c,vФайл версий: текущая версия + diff к каждой предыдущей. Запятая-V в имени — это знак RCS-репозитория
bar.c,vДругой файл — другая независимая история версий. RCS не знал, что foo.c и bar.c — части одного проекта
baz.c,vИ так каждый файл — со своей независимой нумерацией ревизий
БлокировкаКогда программист делал co (checkout) с -l (lock), файл блокировался. Никто другой не мог редактировать, пока блокировка не снята
Один файлRCS работал только с одним файлом. Не было концепта «проект» или «commit, объединяющий несколько файлов»

Главное ограничение SCCS и RCS — они работали по одному файлу. Если ваше «изменение» затрагивает 5 файлов — нет атомарной операции, которая зафиксирует все 5 как единое целое. Каждый файл версионируется независимо, ревизии не синхронизированы.

Кроме того, для редактирования использовалась модель lock-modify-unlock: программист делал co -l foo.c (checkout с lock), редактировал, делал ci foo.c (commit). Пока файл залочен — другие не могли редактировать. На практике это означало: один человек ушёл в отпуск, не сняв lock, — пять коллег ждут.


CVS (1986-1990): первый коммерческий успех

В 1986 году появилась CVS (Concurrent Versions System) — революция. CVS была надстройкой над RCS, но добавила два критических улучшения:

  1. Версионирование всего проекта, а не отдельных файлов. Commit фиксирует состояние нескольких файлов одновременно.
  2. Optimistic concurrency: вместо locks — слияние при конфликте. Несколько программистов могут одновременно редактировать один файл; CVS попытается объединить изменения автоматически, если они в разных строках.
CVS — модель клиент-сервер с optimistic concurrency
CVS ServerЦентральный сервер, на котором хранится репозиторий. Все клиенты подключаются к нему. Без сервера работать нельзя
Programmer Acvs checkout — забирает копию проекта. cvs update — забирает изменения от других. cvs commit — отправляет свои
Programmer BДелает свой checkout, работает независимо. CVS попытается объединить при commit
Programmer CИ так далее. Все ходят к серверу за каждой операцией
Без сетиОтключён интернет -> не можешь сделать commit, не можешь посмотреть log, не можешь сделать diff к прошлой версии. ВСЁ требует сервера

CVS получила огромное распространение. К концу 1990-х CVS был стандартом в open-source: Linux kernel (до Git), FreeBSD, GNU Emacs, gcc — всё на CVS.

Но у CVS были серьёзные проблемы. Главные:

  • Атомарность commit не была реальной. Если сервер падал посреди commit — половина файлов записана, половина нет. Никакой транзакционности.
  • Переименование файлов не отслеживалось. Если вы переименовали foo.c в bar.c, CVS воспринимал это как удаление foo.c и создание нового bar.c. Вся история терялась.
  • Branches и tags были косметикой, реализованной через метки в файлах. Branching был тяжёлой операцией, поэтому в CVS-проектах ветки делались редко.
  • Бинарные файлы требовали ручного флага. Без флага CVS пытался применять текстовые diff к бинарникам и портил их.

Subversion (2000): «CVS done right»

В 2000 году CollabNet запустил проект Subversion (SVN) с прямым лозунгом «CVS done right». Цель: исправить все боли CVS, оставив привычную модель клиент-сервер.

Subversion vs CVS — что починили
Атомарные commitsSVN использовал транзакции BerkeleyDB (потом FSFS). Либо весь commit прошёл, либо целиком откатился. Никаких полу-применённых состояний
Версия проектаВ SVN номер ревизии — это номер всего репозитория, а не отдельного файла. r12 — это конкретное состояние всего проекта
ПереименованияSVN отслеживал rename как одну операцию: история файла сохранялась даже после переименования
Cheap branchesBranch в SVN — это копия в /branches/. Через свойство «svn copy» создавалась за константное время (lazy copy)
Всё ещё централизованноSVN — клиент-сервер. Без интернета не можешь commit, не можешь сделать log, не можешь сравнить с прошлой версией. Это унаследовано от CVS

SVN был очень популярен в 2000-2010-х. Apache Foundation, многие корпорации, Python project, Ruby on Rails — все использовали SVN. В России и СНГ SVN ещё до начала 2020-х был основной VCS в энтерпрайз-проектах (банки, госконторы), где переход на Git происходил медленно.

Но у SVN остался корневой недостаток CVS: всё крутится вокруг центрального сервера. Если у вас нет интернета — вы не можете сделать commit. Если сервер упал — никто из команды не может работать. Если вы за городом и хотите посмотреть, что изменилось два года назад — нужно скачать diff с сервера.

В то же время в начале 2000-х распределённая работа становилась нормой: open-source проекты разрастались до тысяч контрибьюторов в разных часовых поясах, у которых интернет не всегда стабильный. Назрел переход к распределённым VCS.


Распределённые VCS (2003-2005): революция

В 2003 году появилась Monotone — первая широко известная распределённая VCS (DVCS). В ней не было центрального сервера: каждый клиент имел полную копию репозитория, включая всю историю. Commit был локальной операцией. Обмен изменениями между разработчиками — через push/pull, peer-to-peer.

Monotone была экспериментом, не получила массового распространения. Но идею подхватили:

  • Mercurial (2005, Matt Mackall) — DVCS, написана на Python+C, простая в использовании
  • Bazaar (2005, Canonical) — DVCS от Canonical (которые делают Ubuntu)
  • Git (2005, Linus Torvalds) — DVCS, написана за 2 недели, без оглядки на удобство

Все три появились в 2005 году. Не случайно — это год, когда мир созрел к распределённой модели.


Почему Linus написал Git: BitKeeper drama

История появления Git — это технический детектив, который стоит знать каждому DE. Дело было так.

К 2002 году разработка ядра Linux была настолько масштабной, что CVS и Subversion не справлялись. Linus Torvalds выбрал коммерческую DVCS BitKeeper от компании BitMover. BitKeeper была отличной системой — DVCS, быстрая, надёжная — но коммерческой. Однако автор BitKeeper Larry McVoy сделал бесплатную лицензию для open-source проектов, и Linux kernel её использовал с 2002 по 2005 год.

Хронология BitKeeper drama, 2005
Апрель 2002Linux kernel переходит на BitKeeper с бесплатной лицензией для open-source. Linus доволен — DVCS работает, темп разработки растёт
Апрель 2005Andrew Tridgell (автор Samba и rsync) пытается реверс-инжинирить BitKeeper protocol для совместимости. Larry McVoy воспринимает это как нарушение лицензии и отзывает бесплатную лицензию для open-source
3 апреля 2005Linus объявляет: BitKeeper отзывает бесплатную лицензию через несколько месяцев. Linux kernel остаётся без VCS. Linus начинает писать собственную
6 апреля 2005Linus начинает писать Git. Через 3 дня — первый рабочий commit в Git коммит самого Git
29 апреля 2005Прошло 23 дня. Linux kernel переезжает с BitKeeper на Git. Git 0.99 работает. Дальше развивает community

За месяц Linus написал систему, которая через 10 лет вытеснит всех конкурентов. Как? Потому что у него был очень специфический набор требований:

  1. Скорость на больших репозиториях. Linux kernel — ~50 тысяч файлов, миллионы commits. CVS и SVN еле справлялись.
  2. Распределённая модель. Тысячи контрибьюторов в разных часовых поясах должны работать без центральной координации.
  3. Целостность данных. Никаких полу-применённых commit, никаких порчей файлов. SHA-1 хеши на каждом уровне.
  4. Branching должен быть дешёвым. В Linux каждая фича — отдельная ветка, и веток сотни одновременно.
  5. Простая модель данных. Сложные форматы хранения трудно дебажить. У Git — три типа объектов и всё.

Эти требования сформировали Git таким, какой он есть. Каждое странное решение Git — это ответ на одно из этих требований.


Что унаследовал Git, что отбросил

Подытожим. Git — это синтез трёх десятилетий опыта VCS:

Эволюция и что унаследовал Git
От SCCS/RCSИдея хранить версии. Но не дельтами, как в RCS, а snapshot-ами всего дерева (важное отличие)
От CVSАтомарный commit, объединяющий несколько файлов. Optimistic concurrency — никаких lock-ов
От SubversionТранзакционность, отслеживание renames. Глобальный счётчик ревизий — нет, Git использует SHA-1 хеши
От Monotone/MercurialDistributed модель: у каждого клиента полная копия. Commit — локальная операция
Новое в GitCheap branching (создание ветки = 41 байт). Content-addressable storage (SHA-1 = адрес). Snapshots, не дельты. Скорость

Особенности, унаследованные от SCCS/RCS: сама идея версионирования файлов.

От CVS: атомарный commit, охватывающий несколько файлов. Концепт «состояние проекта в целом».

От Subversion: транзакционность операций, отслеживание переименований, инструменты diff.

От Monotone/Mercurial: distributed-модель, peer-to-peer обмен.

Что Git изобрёл сам:

  • Content-addressable storage: каждый объект адресуется своим SHA-1 хешом. Из этого следует целостность, immutability, удобный merge.
  • Snapshots, не дельты: каждый commit — это полный снимок дерева, а не diff от предыдущего. Из этого — скорость операций.
  • Cheap branching: ветка — это просто файл с одной строкой (SHA-1 коммита). Создание ветки стоит наносекунды.

В следующем уроке разберём подробно, чем distributed-модель отличается от centralized, и почему это переломило индустрию.

Unix-философия: do one thing well

Попробуй сам

Если у вас уже установлен Git, попробуйте посмотреть на исторический commit Linus в репозитории самого Git:

mkdir -p ~/git-sandbox/lesson-01-history
cd ~/git-sandbox/lesson-01-history

git clone --depth 1 https://github.com/git/git.git
cd git
git log --reverse --format="%h %ad %s" --date=short | head -5

Если Git ещё не установлен, не страшно — поставим его в модуле 3. Пока просто читайте.


Проверка знанийKnowledge check
Почему Subversion, который во многом исправил недостатки CVS, в итоге проиграл Git?
ОтветAnswer
Потому что SVN исправил «локальные» проблемы CVS (атомарность, renames, branches), но сохранил центральную модель: всё крутится вокруг сервера. Без интернета вы не можете сделать commit, посмотреть историю, сравнить версии. В то же время мир разработки шёл в сторону распределённости: open-source проекты с тысячами контрибьюторов в разных часовых поясах, удалённая работа, нестабильный интернет. Git с distributed-моделью отвечал на этот запрос — каждый клиент полностью самодостаточен, commit локален, обмен изменениями явный (push/pull). К 2015 году большинство новых проектов уже выбирали Git, а к 2020 — это стало индустриальным стандартом.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. В чём принципиальное ограничение RCS (1982) по сравнению с CVS (1986)?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4