gh-label-sync
December 13, 2025 ยท View on GitHub
A GitHub CLI extension for bulk label management and synchronization from YAML/JSON/CSV files.
No more 47 individual API calls! Declarative label management with multi-format support (YAML, JSON, CSV), intelligent diffing, and safe preview mode.
Features
๐ Multi-Format Support - YAML, JSON, and CSV label definitions
๐ Intelligent Sync - Smart diffing shows exactly what will change
๐ก๏ธ Safe Preview Mode - Dry-run before applying changes
๐ค Export Existing Labels - Extract current labels to any format
๐ Clone Between Repos - Quick label copying across repositories
๐ฏ Selective Updates - Fine-grained control with --force and --delete-unmanaged
Why This Extension?
Setting up labels in new repositories or syncing label changes across multiple repos is tedious with the GitHub web UI or requires writing custom scripts. This extension provides declarative label management with support for multiple file formats.
Installation
gh extension install scttfrdmn/gh-label-sync
Quick Start
# Export current labels to a file
gh label-sync export > .github/labels.yml
# Preview what would change
gh label-sync sync --file .github/labels.yml --dry-run
# Apply the changes
gh label-sync sync --file .github/labels.yml
# Copy labels from another repo
gh label-sync clone source/repo --repo target/repo
Commands
Sync Labels from File
gh label-sync sync --file .github/labels.yml
gh label-sync sync --file labels.json --repo owner/repo
gh label-sync sync --file labels.yml --dry-run
Flags:
--file/-f(required): Path to label definition file (YAML or JSON)--dry-run: Show what would change without applying--repo/-R: Target repository (default: current repo)--force: Update existing labels even if they differ (default: skip)--delete-unmanaged: Remove labels not in file (dangerous, default: false)
Export Labels
gh label-sync export > .github/labels.yml
gh label-sync export --format json > labels.json
gh label-sync export --repo source/repo | gh label-sync sync --file -
Flags:
--format: Output format (yaml[default] orjson)--repo/-R: Source repository
Clone Labels Between Repos
gh label-sync clone source/repo --repo target/repo
gh label-sync clone source/repo --repo target/repo --force
Quick way to copy all labels from one repository to another.
File Formats
YAML Format (Recommended)
# .github/labels.yml
labels:
- name: "bug"
color: "d73a4a"
description: "Something isn't working"
- name: "enhancement"
color: "a2eeef"
description: "New feature or request"
- name: "type: feature"
color: "1d76db"
description: "New feature implementation"
- name: "priority: critical"
color: "b60205"
description: "Needs immediate attention"
JSON Format
{
"labels": [
{
"name": "bug",
"color": "d73a4a",
"description": "Something isn't working"
},
{
"name": "enhancement",
"color": "a2eeef",
"description": "New feature or request"
}
]
}
CSV Format
name,color,description
bug,d73a4a,Something isn't working
enhancement,a2eeef,New feature or request
type: feature,1d76db,New feature implementation
Field Requirements:
name(required): Label namecolor(required): 6-character hex color (with or without#)description(optional): Label description
Behavior
Default Sync Behavior
- Create missing labels: Labels in file but not in repo โ create
- Skip differing labels: Labels exist but differ โ skip (unless
--force) - Keep unmanaged labels: Labels in repo but not in file โ keep (unless
--delete-unmanaged)
Example Output
$ gh label-sync sync --file .github/labels.yml
Analyzing labels...
โ bug - matches
โ enhancement - matches
+ type: feature - will create
+ type: bug - will create
~ priority: high - exists but differs (color: ff9800 โ fb8c00)
โ help wanted - exists but not in file
Summary:
2 labels match
2 labels to create
1 label to update (use --force to apply)
1 unmanaged label (use --delete-unmanaged to remove)
? Apply changes? (Y/n)
Use Cases
New Repository Setup
# Export labels from a template repository
gh label-sync export --repo myorg/template > .github/labels.yml
# Apply to new repository
cd new-project
gh label-sync sync --file .github/labels.yml
Organization-Wide Label Standards
# Define labels once
cat > org-labels.yml <<EOF
labels:
- name: "priority: critical"
color: "b60205"
description: "Needs immediate attention"
- name: "priority: high"
color: "d93f0b"
description: "High priority"
# ... more labels
EOF
# Apply to all repos
for repo in $(gh repo list myorg --json nameWithOwner -q '.[].nameWithOwner'); do
gh label-sync sync --file org-labels.yml --repo $repo --force
done
Copy Labels Between Repos
# Quick clone
gh label-sync clone source/repo --repo target/repo
# Or using export/sync
gh label-sync export --repo source/repo | \
gh label-sync sync --file - --repo target/repo
Development
Prerequisites
- Go 1.21 or later
- GitHub CLI (
gh) installed
Local Installation
git clone https://github.com/scttfrdmn/gh-label-sync.git
cd gh-label-sync
go build
gh extension install .
Testing
# Test the extension locally
gh label-sync export
# Run Go tests
go test ./...
Building
# Build for current platform
go build -o gh-label-sync
# Cross-compile for release (done automatically by GitHub Actions)
GOOS=linux GOARCH=amd64 go build -o gh-label-sync-linux-amd64
Architecture
gh-label-sync/
โโโ main.go # Entry point and CLI setup
โโโ cmd/ # Command implementations
โ โโโ sync.go
โ โโโ export.go
โ โโโ clone.go
โโโ pkg/
โ โโโ api/ # GitHub API client wrapper
โ โโโ parser/ # YAML/JSON/CSV parsing
โ โโโ diff/ # Label diff algorithm
โ โโโ format/ # Output formatting
โโโ .github/
โโโ workflows/
โโโ release.yml # Automated cross-platform builds
Release Process
- Update version in code
- Commit changes:
git commit -am "Release v1.0.0" - Create tag:
git tag v1.0.0 - Push tag:
git push --tags - GitHub Actions automatically builds cross-platform binaries and creates release
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Submit a pull request
License
MIT License - see LICENSE file for details
Related
- gh-milestone - Companion extension for milestone management
- GitHub CLI
- go-gh - Go library for building GitHub CLI extensions
Background
This extension was created because GitHub CLI maintainers decided not to include file-based label import in the core CLI, preferring users create extensions to avoid "format debates" between JSON, YAML, CSV, etc.
By being an extension, we can support all formats! ๐
The design is based on comprehensive real-world experience setting up GitHub projects.