🥐

さよならTFVC:Azure DevOpsでTFVCのバージョン管理が非推奨に

2024/10/31に公開

新規のAzure DevOpsプロジェクト作成時にバージョン管理方式としてTFVCが選べなくなる

Azure Reposでゼロべースでソースコード管理環境を構築する場合、TFVC vs Gitどっちがいいですか?最近はGitが主流だと思いますがTFVCを推奨しない理由は?というおたよりがあったので、ふと思い立って新規でTFVCのバージョン管理でAzure DevOpsの新規プロジェクトを作ってみようとしたら、TFVCが選べなくなってました。

Organization Settings > Repositoriesにいくと、TFVCベースのリポジトリ作成が無効になる設定がOnになってました。

同じようなことがAzure Pipelinesのクラシックパイプライン非推奨時にもあったので、
多分そういうアプデが合ったんだろうなと思ってリリースノートを見たら、2024年6月14日のアップデートで、上記のTFVCのレポジトリの作成を無効にする設定が追加されたようです。

https://learn.microsoft.com/ja-jp/azure/devops/release-notes/2024/sprint-240-update

近年、Git が Azure Repos の優先バージョン管理システムになったため、Team Foundation バージョン管理 (TFVC) に新機能は追加されていません。 セキュリティ、パフォーマンス、アクセシビリティに関する最近の改善はすべて Git リポジトリ専用に行われ、TFVC の使用が継続的に減少しています。 一部のユーザーはまだ TFVC に依存しており、この機能セットを削除する予定はありませんが、新しいプロジェクトや組織、および現在 TFVC を使用していないプロジェクトについては、TFVC を段階的に段階的に廃止する予定です。

ぱっと見た感じ、
「最近の主流はGitベースになったからTFVCもうあんま使ってる人いない、もうアプデもメンテもそんなするつもりないからAzure ReposでTFVCはもうやめとけ」
ってことだと思いました。

たしかに、去年提供された、コードベースのスキャン、シークレットスキャン、依存関係のリスクの検知が可能になるGitHub Advanced Security for Azure DevOps(GHAzDO)もGitでないと使えないので、うすうすもうGitベースReposにしかこういった最新のDevSecOps/DevOpsのプラクティスを実現できる機能は提供されないんだろうなという感じはしてました。

すでに作成されているTFVCリポジトリにはこの変更は適用されないようですが、段階的に廃止しされるということを鑑みると、どうしてもじゃない限り新規でリポジトリ作る際はもうGitベースの方がよさそうです。

そしていつの間にかAZ-400のラーニングパスからも、ソースコードのバージョン管理の「集中型ソース管理を理解する」「分散型ソース管理を理解する」のコンテンツがなくなってました。
https://learn.microsoft.com/ja-jp/training/paths/az-400-work-git-for-enterprise-devops/

TFVCでできてたことをGitベースのAzure Reposで実現/代替するには

とはいえ、TFVCのような集中型のソース管理にしかできなかったことや集中型ならではのメリットもあったかと思います。

ぱっと思いつくのはこんなところ。

  1. 単一のリポジトリサーバーを管理することで、管理作業がシンプルになり、バージョン管理プロセスが直感的でわかりやすい
  2. ディレクトリやファイルレベルでの細かなアクセス権限の設定や管理が可能
  3. 大規模なファイルを一元管理できる

1については確かにローカルブランチだのリモートブランチだのcommit/push/pull requestとかを覚えないといけないGitベースに比べると学習コストが少なくて済む、というのは確かにそうなので、それに関してはすいません慣れて下さい、ですが、2,3に関してはGitベースでやるとしたらこうなるかな?という代替案的なものを考えてみました。

Gitベースリポジトリでのコードベースの可視性の制御

  1. ディレクトリやファイルレベルでの細かなアクセス権限の設定や管理が可能

TFVCなどの集中型バージョン管理では特定のフォルダの配下を不可視にするといったアクセス制御ができました。こういったセキュリティ的な要件がある場合、TFVCが選択されていたかと思います。

確かにGitベースリポジトリだとリポジトリの中の特定のフォルダ配下のみを不可視に、といったことはできないので、Gitベースで特定のソースの可視性を制御するための代替案としては

(1)リポジトリを分割する
(2)Gitのサブモジュールやサブツリーを使う

になるかなと思います。

(1)リポジトリ分割

データの機密性に応じてリポジトリを分割し、アクセス権限をリポジトリ単位で管理することが一つの方法です。たとえば、公開が難しいフォルダを別のリポジトリに移し、必要なユーザーのみにアクセス権限を付与することで、TFVCのときに可能だった「ここだけはこのユーザーグループには見せたくない」というセキュリティ要件を達成することができます。

