Когда Линус Торвальдс создавал Git, он проектировал распределенную систему для разработчиков ядра Linux, работающих на персональных компьютерах. Фундаментальная идея была простой: у каждого инженера на локальном жестком диске хранится полная копия репозитория, а синхронизация происходит короткими пачками изменений. Однако в современную эпоху гигантских корпоративных монорепозиториев и непрерывной работы кодинг-агентов, отправляющих сотни коммитов в минуту, архитектура Git начинает трещать по швам.
Организация надежного серверного хостинга Git превратилась в одну из самых дорогих и сложных задач системного администрирования. Проект Walgit, написанный на языке Rust инженером Роханом Годхой, реализует открытую версию архитектуры Continuity, разработанной компанией Cursor. Он показывает, как превратить обычное объектное хранилище (AWS S3, MinIO или Cloudflare R2) в полноценный бессерверный Git-сервер без баз данных, сетевых дисков и сложных кворумов.
Почему Git исторически сопротивлялся облаку
Чтобы понять смелость этой идеи, нужно вспомнить, как устроен внутренний формат хранения Git. Все коммиты, деревья каталогов и файлы сжимаются в так называемые pack-файлы. Они спроектированы так, чтобы занимать минимум места на диске. Но за экстремальную компактность приходится платить: чтобы прочитать один файл из коммита пятилетней давности, Git должен последовательно развернуть цепочку дельта-разниц (компрессионных правок), выполняя десятки мелких случайных чтений в разных частях диска.
На локальном NVMe-накопителе такие операции происходят за микросекунды. Но если положить репозиторий на сетевую файловую систему (NFS или CephFS) или подключить блочное хранилище через сеть, случайный поиск превращается в кошмар задержек. Каждый запрос заставляет головки виртуальных дисков метаться по сети, а серверы Git захлебываются в ожидании ввода-вывода.
Именно поэтому такие гиганты, как GitHub и GitLab, вынуждены были строить сверхсложные распределенные системы (GitHub Spokes или GitLab Gitaly/Praefect). В них задействованы сотни мощных серверов с локальными быстрыми дисками, трехфазные коммиты (3PC) для синхронизации реплик и отдельные реляционные базы данных, отслеживающие, на каком именно физическом сервере лежит тот или иной проект. Управлять таким стеком под силу лишь крупным инфраструктурным командам.
Continuity: когда S3 становится единственным источником правды
Компания Cursor, создающая популярный интеллектуальный редактор кода, столкнулась с этой проблемой лоб в лоб. Когда тысячи пользователей и ИИ-агентов одновременно редактируют код, серверы традиционного Git быстро выходят из строя под лавиной конкурирующих пушей. В поисках выхода инженеры разработали архитектуру Continuity, подробно описанную в их техническом манифесте «Git at any scale».
Главный тезис новой парадигмы радикален: серверы вообще не должны хранить постоянное состояние на локальных дисках. Единственным источником абсолютной правды объявляется объектное хранилище S3.
Вместо того чтобы непрерывно упаковывать и перепаковывать локальные pack-файлы, все входящие изменения сохраняются в виде журнала упреждающей записи (Write-Ahead Log, WAL). Любой сервер Walgit становится легкозаменяемым вычислительным узлом. Если виртуальная машина с сервером внезапно сгорает или перезагружается, данные не теряются: все зафиксированные коммиты уже лежат в надежном бакете, защищенном девятью девятками доступности облачного провайдера.
Журнал WAL, атомарный CAS и групповой коммит
Как обеспечить консистентность истории коммитов в среде, где нет центральной базы данных и лидеров кластера Raft? Секрет кроется в атомарной операции Compare-And-Swap (CAS), которую нативно поддерживают современные объектные хранилища через условную запись (условие заголовка If-Match по значению ETag или поколению объекта).

