🚯

Azure DevOpsでゴミブランチの乱立を防ぐための運用アイデア

2023/10/20に公開1

ゴミブランチの乱立

Azure DevOpsでgit flowでブランチを運用していますが、気が付いたらいらなくなったブランチでいっぱいになっていて困ってる、しかも消せない、、、(´;ω;`)というお悩みのご相談を最近多く頂いたので、Azure DevOpsでゴミブランチの乱立を防ぐための運用アイデアを置いておきます。

git flow

今回のご相談では、こんな感じのgit flowでAzure DevOpsのRepositoryでソースコードを運用しているとのことでした

main
├── hotfix
└── develop
    ├── feature/feature-name1
    ├── feature/feature-name2
    └── feature/feature-name3...

git flowでは寿命の長いブランチ(ここでいうとmain, hotfix, develop)と短命のブランチ(feature/...)を並存させて、機能開発は短命のfeatureブランチで行い、mergeされたら消す。という運用を想定しています。
https://learn.microsoft.com/ja-jp/azure/devops/repos/git/git-branching-guidance?view=azure-devops

このfeature/feature-name1,2,3...がどんどん溜まっていってゴミブランチの山ができてしまってどうしよう(´・ω・`)という風になる。

Azure DevOpsでのブランチ削除

Azure DevOpsでは、ブランチを削除する場合は単純に削除したいブランチを選択してこんな感じでDelete branchを選べば消せます。

もしくは、Pull RequestのこのCompleteボタンを押下したときに

こんな感じのダイアログが出てくるので、ここでDelete {branch_name} after merging. に✓を入れればmerge後にブランチが削除されます。

ブランチ削除の権限

しかし、このブランチの削除ができるのはAzure DevOpsではデフォルトではブランチ作成者のみです。
ブランチ削除のためには、Force push (rewrite history, delete branches and tags)の権限がAllowになっていることが必要です。

これは非常に強力な権限で、MSのAzDOのDocsでもデフォルトではどのセキュリティグループにも設定されていない、とあります。

https://learn.microsoft.com/ja-jp/azure/devops/organizations/security/default-git-permissions?bc=%2Fazure%2Fdevops%2Frepos%2Fbreadcrumb%2Ftoc.json&toc=%2Fazure%2Fdevops%2Frepos%2Ftoc.json&view=azure-devops

運用アイデア

これを踏まえると、ゴミブランチの乱立を防ぐためには、運用ルールとしてPR依頼した人(ブランチ作成者) がComplete時にDelete XXX branch after mergingにチェック入れる、というルールにするのが良いのかなと思いました。

GitHubだとブランチルールで簡単にできるのになんでAzure DevOpsだとダメなんだろ?ってなりましたが、ブランチの作成者がブランチのライフサイクルに責任を持て、という思想なのかな~と思いました。

もうブランチ作った人チームからいなくなっちゃたよ、、Reposがゴミブランチだらけだよ、、、(´;ω;`)という場合は、そのRepositoryで誰かに一時的にForce push~の権限を与えてその人をブランチ掃除人にして、一斉掃除をするしかないかなと思います。

Repos単位でブランチ削除の権限を誰かに割り当てる場合、Project Settings> Repos > Repositories > 掃除したいRepos > 掃除人にしたい人をsearch for users or groupで検索して追加 > 掃除人にしたい人にForce push-の権限をAllow、でいけます。

Referene

https://techblog.ap-com.co.jp/entry/2021/11/11/155158

Discussion

yutakaosadayutakaosada

10.21 Update. 手順をbashに統一
権限周りも記載されていて大変有益でした。
既にゴミブランチが溜まっちゃっている場合、下記の手順でいい感じにお掃除できると思ったので、この記事を見てる方向けにも共有させていただきます。

1.git bashでAzure Repos remote 全ブランチを出力

※既にゴミブランチが溜まっちゃった後のお掃除用に一覧化し削除対象の仕分けで利用する想定

bash
$ echo "ブランチ名,最終更新日,最終更新者" > currentBranches.csv
$ git for-each-ref --sort=committerdate refs/remotes/origin/ --format='%(refname:short)%09%(committerdate:short)%09%(committername)' >> currentBranches.csv

2.git bashでremoteのブランチを削除

[1]で出力した一覧を元に下記のコマンドを実行し一括削除🧹

bash
git push origin --delete [削除対象ブランチ名]

etc.PowerShellでAzure DevOps Rest API を利用して Azure Repos remote 全ブランチを出力するコマンドレット

※PATベースですので、各自必要に応じて発行ください。Pipelineに組み込んで自動削除とかもアリだと思いました。

powershell
powershell
# 環境設定
#$organization = "YOUR_ORGANIZATION"
#$project = "YOUR_PROJECT"
#$repository = "YOUR_REPOSITORY"
#$pat = "YOUR_PAT"

# ヘッダ設定
$headers = @{
    Authorization = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($pat)"))
}
# ブランチ情報の取得
$uri = "https://dev.azure.com/$organization/$project/_apis/git/repositories/$repository/refs?filter=heads&api-version=6.0"
$response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers

# 必要な情報を出力
$response.value | ForEach-Object {
    $branchName = $_.name -replace 'refs/heads/', ''
    $committer = $_.creator.displayName
    $commitDate = $_.creator.date

    [PSCustomObject]@{
        BranchName  = $branchName
        Committer  = $committer
        CommitDate = $commitDate
    }
#} | Format-Table
} | Export-Csv -Path 'branches.csv' -NoTypeInformation -Encoding UTF8

※誤って削除した場合について、公式に削除されたブランチにはアイテム保持ポリシーがありません。 削除された Git ブランチはいつ削除されたかに関係なく、いつでも復元できます。 と記載があることから復旧はできるものの、事故は防ぎたいですね。
https://learn.microsoft.com/ja-jp/azure/devops/repos/git/restore-deleted-branch?view=azure-devops