Azure Reposでは複数のリポジトリをホストすることができるので、Project Settings> Repositoriesでアクセスを制御したいリポジトリを選択して、Securityのタブを選択すると、該当のリポジトリのアクセス制御を設定することができます。

リポジトリを特定のユーザー/グループに対して不可視にしたい場合は、ここのSearch for users or groupでそのユーザー/グループを検索して、Readの設定をDenyにしてください。

単純に可視性だけをコントロールしたい場合は、これが最も手っ取り早いかなと思います。
フロントエンドとバックエンドがそれぞれ独立しているとか、マイクロサービスでサービスごとにリポジトリを切るという方針であればこれが最も簡単でアクセス制御の自由度も高いですが、

一方で、リポジトリが完全に分れてしまうため、独立したプロジェクト/サービスでない場合にこの方法でリポジトリ分割をすると統合の手間がとてもかかるというデメリットがあります。

個人的には、「プロジェクト/サービスがそもそも独立していない(させたくない/させるべきでない)のであれば、コードベースも分割すべきでない」
と思います。
理由としては、 コードベースの運用コストが上がる(統合のための手間が掛かる) こと、透明性の低下からくるコラボレーションのしにくさとアジリティの低下に繋がるからです。
プロジェクト/サービスとして独立していないのであればもうそれは一部分を不可視にするとかはしないでひとつのリポジトリとして管理したほうがよいと思います。

(2)Gitサブモジュール or サブツリー ※複雑なのであまりおすすめしない

一部のユーザーには全部見えてほしくない、でもソースの一元管理は必要という場合は、Gitサブモジュールかサブツリーを使うことになるかなと思います。

Gitリポジトリの「リポジトリに含まれるファイルはリポジトリにContributeするユーザーには全部見える」という性質上、見せたくないものがあるならリポジトリを分割する、というのは避けられません。

Gitサブモジュールやサブツリーを使用することで、リポジトリを分割しつつ、必要に応じてメインのリポジトリにサブモジュールやサブツリーとして組み込むことで、ソースの一元管理をしながらアクセス制御を実現できます。

- Gitサブモジュール:
1つのリポジトリの中に他のリポジトリを「リンク」として含める方法です。サブモジュールとして追加されたリポジトリは親リポジトリとは独立して管理され、特定のコミットやバージョンに固定することができます。

以下のコマンドで追加

# リポジトリBをサブモジュールとして追加
git submodule add https://example.com/path/to/repoB.git path/to/B

# リポジトリCをサブモジュールとして追加
git submodule add https://example.com/path/to/repoC.git path/to/C

例えば、共通のライブラリやツールが必要な場合、サブモジュールとしてそのリポジトリを追加し、更新の影響を最小限に抑えながら利用できます
サブモジュールはリンクされたリポジトリの「特定のコミット」に依存しているため、親リポジトリの更新や他のサブモジュールへの変更の影響を受けずに管理可能です。ただし、別途サブモジュールを更新する操作(git submodule updateなど)が必要です。

- Gitサブツリー:
他のリポジトリの内容を「統合」し、親リポジトリの一部として管理する方法です。サブツリーに含まれるリポジトリのコードは親リポジトリに直接マージされるため、更新も統合されます。
サブツリーは親リポジトリとサブリポジトリの間の変更を双方向で簡単に行いたい場合に便利です。たとえば、プロジェクトの一部として依存リポジトリを直接マージし、変更を簡単に取り込んだり、他のリポジトリに変更をプッシュすることが可能です。

以下のコマンドで追加

# リポジトリBをサブツリーとして追加
git remote add B_repo https://example.com/path/to/repoB.git
git subtree add --prefix=path/to/B B_repo main  # mainブランチを追加

たとえば、集中管理をするリポジトリAがあり、そのリポジトリAのサブモジュール/サブツリーとしてリポジトリB, CをAに追加します。
リポジトリA, B, Cのアクセス制御は以下のように構成します。

  • リポジトリA:特定の管理者や集中管理担当者のみがアクセスできるようにアクセス制御します。
  • リポジトリB、リポジトリC: リポジトリBやCには、それぞれ対応するチームやユーザーが直接アクセスできるように設定(リポジトリAの中身はB,Cのユーザーからは不可視)

これで疑似的なTFVCっぽい集中管理と一部のデータの不可視を実現できますが、リポジトリを分割しているということには変わりはないため、やはりこちらの手段も、これらのリポジトリがプロジェクト/サービスとして独立していないのであれば、とても運用が手間になるので、そうであればいっそのこともう単一リポジトリの方がよいかと思います。

さらに、プロジェクトやサービスとして独立しているのであれば、アクセス制御のしやすさや運用のしやすさという観点から、素直にリポジトリ分割のみを行うほうがよいと思います。