Под каждый репозиторий в бакете отводится простая структура каталогов:
log/<seq>.pb: упорядоченный журнал метаданных коммитов;wal/<checksum>.pack: неизменяемые бинарные паки с новыми объектами;manifest.pb: крошечный файл состояния, содержащий текущие указатели веток и ссылки на актуальные сегменты WAL.
Когда разработчик или агент выполняет команду git push, процесс укладывается в строгий протокол:
- Клиент передает новые объекты по стандартному протоколу Smart HTTP.
- Сервер Walgit проверяет целостность объектов и загружает pack-файл в бакет S3.
- Сервер готовит новую версию
manifest.pbи отправляет запрос на атомарную перезапись с условием: «принять запись, только если текущий ETag совпадает с прочитанным перед началом операции».
Если параллельно другой разработчик успел обновить манифест, операция отклоняется с ошибкой конфликта (HTTP 412). Сервер перечитывает свежее состояние, объединяет независимые изменения и повторяет попытку. Для высоконагруженных монорепозиториев в Walgit предусмотрен групповой коммит (Group Commit): несколько пушей, пришедших с интервалом в несколько миллисекунд, склеиваются в одну транзакцию, отправляя в S3 один общий манифест.
Клонирование без нагрузки: магия bundle-uri и Remote Reader
Вторая извечная беда Git-серверов — операция git clone. Когда десятки CI-агентов одновременно клонируют многогигабайтный монорепозиторий, процессор сервера раскаляется: демон Git вынужден на лету собирать и пережимать огромный pack-файл из разрозненных дельт.
Walgit обходит это узкое место с помощью встроенной поддержки спецификации Git bundle-uri. Сервер периодически формирует статические архивные срезы веток (Git bundles) и кладет их в S3. При попытке клонирования клиент получает не поток распакованных байтов от демона, а простую ссылку на статический файл в облаке или сети доставки контента (CDN). Загрузка 95% объема проекта происходит на предельной скорости канала напрямую из объектного хранилища, вообще не нагружая вычислительные ядра сервера.
А что делать, если монорепозиторий настолько огромен, что его полная копия просто не помещается на локальный диск сервера? На этот случай в Walgit реализован механизм Remote Reader. Сервер держит на диске лишь индексные файлы, а конкретные бинарные объекты читает по требованию прямо из S3 через частичные HTTP-запросы диапазона байтов (HTTP Range Requests).
Практический запуск и пределы бессерверного подхода
Walgit распространяется в виде единого бинарного файла на языке Rust. Для его запуска достаточно подготовить компактный файл конфигурации walgit.toml:
[server]
listen = "0.0.0.0:8080"
public_url = "https://git.internal.company.net"
auto_create_on_push = true
[server.auth]
mode = "token"
anonymous_read = false
tokens = [
{ principal = "ci-runner", token_env = "WALGIT_TOKEN_CI", write = true },
{ principal = "developer", token_env = "WALGIT_TOKEN_DEV", write = true }
]
[store]
backend = "s3"
bucket = "company-git-production"
[store.s3]
endpoint = "https://s3.eu-central-1.amazonaws.com"
region = "eu-central-1"
[placement]
# Локальный кэш используется исключительно для прогрева частых операций чтения
cache.mode = "disk"
cache.dir = "/var/cache/walgit"
После старта демона взаимодействие с сервером ничем не отличается от привычной работы с GitHub или GitLab. Клиент Git использует стандартные команды по протоколу HTTP:
# Запуск демона с экспортом токена аутентификации в окружение
export WALGIT_TOKEN_DEV=$(openssl rand -hex 24)
walgit serve --config walgit.toml &
# Инициализация локального проекта и первая фиксация изменений
git init my-service && cd my-service
echo "# Microservice Repository" > README.md
git add README.md
git commit -m "Initial commit"
# Пуш в создаваемый на лету репозиторий через Smart HTTP
git -c http.extraHeader="Authorization: Bearer $WALGIT_TOKEN_DEV" \
push https://git.internal.company.net/core/my-service.git main
# Быстрое клонирование репозитория с раздачей тяжелых данных через bundle-uri
git -c http.extraHeader="Authorization: Bearer $WALGIT_TOKEN_DEV" \
-c transfer.bundleURI=true \
clone https://git.internal.company.net/core/my-service.git
Конечно, бессерверный подход на базе S3 несет в себе понятные инженерные компромиссы. Задержка одиночного коммита неизбежно включает в себя сетевой путь до объектного хранилища (обычно 50–150 мс), что немного медленнее прямой записи на локальный NVMe. Кроме того, бакет требует периодического фонового обслуживания: фоновый воркер должен выполнять компактизацию накопившихся мелких паков в крупные и обновлять статические бандлы.
Тем не менее, Walgit доказывает: время громоздких и капризных кластеров хостинга кода подходит к концу. Перенос парадигмы Write-Ahead Log из мира реляционных баз данных в фундамент Git открывает дорогу к дешевой, отказоустойчивой и практически бесконечно масштабируемой инфраструктуре разработки.
