7.04. Azure Repos и TFS
Azure Repos и TFS
1. Общая архитектура
Azure DevOps — это целостная платформа поддержки жизненного цикла программного обеспечения, объединяющая инструменты управления проектами, контроля версий, непрерывной интеграции, тестирования и развертывания в единую среду. В отличие от набора разрозненных решений, Azure DevOps спроектирован как интегрированная система, в которой каждый компонент функционально связан с другими: задачи в Azure Boards могут быть привязаны к коммитам в Azure Repos, пул-реквесты могут запускать конвейеры в Azure Pipelines, а результаты тестов в Azure Test Plans влияют на принятие решений о слиянии кода.
Azure Repos является центральным элементом этой системы: именно здесь сосредоточена работа с исходным кодом, его хранением, изменением, проверкой и эволюцией. Репозиторий — база данных метаинформационной истории: каждое изменение, каждое решение о включении или отклонении кода, каждая попытка интеграции — всё это фиксируется, становится частью аудиторской цепочки и может быть восстановлено или проанализировано в будущем.
Azure Repos — это модуль Azure DevOps Services (облачная версия) или Azure DevOps Server (локальная установка, ранее известная как Team Foundation Server, TFS). Это означает, что доступ к репозиториям напрямую зависит от конфигурации проекта в коллекции проектов (Project Collection), а права на работу с кодом управляются через те же механизмы групп безопасности, что и права на работу с задачами или с конвейерами.
Архитектурно Azure Repos реализует две независимые, но функционально равноправные модели контроля версий: Git и Team Foundation Version Control (TFVC). Эти модели не являются альтернативами в рамках одного репозитория — каждая команда или проект выбирает одну из них при создании репозитория, и переключение между моделями в процессе эксплуатации невозможно без миграции. Различия между Git и TFVC гораздо глубже, чем просто синтаксис команд или интерфейс: они отражают принципиально разные философии организации совместной разработки, управления изменениями и построения истории кода.
2. Исторический контекст
Для понимания логики Azure Repos необходимо рассмотреть его эволюцию. Первоначально Microsoft предложила Team Foundation Server (TFS) как комплексное решение для управления разработкой ПО, ориентированное на корпоративные команды, которым требовалась строгая регламентация процессов, централизованное хранение артефактов и тесная интеграция с инструментарием Visual Studio. TFS включал в себя сервер приложений, базу данных (обычно Microsoft SQL Server), систему контроля версий (TFVC), модули отслеживания работ, сборки и отчетности.
Система TFVC, являвшаяся ядром управления версиями в TFS, была разработана как прямая альтернатива CVS и Subversion, но с упором на расширенные возможности корпоративного управления: блокировка файлов, обязательное обоснование изменений, шаблоны шельфов (shelving), политики ветвления и слияния, строгий контроль целостности истории. Это решение оправдывало себя в условиях крупных проектов с многоуровневой проверкой кода, длительными циклами релизов и высокими требованиями к аудиту.
Однако к середине 2010-х годов распределённые системы контроля версий, прежде всего Git, получили доминирующее распространение. Git предложил другую парадигму: локальная полная история репозитория, операции на уровне снимков, неизменяемые коммиты, гибкие стратегии ветвления и слияния. В ответ на эту тенденцию Microsoft интегрировала поддержку Git в TFS 2013, а затем, с запуском облачной версии под названием Visual Studio Team Services (VSTS), сделала Git основным, рекомендованным способом ведения контроля версий.
В 2018 году VSTS был переименован в Azure DevOps Services, а локальная версия — в Azure DevOps Server. Термин Azure Repos появился как брендированное название модуля управления версиями внутри Azure DevOps, подчеркивающее его облачную природу и открытость — репозитории Azure Repos полностью совместимы со стандартным Git-протоколом и могут взаимодействовать с любыми внешними Git-клиентами, хостингами и инструментами.
TFVC остался доступен в Azure DevOps Server и Azure DevOps Services для организаций, чей регламент, инфраструктура или критические процессы по-прежнему опираются на его уникальные возможности. Таким образом, Azure Repos представляет собой редкий случай, когда одна платформа параллельно поддерживает две радикально разные модели контроля версий, предоставляя выбор.
3. Концептуальные основы контроля версий
Прежде чем перейти к деталям реализации, необходимо чётко разграничить две фундаментальные модели, лежащие в основе TFVC и Git.
Централизованная модель (TFVC) предполагает наличие единственного авторитетного сервера, хранящего полную историю всех файлов. Клиентские машины получают рабочие копии — текущие состояния выбранных файлов или директорий — и отправляют на сервер только изменения (патчи). История существует только на сервере; локально разработчик не имеет доступа к предыдущим версиям, кроме как через запросы серверу. Операции типа «посмотреть разницу между ревизиями» или «восстановить файл к состоянию на месяц назад» требуют сетевого взаимодействия. Такая модель обеспечивает строгий контроль: сервер может применять политики до принятия изменений — например, требовать проверки кода, прохождения сборки или наличия связанной задачи.
Распределённая модель (Git) основана на идее того, что каждый участник обладает полной копией истории репозитория — всех коммитов, всех веток, всех меток. Локальный репозиторий — это самостоятельная база данных изменений. Операции с историей (сравнение, возврат, поиск по логу) выполняются мгновенно и автономно. Отправка (push) и получение (pull/fetch) изменений — это синхронизация между репозиториями, а не передача изменений на «главный» сервер. Сервер в Git (например, в Azure Repos) — это лишь соглашение о том, какой репозиторий считается каноническим для команды. Это даёт гибкость: разработчик может экспериментировать локально, создавать десятки временных веток, переписывать историю, не влияя ни на кого, пока не решит поделиться результатом.
Эти различия определяют всю остальную структуру — от организации рабочего процесса до подхода к ветвлению, от механизмов резервного копирования до требований к сетевой инфраструктуре.
4. Архитектурные различия
В TFVC история представляет собой журнал операций, выполненных над файловой системой: добавить файл X в ревизии 123, изменить строки 5–8 в файле Y в ревизии 145, переименовать файл Z в W в ревизии 189, откатить изменения в файле X, внесённые в ревизии 200. Каждая операция имеет уникальный идентификатор и фиксируется в порядке применения. При этом сама структура репозитория — это иерархия папок и файлов, и каждая операция относится к конкретному пути. Слияние в TFVC — это перенос отдельных изменений (changesets) из одной ветки (например, /Dev/FeatureA) в другую (/Main). При этом можно выбрать подмножество файлов из changeset для слияния — это даёт контроль, но требует вручную отслеживать незавершённые слияния.
Git, напротив, работает со состояниями (snapshots). Каждый коммит — это полная картина всего дерева файлов на момент коммита. Разница между коммитами вычисляется дельтой между этими состояниями. Переименование файла в Git — это не специальная операция, а следствие того, что в новом состоянии один файл исчез, а другой появился, и алгоритмы Git могут вывести факт переименования по схожести содержимого. Однако, строго говоря, Git восстанавливает её при анализе истории. Это делает историю более компактной и менее подверженной ошибкам при слиянии, но требует от разработчика осознания того, что переименования не являются атомарными событиями.
Следствием этого является и различие в представлении меток. В TFVC метка (label) — это именованная коллекция файлов с указанием их версий на момент создания метки. Один и тот же файл в разных метках может иметь разные ревизии. Это позволяет, например, зафиксировать «сборку 1.2.0», в которой часть компонентов обновлена, а часть — осталась на старой версии. В Git метка (tag) — это ссылка на конкретный коммит, а значит — на конкретное состояние всего репозитория. Метка в Git всегда ссылается на единую точку в истории, охватывающую все файлы. Это упрощает репродуцируемость сборок, но исключает возможность создания «гибридных» меток.
5. Рабочий процесс и инструментальная интеграция
В TFVC рабочий процесс начинается с получения рабочей копии через tf get. Если файл подлежит изменению, он должен быть заблокирован (tf checkout), чтобы предотвратить конфликтующие правки. После внесения изменений разработчик создаёт changeset, добавляя к нему описание, связанную задачу и, при необходимости, помещает изменения во временное хранилище (shelve set) для промежуточного обсуждения без фиксации. Отправка изменений (tf checkin) производится одномоментно: весь changeset или ничего. Сервер может применить политики: запустить сборку (Gated Check-in), потребовать код-ревью, проверить соответствие политике именования.
В Git рабочий процесс более гибкий: после клонирования (git clone) разработчик работает локально, совершая коммиты без сетевого взаимодействия. Ветвление — дешёвая операция, выполняемая за счёт создания новой ссылки на коммит. Слияние происходит через git merge или git rebase, с возможностью разрешения конфликтов локально. Отправка изменений (git push) производится только после того, как разработчик сам завершил локальную историю. Проверка кода, сборка и тестирование запускаются уже после отправки, в рамках пул-реквеста — на стороне сервера. Это означает, что в Git политики применяются после факта изменения, но до его объединения с целевой веткой.
Azure Repos предоставляет интерфейс для обоих подходов: для TFVC — через Team Explorer в Visual Studio, Azure DevOps Web UI и утилиту командной строки tf; для Git — через стандартные Git-клиенты, встроенные инструменты в VS/VS Code и REST API. При этом веб-интерфейс Azure DevOps унифицирует представление: как для Git, так и для TFVC доступны просмотр истории, сравнение версий, поиск по коду, навигация по изменениям. Однако внутренние механизмы, лежащие в основе этих представлений, различны.
6. Git в Azure Repos
Azure Repos реализует стандартный протокол Git без модификаций ядра. Это означает, что любой клиент, совместимый с Git версии 2.x и выше (включая официальные дистрибутивы для Windows, macOS, Linux; плагины для Visual Studio, Visual Studio Code, JetBrains IDE; инструменты вроде SourceTree или GitKraken), может подключаться к репозиторию Azure Repos по протоколам HTTPS или SSH. Все базовые операции — clone, fetch, pull, push, merge, rebase, cherry-pick, reset, reflog — работают идентично локальному Git-репозиторию.
Тем не менее, Azure Repos вносит надстроечные слои, не меняющие протокол, но расширяющие его поведение в облачной среде. Эти расширения реализованы на стороне сервера и активируются при взаимодействии с репозиторием через Azure DevOps Services или Azure DevOps Server. К ним относятся:
- Политики ветвления (Branch Policies) — механизмы принудительного контроля над процессом изменения кода в защищённых ветках. Они срабатывают при попытке
git pushв ветку, на которую наложена политика, и могут отклонить операцию до завершения. - Автоматические проверки (Build Validation, Status Checks) — интеграция с Azure Pipelines, при которой каждая попытка отправки в защищённую ветку или создание пул-реквеста к ней запускает конвейер сборки и тестирования; результат этого конвейера становится частью условия для разрешения слияния.
- Расширенная метаинформация коммитов — привязка к элементам работ (work items), упоминания пользователей, автоматические закрытия задач по ключевым словам (
#ID,fixes #ID). Эта информация не хранится в самом коммите Git (не в заголовке или теле), а ассоциируется с ним в базе данных Azure DevOps и отображается в веб-интерфейсе. - Глобальный поиск по коду (Code Search) — индексация содержимого репозиториев, поддерживающая семантический поиск по именам функций, классов, строк; поиск с учётом контекста, истории изменений, ссылок между репозиториями. Работает через отдельный механизм, независимый от
git grep. - Ограничения на размер файлов и репозитория — по умолчанию Azure Repos накладывает лимиты: файлы свыше 100 МБ требуют использования Git LFS (Large File Storage), а полный размер
.git-истории рекомендуется не превышать 10 ГБ (в противном случае производительность операцийclone,fetchдеградирует). Эти ограничения не являются частью протокола Git, но являются практическими мерами поддержания стабильности облачного хостинга.
Azure Repos обёртывает Git. Любой репозиторий, созданный в Azure Repos, можно клонировать локально и использовать независимо от Azure DevOps — например, перенести в GitHub или GitLab. Обратная совместимость обеспечивается за счёт строгого следования спецификации протокола.
7. Структура репозитория и управление пространством имён
В Azure DevOps пространство имён для репозиториев организовано на трёх уровнях:
- Организация (Organization) — высший уровень, определяющий домен URL (
https://dev.azure.com/{org}), политики безопасности по умолчанию, лицензирование, интеграции с Azure Active Directory. Организация может включать множество проектов. - Проект (Project) — логическая единица работы, объединяющая репозитории, доски задач, конвейеры, артефакты. Один проект может содержать до 1000 репозиториев (лимит по умолчанию, увеличивается по запросу). Проекты могут использовать разные шаблоны процессов (Agile, Scrum, CMMI), но это не влияет на репозитории напрямую.
- Репозиторий (Repository) — независимый Git-репозиторий, имеющий уникальное имя в пределах проекта. Имя репозитория становится частью URL (
https://dev.azure.com/{org}/{project}/_git/{repo}).
Иерархия гарантирует изоляцию: репозитории разных проектов не имеют прямого доступа друг к другу, даже если имена совпадают. Доступ к репозиторию управляется через группы безопасности на уровне проекта или отдельно для каждого репозитория. Можно назначить роли Reader, Contributor, Project Administrator — или создать кастомные группы с тонкой настройкой разрешений (например, разрешить коммиты только в ветки feature/*, но запретить push в main).
Каждый репозиторий имеет ровно одну ветку по умолчанию (default branch), которая назначается при создании (обычно main или master) и может быть изменена в настройках репозитория. Эта ветка играет роль канонической точки интеграции: пул-реквесты по умолчанию нацелены на неё, политики ветвления изначально применяются к ней, а статус сборки основного конвейера отображается именно для неё в интерфейсе.
8. Защищённые ветки и политики ветвления
Защита ветки — это ограничение на push, и комплексный механизм обеспечения целостности кодовой базы. Когда ветка (например, main, release/*, hotfix/*) помечается как защищённая (protected), все операции записи в неё (git push, git merge) должны пройти набор обязательных проверок. Эти проверки задаются в виде политик и включают:
- Требование пул-реквеста — прямой
pushв ветку невозможен. Любое изменение должно поступать через пул-реквест, даже от администраторов (если не снят флаг Allow bypassing policies). - Минимальное количество одобрений — указывается число уникальных рецензентов, чьи одобрения необходимы для завершения пул-реквеста. Можно задать автоматических рецензентов (например, «все изменения в
/src/database/должны одобрять члены группы DB Admins»). - Проверка сборки (Build Validation) — при создании или обновлении пул-реквеста автоматически запускается указанный конвейер Azure Pipelines. Пул-реквест может быть завершён, только если сборка завершилась успешно. Можно настроить несколько проверок (например, сборка + статический анализ + тесты безопасности).
- Требование включения связанных элементов работ — пул-реквест должен ссылаться хотя бы на одну задачу, ошибку или элемент пользовательского требования из Azure Boards. Это обеспечивает прослеживаемость изменений.
- Требование комментариев при отклонении — если рецензент отклоняет пул-реквест, система может потребовать ввести причину.
- Блокировка слияния при наличии конфликтов — даже если сборка прошла, слияние невозможно, пока не будут разрешены конфликты с целевой веткой.
Политики применяются каскадно: можно задать политики для шаблонов имён веток (например, refs/heads/release/*), и все новые ветки, соответствующие шаблону, унаследуют их. Это позволяет стандартизировать поведение веток релизов без ручной настройки каждой.
Политики проверяются сервером Azure DevOps до фактического выполнения git merge. Это означает, что даже если локально операция merge проходит без конфликтов, сервер может отклонить слияние из-за невыполненной политики (например, отсутствия одобрения). Такой подход гарантирует, что история в защищённой ветке всегда соответствует установленным требованиям.
9. Пул-реквесты
Пул-реквест (pull request, PR) в Azure Repos — это запрос на слияние, полноценный процесс совместной работы над изменением. Он существует независимо от состояния локальных веток и продолжает функционировать даже после git push --force, обновляя своё состояние автоматически.
Жизненный цикл пул-реквеста:
- Создание — инициируется через веб-интерфейс или команду
az repos pr create. Указываются исходная и целевая ветки, заголовок, описание, рецензенты, связанные элементы работ. - Обсуждение — рецензенты просматривают изменения построчно, оставляют комментарии, ставят вопросы, запрашивают исправления. Комментарии могут быть привязаны к конкретной строке кода и коммиту.
- Итерации — автор вносит дополнительные коммиты в исходную ветку; пул-реквест автоматически включает их в сравнение. Сборки перезапускаются, статус обновляется.
- Одобрение (approve) — рецензенты явно подтверждают готовность к слиянию. Одобрение может быть отозвано при появлении новых коммитов.
- Завершение (complete) — ответственный (обычно автор или лидер команды) инициирует финальное слияние. В этот момент:
- выполняется финальная проверка политик (сборка, одобрения и т.д.);
- создаётся коммит слияния (merge commit), который фиксирует факт интеграции (если используется стратегия
merge); - исходная ветка может быть автоматически удалена;
- связанные элементы работ получают обновления статуса (например, «в работе» → «решена»).
Azure Repos поддерживает три стратегии завершения пул-реквеста:
- Merge commit — создаётся отдельный коммит, родительские ссылки которого указывают и на последний коммит в целевой ветке, и на последний коммит в исходной. История остаётся нелинейной, но сохраняет информацию об интеграции.
- Squash merge — все коммиты из исходной ветки объединяются в один, который добавляется в целевую ветку как простой (не merge) коммит. История становится линейной, но теряется детализация промежуточных шагов.
- Rebase and fast-forward — коммиты из исходной ветки переносятся поверх целевой (как при
git rebase), а затем выполняется fast-forward-слияние. Требует, чтобы целевая ветка не изменилась после начала пул-реквеста.
Выбор стратегии зависит от принятого в команде стиля ведения истории: кому-то важна прослеживаемость каждого эксперимента, кому-то — читаемость линейного лога.
10. Форки
Форк (fork) в Azure Repos — это независимая копия репозитория, созданная в рамках той же организации или в личном пространстве пользователя. В отличие от клонирования, форк остаётся привязанным к исходному репозиторию (upstream) и предоставляет встроенные механизмы синхронизации и обратной интеграции.
Типичные сценарии использования форков:
- Участие внешних контрибьюторов — разработчик без прав записи в основной репозиторий создаёт форк, вносит изменения в нём, а затем отправляет пул-реквест из своего форка в основной репозиторий. Это стандартный workflow для open-source-проектов в Azure DevOps.
- Изоляция экспериментальных направлений — команда может создать форк для радикального рефакторинга, не рискуя стабильностью основной кодовой базы. В отличие от долгоживущей ветки, форк не «загрязняет» пространство имён основного репозитория.
- Конфиденциальные доработки — если часть кода требует отдельного режима доступа (например, приватный API-ключ), его можно разработать в форке с ограниченными правами, а затем интегрировать только те части, которые подлежат публикации.
Форк содержит полную историю оригинала на момент создания, включая все ветки и коммиты. После создания форк развивается независимо: новые коммиты в основном репозитории не попадают в форк автоматически. Для обновления форка используется функция Sync (в веб-интерфейсе) или ручной git fetch upstream && git merge upstream/main. При этом история форка и основного репозитория остаётся связанной: Azure DevOps корректно строит сравнение даже при расхождении истории.
Пул-реквест из форка в основной репозиторий ничем не отличается от обычного PR: к нему применяются те же политики, он проходит те же проверки. Единственное различие — в настройке прав доступа: администраторы основного репозитория должны разрешить внешние пул-реквесты (по умолчанию разрешены), и при первом PR из нового форка может потребоваться ручное подтверждение связи.
11. Механизмы отслеживания и аудита
Azure Repos ведёт расширенный журнал аудита для всех операций с репозиторием. Помимо стандартной Git-истории, фиксируется:
- Кто создал/удалил репозиторий;
- Кто изменил политики ветвления или настройки безопасности;
- Кто создал, обновил, завершил или отменил пул-реквест;
- Какие элементы работ были связаны с коммитами или пул-реквестами;
- Когда и кем были изменены файлы через веб-интерфейс (Web Edit);
- Попытки
pushс нарушением политик (отклонённые операции).
Эти данные доступны через веб-интерфейс (раздел Repository settings → Auditing), через REST API и могут быть экспортированы в Azure Monitor или внешние SIEM-системы. Это критически важно для организаций, подчиняющихся регуляторным требованиям (ISO 27001, SOC 2, ГОСТ Р ИСО/МЭК 27001), где требуется доказуемость целостности и прослеживаемость изменений.
12. Team Foundation Version Control
Team Foundation Version Control (TFVC) — это централизованная система управления версиями, разработанная Microsoft как ключевой компонент Team Foundation Server и, впоследствии, Azure DevOps Server/Services. В отличие от Git, TFVC не основана на распределённой модели и не совместима с протоколами, принятыми в open-source-сообществе. Это — закрытая, сервер-центричная архитектура, в которой клиент и сервер жёстко связаны через собственный протокол (на базе SOAP и REST в более поздних версиях), а рабочий процесс строится вокруг прямого взаимодействия с центральным репозиторием.
Основные компоненты TFVC:
- Сервер приложений Azure DevOps / TFS — обрабатывает запросы клиентов, управляет сессиями, применяет политики, координирует операции.
- База данных (Microsoft SQL Server) — хранит всю информацию: содержимое файлов (в сжатом виде), метаданные (имена, пути, права), журнал изменений (changesets), связи с элементами работ, настройки политик. Не существует «истории вне сервера» — даже при локальном редактировании без подключения к сети невозможно зафиксировать изменение.
- Клиентские инструменты — Team Explorer (интегрированный в Visual Studio), Team Explorer Everywhere (для Eclipse, IntelliJ и других IDE), утилита командной строки
tf(Team Foundation Command Line Client), веб-интерфейс Azure DevOps. Все они взаимодействуют с сервером по единому API.
Ключевое отличие архитектуры TFVC — отсутствие локальной истории. При выполнении команды tf get клиент получает рабочую копию — текущие версии выбранных файлов, но без метаинформации о предыдущих состояниях. Чтобы увидеть разницу между двумя версиями, выполнить сравнение или восстановить файл — требуется сетевое обращение к серверу. Это обеспечивает централизованный контроль, но повышает зависимость от доступности сервера и скорости сети.
13. Модель изменений
В TFVC базовой единицей изменения является changeset — атомарная, неизменяемая запись в журнале, содержащая:
- список файлов и их новых версий (или указание на удаление/переименование);
- метаданные: автор, дата и время, комментарий, связанные элементы работ (work items), метки (labels), политики, под которые подпадало изменение;
- идентификатор (например, Changeset 1452), присваиваемый сервером последовательно и глобально для всей коллекции проектов.
Changeset создаётся только при check-in — операции отправки изменений на сервер. До этого момента изменения остаются в локальной рабочей области (workspace) и могут быть отменены без следа. Важно: в TFVC невозможно сделать частичный check-in. Либо все застейдженные изменения попадают в один changeset, либо ни одно. Это гарантирует целостность логической единицы работы (например, «реализация функции X»), но требует от разработчика чёткого разделения задач до начала кодирования.
Сервер присваивает changeset уникальный номер, который становится постоянной ссылкой на состояние кодовой базы в точке времени check-in. В отличие от хешей Git, номера changeset линейны и последовательны — это упрощает навигацию для неспециалистов («соберите changeset 1452»), но не обеспечивает криптографической целостности: при восстановлении из резервной копии номера могут быть переназначены.
14. Рабочие области (Workspaces) и модели получения файлов
Рабочая область (workspace) — это клиентская концепция, определяющая сопоставление между путями на сервере и путями на локальной машине. Каждый пользователь может иметь множество рабочих областей, каждая из которых может охватывать разные подмножества репозитория.
Существует два типа рабочих областей:
- Серверные (Server workspaces) — метаданные о состоянии файлов (версия, статус — «не изменён», «в процессе изменения», «заблокирован») хранятся на сервере. Клиент при каждом взаимодействии (например,
tf status) запрашивает актуальное состояние. Это обеспечивает строгую синхронизацию и возможность блокировки файлов, но требует постоянной связи с сервером. - Локальные (Local workspaces) — введены в TFS 2012 для улучшения автономной работы. Метаданные хранятся локально (в скрытой папке
.tf), а изменения отслеживаются по времени изменения файлов (как в Git). Блокировки файлов недоступны, но проверка статуса работает без сети. Локальные рабочие области стали стандартом по умолчанию, однако серверные по-прежнему используются в сценариях, требующих эксклюзивного контроля.
В TFVC файлы по умолчанию находятся в состоянии read-only после получения (tf get). Чтобы начать редактирование, нужно выполнить tf checkout, что переводит файл в режим «изменяемый» и, при серверной рабочей области, может наложить блокировку (lock). Блокировка бывает двух типов:
- Check Out — No Lock — файл редактируется без блокировки; конфликты разрешаются при check-in (merge или overwrite).
- Check Out — Check In Lock — эксклюзивная блокировка: только один пользователь может редактировать файл одновременно. Это исключает конфликты, но снижает параллелизм и может привести к «застреванию» изменений, если разработчик забыл снять блокировку.
Выбор модели зависит от характера проекта: для бинарных файлов (изображения, документы Word), слияние которых невозможно, блокировка обязательна; для текстового кода — обычно не используется.
15. Shelving
Одна из наиболее мощных и уникальных функций TFVC — это shelving (шельфинг). Shelving позволяет сохранить текущие незавершённые изменения на сервере без создания changeset. Такой набор изменений называется shelveset (набор на полке).
Shelveset содержит:
- список изменённых, добавленных и удалённых файлов с их текущим содержимым;
- метаданные: имя автора, дата, комментарий, опционально — связь с элементами работ.
Shelveset не становится частью истории и не влияет на целостность основной ветки. Он существует как временный артефакт, доступный для:
- Код-ревью до завершения работы — разработчик может отправить shelveset коллегам для предварительного обсуждения, даже если функция ещё не протестирована.
- Переключения контекста — «положить на полку» текущую работу и начать срочное исправление, не теряя промежуточных изменений.
- Совместной отладки — передать коллеге точное состояние кода, включая незакоммиченные изменения.
- Резервного копирования «на лету» — защита от потери локальных правок при сбое машины.
Shelveset можно извлечь (tf unshelve) в любую рабочую область, в том числе другим пользователем. При извлечении изменения накладываются на текущее состояние рабочей области, и система помечает файлы как «в процессе изменения», готовые к check-in или дальнейшему редактированию.
Важно: shelveset не защищён от перезаписи. Если автор создаёт новый shelveset с тем же именем, предыдущий теряется. Поэтому рекомендуется использовать уникальные имена (например, users/timur/featureX-v2) или включать дату в название.
16. Ветвление и слияние
В отличие от Git, где ветка — это лёгкая ссылка на коммит, в TFVC ветвление реализуется как копирование поддерева директорий на сервере. Процесс называется branching by path.
Типичная структура репозитория TFVC:
$/
ProjectA/
Main/ ← основная линия разработки
Dev/ ← активная разработка
Release/1.0/ ← стабильная версия для поддержки
Release/2.0/ ← текущий релиз
Чтобы создать ветку, администратор выполняет tf branch $/ProjectA/Main $/ProjectA/Dev — это копирует всё содержимое Main в Dev на сервере, сохраняя ссылку на исходную точку (baseless branch если связи нет). Каждый файл в ветке сохраняет информацию о том, откуда он был скопирован, что позволяет серверу отслеживать историю слияний.
Слияние (tf merge) — это перенос изменений из одного пути в другой. Команда tf merge $/ProjectA/Dev $/ProjectA/Main анализирует changeset, применённые в Dev после последнего слияния, и создаёт локальные изменения в рабочей области Main. Разработчик разрешает конфликты, затем выполняет check-in — сервер фиксирует результат как новый changeset в целевой ветке.
Особенности:
- Слияние происходит на уровне файлов, а не репозитория целиком. Можно выбрать подмножество файлов для слияния — это даёт гибкость, но требует ручного контроля за тем, какие изменения уже интегрированы.
- Сервер ведёт журнал слияний (merge history), отслеживая, какие changeset перенесены между путями. При повторном слиянии учитываются только новые изменения.
- Возможны «бесосновные» слияния (baseless merge), когда связи между ветками нет — это рискованно и требует ручной верификации.
Эта модель хорошо подходит для сценариев с чёткой иерархией веток (Main → Dev → Feature) и длительными циклами поддержки (множество параллельных Release-веток), но менее эффективна при активном параллельном ветвлении (сотни feature-веток).
17. Политики check-in
TFVC реализует политики на этапе подготовки к check-in, а не после, как в Git. Это позволяет отклонить изменение до его попадания в историю.
Стандартные политики:
- Work Items — требует указания хотя бы одной связанной задачи.
- Builds — запускает сборку на агенте до check-in (Gated Check-in). Если сборка падает — changeset не создаётся.
- Code Review — интеграция с механизмом запросов на проверку в Azure DevOps; check-in возможен только после одобрения.
- Comment Requirement — требует непустого комментария.
- Custom Policies — разработчик может написать собственную политику на C# и развернуть её на сервере (требует админ-прав).
Gated Check-in особенно важен: он создаёт частный changeset, запускает сборку в изолированной среде, и только при успехе фиксирует изменения в основной линии. Если сборка падает, разработчик получает отчёт, но история остаётся нетронутой. Это гарантирует, что в Main никогда не попадёт неработоспособный код.
Для разработчиков, не желающих ждать сборки, доступен режим Shelved Changes for Gated Check-in — изменения отправляются на сервер как shelveset, сборка запускается асинхронно, а результат приходит по email. Это сохраняет производительность без потери контроля.
18. Интеграция с Visual Studio и Team Explorer
TFVC тесно интегрирован в Visual Studio через Team Explorer — панель инструментов, предоставляющую доступ ко всем функциям:
- просмотр и фильтрация истории changeset;
- сравнение версий файлов с подсветкой различий;
- аннотация (blame) — кто и когда изменил каждую строку;
- создание и управление рабочими областями;
- shelving и unshelving;
- визуальное ветвление и слияние с диаграммами зависимостей;
- прямое редактирование файлов в браузере (Web Access).
Team Explorer Everywhere (Tee) обеспечивает аналогичную функциональность для Java-разработчиков в Eclipse, IntelliJ IDEA и других IDE через плагин. Командная строка tf остаётся основным инструментом для автоматизации и CI/CD-сценариев.
Важно: TFVC не имеет встроенного механизма для работы вне экосистемы Microsoft. Хотя существуют сторонние клиенты (например, через плагины к TortoiseSVN), их функциональность ограничена, и они не поддерживают полный набор политик и интеграций.
19. Ограничения современного применения TFVC
Несмотря на мощные механизмы контроля, TFVC сталкивается с рядом вызовов в условиях современной разработки:
- Зависимость от сервера — автономная работа ограничена; командировки, проблемы с сетью, обновления сервера приводят к простою.
- Медленные операции с историей — просмотр лога по большому репозиторию или сравнение далёких changeset может занимать минуты.
- Сложность миграции — переход с TFVC на Git требует конвертации истории, которая может быть неполной (потеря информации о блокировках, shelve-sets, метках как гибридных наборов).
- Ограниченная поддержка community-инструментов — отсутствие интеграции с GitHub Actions, Dependabot, большинством линтеров вне экосистемы Azure.
- Рост сложности при увеличении масштаба — тысячи файлов, сотни пользователей, десятки веток ведут к замедлению операций и усложнению управления доступом.
Тем не менее, TFVC остаётся оправданным выбором в следующих сценариях:
- Проекты, регламентированные ГОСТами или внутренними стандартами, требующими строгого аудита и одобрения до фиксации;
- Команды, работающие с большим количеством бинарных артефактов (CAD-модели, видео, дизайн-макеты), где блокировка файлов критична;
- Организации с устоявшимися процессами, где стоимость миграции превышает выгоду от перехода;
- Системы, где интеграция с унаследованными инструментами (например, старыми версиями Visual Studio) является обязательным требованием.
20. Сравнительный анализ
Выбор между Git и TFVC в Azure Repos является решением, зависящим от совокупности факторов: характера разрабатываемого продукта, состава и распределения команды, требований к регулированию, инфраструктурных возможностей и стратегических планов организации. Ниже представлено детальное сравнение по основным измерениям.
Производительность и масштабируемость
Git демонстрирует высокую производительность при операциях с историей (лог, сравнение, поиск), поскольку они выполняются локально и опираются на сжатое представление объектов в .git/objects. Время клонирования растёт линейно с размером истории, но после первого клонирования все последующие операции (pull, diff, log) почти мгновенны. Однако при больших бинарных файлах (например, наборы тестовых данных, 3D-модели) история быстро раздувается, даже с использованием Git LFS. Azure Repos накладывает практические ограничения: рекомендуется не превышать 10 ГБ для .git-папки и 100 МБ на отдельный файл без LFS.
TFVC, напротив, хранит файлы в сжатом виде в SQL Server, и рабочая копия содержит только текущие версии — это экономит место на клиентских машинах. Операции get, status, checkin зависят от сетевой задержки и нагрузки на сервер базы данных. При большом числе одновременных пользователей (сотни+) и высокой частоте check-in производительность сервера TFS может деградировать, требуя горизонтального масштабирования (пулы серверов приложений, зеркалирование БД). В то же время работа с большими бинарными файлами — сильная сторона TFVC: блокировка, частичная загрузка, отсутствие необходимости в LFS.
Рабочий процесс и гибкость
Git предоставляет максимальную гибкость: разработчик может создавать десятки локальных веток, переписывать историю (rebase, commit --amend), экспериментировать без риска повлиять на других, а затем представить чистую, линейную историю через squash-merge. Это соответствует agile-подходам с короткими итерациями, частыми релизами и активным участием в open-source. Однако такая свобода требует дисциплины: неопытный разработчик может случайно push --force в общую ветку или потерять коммиты через reset --hard.
TFVC навязывает строгую последовательность: получить → заблокировать → изменить → проверить → зафиксировать. Это снижает когнитивную нагрузку на новичков и исключает классические ошибки Git, но ограничивает параллелизм. Ветвление — дорогостоящая операция (копирование на сервере), поэтому feature-ветки используются редко, а основная работа ведётся в общей Dev-ветке. Такой подход подходит для waterfall- и V-моделей, где изменения вносятся крупными блоками и проходят многоуровневую верификацию до включения в основную линию.
Безопасность и аудит
TFVC обеспечивает более глубокий контроль на этапе внесения изменений. Политики check-in (включая Gated Check-in) гарантируют, что в историю попадают только проверенные, собранные и одобренные изменения. Блокировка файлов исключает конфликты при работе с неделимыми артефактами. Журнал изменений — линейный, нумерованный, легко интерпретируемый не-разработчиками (аудиторами, менеджерами). Это критически важно для проектов в регулируемых отраслях: медицина, финансы, оборона, где требуется доказуемость «кто, когда, почему и после какой проверки внёс изменение».
Git полагается на постфактум-контроль: пул-реквесты, автоматические проверки, защищённые ветки. Но поскольку история может быть переписана (rebase, filter-branch), а коммиты создаются локально, существует теоретическая возможность внесения изменений без аудита (если отключить политики или использовать git push --force-with-lease). В реальных условиях Azure Repos минимизирует эти риски через политики и запрет forced push в защищённых ветках, но архитектурно «доверяй, но проверяй» остаётся основополагающим принципом.
Интеграция и экосистема
Git обладает беспрецедентной экосистемой: миллионы инструментов, ботов, хуков, CI/CD-систем (GitHub Actions, GitLab CI, Jenkins), линтеров, анализаторов безопасности (Snyk, SonarQube), автоматизации (Dependabot, Renovate). Azure Repos поддерживает большинство из них через стандартные webhook и REST API. Интеграция с GitHub Copilot, Advanced Security и другими облачными сервисами Microsoft реализована на уровне API, не зависящем от типа репозитория.
TFVC интегрирован главным образом в экосистему Microsoft: Visual Studio, Azure Pipelines (через tf-шаги), Power BI для отчётов по истории. Внешние инструменты либо отсутствуют, либо требуют написания кастомных адаптеров. Например, для статического анализа нужно запускать сканер после tf get, передавая ему локальную рабочую копию, тогда как в Git сканер может работать напрямую с историей через git show.
Обучаемость и поддержка
Git имеет крутую кривую обучения: понимание модели объектов (blob, tree, commit, tag), ссылок (HEAD, refs), операций (rebase vs merge, reset vs revert) требует времени. Ошибки могут быть катастрофическими (потеря истории), хотя средства восстановления (reflog, fsck) существуют. Документация обширна, но фрагментирована.
TFVC проще для старта: операции близки к привычной файловой системе («получить», «сохранить на сервер»). Интерфейс Team Explorer интуитивен для пользователей Visual Studio. Однако глубокое понимание shelving, типов рабочих областей, merge history и политик требует погружения в специфику TFS. Обучающих материалов меньше, многие знания передаются внутри организаций.
Резервное копирование и аварийное восстановление
В TFVC резервное копирование сводится к резервной копии базы данных SQL Server и конфигурационных файлов TFS/Azure DevOps Server. Восстановление — стандартная процедура SQL Server: точка во времени, полное восстановление. Это надёжно, но требует квалифицированного DBA.
В Git каждый клон — потенциальная резервная копия всей истории. Однако для корпоративного использования Azure Repos обеспечивает автоматическое реплицирование данных в географически распределённые дата-центры Microsoft Azure, что исключает необходимость вручную управлять бэкапами. Локальные клонированные репозитории не заменяют централизованное хранение — они не содержат политики, пул-реквесты, связи с задачами.
21. Рекомендации по выбору модели контроля версий
Решение должно основываться на объективной оценке требований проекта. Ниже — обобщённые рекомендации.
Выбирать Git (Azure Repos Git), если:
- Команда распределена географически или работает в гибридном/удалённом формате;
- Проект использует agile, DevOps, CI/CD с частыми релизами (раз в день и чаще);
- Разработка ведётся на кроссплатформенных языках (Python, JavaScript, Go, Rust) и инструментах, изначально ориентированных на Git;
- Требуется интеграция с open-source-сообществом, внешними контрибьюторами или публичными репозиториями;
- История кода должна быть неизменяемой и криптографически подтверждённой;
- Команда обладает навыками работы с распределёнными системами или готова их нарабатывать.
Выбирать TFVC, если:
- Проект регулируется стандартами, требующими строгого контроля до фиксации (например, ГОСТ Р ИСО/МЭК 12207, DO-178C, IEC 62304);
- Основная часть артефактов — бинарные файлы (CAD, видео, документация в формате .docx), где слияние невозможно и критична блокировка;
- Команда использует устаревшие или специализированные инструменты, не поддерживающие Git (например, старые версии MATLAB Simulink с TFS-плагином);
- Регламент требует линейной, легко читаемой истории изменений для аудиторов без технического бэкграунда;
- Существующая инфраструктура Azure DevOps Server уже настроена под TFVC, и стоимость миграции превышает долгосрочную выгоду.
Гибридный подход возможен, но с оговорками:
- Использовать Git для исходного кода и TFVC для бинарных артефактов (дизайн, документация, тестовые данные) — технически реализуемо, но усложняет процессы: две системы доступа, два набора политик, два инструмента для сборки.
- Поддерживать TFVC-репозиторий только для legacy-модулей, а новые — в Git — допустимо при чётком разделении границ ответственности.
22. Миграция с TFVC на Git
Миграция — организационная задача. Даже при безупречном переносе истории успех зависит от готовности команды изменить рабочие привычки.
Этапы миграции
-
Анализ и планирование
- Инвентаризация репозиториев: объём, структура веток, количество пользователей, политики.
- Определение стратегии: полная миграция истории vs. «точка отсечения» (оставить старое в TFVC, новое — в Git).
- Выбор инструмента миграции.
- Обучение команды основам Git и нового workflow.
-
Подготовка целевой среды
- Создание нового проекта или репозитория в Azure DevOps.
- Настройка политик ветвления, групп безопасности, шаблонов пул-реквестов.
- Интеграция с Azure Pipelines под новую модель сборки (YAML вместо классических конвейеров).
-
Миграция данных
- Запуск инструмента конвертации.
- Валидация: сравнение числа коммитов/changeset, контроль целостности файлов, проверка меток и веток.
- Устранение артефактов: «разрывы» истории из-за baseless merge, потеря информации о блокировках.
-
Параллельная эксплуатация и отсечка
- Запуск двух систем на ограниченный срок (например, 2 недели).
- Запрет новых changeset в TFVC, разрешение только для hotfix-исправлений.
- Полное отключение TFVC и архивирование сервера.
Инструменты миграции
- git-tfs — open-source утилита командной строки. Позволяет постепенно клонировать TFVC-ветки в локальный Git-репозиторий, сопоставлять пользователей, игнорировать бинарные файлы. Подходит для небольших репозиториев. Требует ручной настройки, не поддерживает shelvest-sets и сложные политики.
- Azure Repos Migration Tool (TFVC to Git) — официальный инструмент Microsoft (часть Azure DevOps Server Administration Console). Автоматизирует миграцию на уровне сервера, сохраняет связи с work items, корректно обрабатывает ветвление и слияние. Работает только при локальной установке Azure DevOps Server.
- Коммерческие решения (например, Polarion, OpsHub) — обеспечивают миграцию с сохранением расширенной метаинформации (shelvesets, политики, отчёты), но требуют лицензирования и консультационной поддержки.
Риски и ограничения
- Потеря информации: shelvest-sets, блокировки файлов, гибридные метки (labels с разными версиями файлов), комментарии к отдельным строкам в changeset не имеют эквивалента в Git и не переносятся.
- Искажение истории: при конвертации TFVC-веток в Git-ветки могут возникнуть «лишние» merge-коммиты или потеря линейности.
- Проблемы с кодировкой: TFVC хранит файлы в кодировке, заданной на сервере; при миграции в Git возможны искажения кириллицы, если не указан
core.autocrlfиcore.safecrlf. - Нарушение процессов: автоматические сборки, отчёты Power BI, скрипты на
tfперестанут работать и потребуют переписывания.
Перед миграцией рекомендуется провести пилотный проект — перенести один небольшой репозиторий, оценить трудозатраты и выявить проблемы.
23. Перспективы развития и долгосрочная поддержка
Microsoft официально поддерживает TFVC в Azure DevOps Server как минимум до 2029 года (2+ года после выхода последней версии). В Azure DevOps Services (облако) TFVC остаётся доступным без ограничений. Однако в дорожных картах развития новых функций (например, AI-помощь через Copilot, расширенная безопасность) приоритет отдаётся Git-репозиториям. Это отражает рыночную реальность: >95% новых проектов в Azure DevOps используют Git.
TFVC не будет удалён, но его развитие будет направлено на поддержку существующих корпоративных клиентов, а не на привлечение новых. Для организаций, только начинающих путь, выбор Git является стратегически обоснованным — он обеспечивает совместимость с будущими инструментами, рынком труда и open-source-экосистемой.