Gitリポジトリで共有のコードベースに対する意図しない変更からの防御

やっぱりGitだとセキュリティが心配ですという方はこちらのブランチ保護に関する記事をご覧ください。大事なブランチを保護するために提供されているAzure Reposのブランチロック、ブランチポリシーの設定について記載しています。
https://zenn.dev/yuriemori/articles/70668dae9fe080

さらに、Gitでしか使えないDevSevOpsのツールによるセキュリティ担保についてはこちらを
https://zenn.dev/yuriemori/articles/0d7ef5b16c9655

Gitベースリポジトリで大規模データを扱う

Gitベースリポジトリでも大規模なデータを扱うことは可能ですが、リポジトリのサイズが大きくなると、リポジトリの操作やクローン、プッシュなどの処理に時間がかかる問題が発生することがあります(リポジトリサイズが数GBとかになるとこの問題が顕著になる)。

リポジトリが大きくなる原因としては、主に以下の2つが原因として挙げられるので、これに対する対応が必要になります。

  • 長いコミット履歴
  • 大きなバイナリファイル

シャロークローンを使う

必要なコミットの履歴のみを取得してリポジトリをクローンすることができます。これによって、
リポジトリの全履歴を取得するのではなく、リポジトリの履歴を一部だけ取得し、リポジトリのサイズを最小限に抑えることができます。

git clone --depth 1 <cloneするリポジトリURL>

Git LFS(Large File Storage)を使う

Git LFSを利用すると、大容量ファイルの保存を効率化し、リポジトリのサイズを抑えながら、バイナリファイルのバージョン管理が可能になります。

https://learn.microsoft.com/ja-jp/training/modules/manage-git-repositories/2-work-large-repositories?ns-enrollment-type=learningpath&ns-enrollment-id=learn.wwl.az-400-work-git-for-enterprise-devops

.gitignoreファイルを使う

リポジトリのサイズを最小限に抑えるためには、コンパイル済みコードやその他のバイナリの依存関係や一時ファイルなどのリポジトリのサイズを大きくしがちなファイルを.gitignoreファイルで管理して、リポジトリにコミットしないようにします。
基本的に、リポジトリにコミットするのはソースコードのみにします。

※コンパイル済みコード/依存関係はビルドプロセスの中でパッケージングするようにしてください
https://learn.microsoft.com/ja-jp/azure/devops/repos/git/ignore-files?view=azure-devops&tabs=visual-studio-2022

Azure ReposのGitリポジトリで大きなファイルを管理する場合のプラクティスについての詳細は、こちらを参照してください。
https://learn.microsoft.com/ja-jp/azure/devops/repos/git/manage-large-files?view=azure-devops

GitベースのAzure Reposを使っていて、リポジトリサイズが大きくなったら課金が発生しますか?

No! Azure DevOps Serviceの料金プランを見てみると、一番安いプランのBasicでもAzure Reposに関しては 「無制限のプライベート Git リポジトリ」 とあり、Reposの容量が大きくなったからといって、追加のお金は掛からないようです。
その上のBasic+Test Plansのプランでも、「すべてのBasicプランの機能を含む」とあるので、Basic同様にReposのサイズによる課金はなさそうです。


https://azure.microsoft.com/ja-jp/pricing/details/devops/azure-devops-services/

ただし、じゃあX00GBもいけるかというと当然そうではなく、サイズ限界はあります。
Azure Reposのサイズは250 GB以下 にする必要があり、さらに最適なパフォーマンスのためには10GB未満にする必要があります。

https://learn.microsoft.com/ja-jp/azure/devops/repos/git/limits?view=azure-devops#repository-size

まとめ

というわけで、「Azure Reposでゼロべースでソースコード管理環境を構築する場合、TFVC vs Gitどっちがいいですか?最近はGitが主流だと思いますがTFVCを推奨しない理由は?」というおたよりの回答については、

  • TFVCのAzure Reposは今後段階的に廃止されるため、将来的にはメンテナンスやサポートが得られなくなるリスクがある
  • (完全に個人的見解)昨今のDevOpsやDevSecOpsのプラクティスやそれを実現するための機能(GHAzDO)はGitベースバージョンコントロールを前提としているので、コードベースを長くメンテしていく、DevOpsの実践を積極的に行う可能性があるのであれば、アクセスできるナレッジの量の違いという観点からGitベースの方がいいと思う

ので、「どうしてもっていう理由がないなら新規でAzure ReposでTFVCはやめたほうがいいです」という回答になります。

ここまで読んでAzure ReposをTFVCからGitに移行したくなった方はこちらをご覧ください。
https://learn.microsoft.com/ja-jp/azure/devops/repos/git/import-from-tfvc?view=azure-devops

Discussion