This final chapter puts everything together with real-world automation patterns, CI/CD integration, and productivity tips.

Full Feature Development Workflow

A complete workflow from issue to merged PR, entirely from the terminal:

# 1. Find or create the issue
gh issue create --title "Add dark mode" --label enhancement --assignee @me
 
# 2. Create a linked development branch
gh issue develop 42 --name feature/dark-mode --base main
 
# 3. Make changes, commit
# ... edit code ...
git add . && git commit -m "Implement dark mode"
 
# 4. Create the PR (auto-pushes the branch)
gh pr create --title "Add dark mode" --body "Closes #42" --reviewer teammate
 
# 5. Watch CI
gh pr checks --watch
 
# 6. Merge when ready
gh pr merge --squash --delete-branch
 
# 7. Verify the issue was closed
gh issue view 42 --json state --jq '.state'

Fork-Based Contribution Workflow

Contributing to an open source project:

# 1. Fork and clone in one step
gh repo fork upstream-org/project --clone
cd project
 
# 2. Create a feature branch
git checkout -b fix-typo
 
# 3. Make changes and commit
git add . && git commit -m "Fix typo in README"
 
# 4. Create the cross-fork PR
gh pr create --title "Fix typo in README" --body "Small typo fix"
 
# 5. Monitor CI checks
gh pr checks --watch
 
# 6. Respond to review feedback
git add . && git commit -m "Address review feedback"
git push
 
# 7. If the base branch has moved ahead
gh pr update-branch

Release Automation

Script a release process:

#!/bin/bash
set -e
 
VERSION=$1
if [ -z "$VERSION" ]; then
  echo "Usage: ./release.sh v1.2.3"
  exit 1
fi
 
# Ensure we're on main and up to date
git checkout main && git pull
 
# Tag
git tag "$VERSION"
git push origin "$VERSION"
 
# Build (hypothetical)
make build-all
 
# Create release with auto-generated notes
gh release create "$VERSION" \
  --title "$VERSION" \
  --generate-notes \
  ./dist/*
 
echo "Release $VERSION published!"
gh release view "$VERSION" --web

CI/CD Integration

Using gh in GitHub Actions

name: Auto-merge Dependabot PRs
on:
  pull_request:
    types: [opened, synchronize]
 
permissions:
  contents: write
  pull-requests: write
 
jobs:
  auto-merge:
    if: github.actor == 'dependabot[bot]'
    runs-on: ubuntu-latest
    steps:
      - name: Enable auto-merge
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh pr merge --auto --squash "${{ github.event.pull_request.number }}" -R "${{ github.repository }}"

Automated Issue Triage

name: Triage new issues
on:
  issues:
    types: [opened]
 
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - name: Add triage label
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh issue edit ${{ github.event.issue.number }} \
            --add-label "needs-triage" \
            -R "${{ github.repository }}"

Scheduled Stale Issue Cleanup

name: Close stale issues
on:
  schedule:
    - cron: '0 9 * * 1'  # Every Monday at 9am
 
jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Close old issues
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          gh issue list \
            --label "stale" \
            --state open \
            --json number \
            --jq '.[].number' \
            -R "${{ github.repository }}" | \
          xargs -I {} gh issue close {} \
            --comment "Closing as stale. Reopen if still relevant." \
            --reason "not planned" \
            -R "${{ github.repository }}"

GitHub Enterprise Server

All gh commands work with GitHub Enterprise Server (2.20+). There are several ways to configure it.

Authenticate with Enterprise

# Interactive login
gh auth login --hostname github.mycompany.com
 
# Token-based login (for CI/automation)
echo $MY_ENTERPRISE_TOKEN | gh auth login --hostname github.mycompany.com --with-token

Set a Default Host

# Environment variable (recommended for scripts)
export GH_HOST=github.mycompany.com
export GH_ENTERPRISE_TOKEN=ghp_xxxxx
 
# Now all commands target the enterprise instance
gh repo list my-org
gh issue list -R my-org/my-repo

Per-Command Host Override

gh repo list --hostname github.mycompany.com

Multiple Hosts

You can be authenticated to both github.com and an enterprise instance simultaneously. gh determines the host from:

  1. The --hostname flag (if provided)
  2. The GH_HOST environment variable
  3. The git remote of the current repository
  4. Default: github.com

Enterprise-Specific Considerations

  • Token scopes may differ on Enterprise. Verify with gh auth status --hostname github.mycompany.com
  • API endpoints are auto-prefixed: gh api repos/org/repo becomes https://github.mycompany.com/api/v3/repos/org/repo
  • Config is stored per-host in ~/.config/gh/hosts.yml

Productivity Tips

1. Set Up a Dashboard Alias

gh alias set --shell dashboard '
echo "=== My PRs ==="
gh search prs --author @me --state open --json repository,title,number --jq ".[] | \"  \(.repository.nameWithOwner)#\(.number) \(.title)\""
echo ""
echo "=== Review Requests ==="
gh search prs --review-requested @me --state open --json repository,title,number --jq ".[] | \"  \(.repository.nameWithOwner)#\(.number) \(.title)\""
echo ""
echo "=== My Issues ==="
gh search issues --assignee @me --state open --json repository,title,number --jq ".[] | \"  \(.repository.nameWithOwner)#\(.number) \(.title)\"" | head -10
'

2. Quick PR Review Cycle

gh alias set review 'pr checkout'
gh alias set approve 'pr review --approve'
gh alias set lgtm 'pr review --approve --body "LGTM!"'

3. Batch Operations

# Add a label to all open issues matching a search
gh search issues "memory leak" --repo myorg/myrepo --state open --json number --jq '.[].number' | \
  xargs -I {} gh issue edit {} --add-label "priority: high" -R myorg/myrepo
 
# Close all draft PRs older than 30 days
gh pr list --draft --json number,createdAt --jq \
  '[.[] | select((.createdAt | fromdateiso8601) < (now - 2592000))] | .[].number' | \
  xargs -I {} gh pr close {} --delete-branch

4. Sync Multiple Forks

#!/bin/bash
for repo in project1 project2 project3; do
  echo "Syncing $repo..."
  gh repo sync myuser/$repo --source upstream-org/$repo
done

5. Environment-Based Defaults

Add to your .bashrc / .zshrc:

# Default repo for personal projects
export GH_REPO="myuser/my-main-project"
 
# Preferred editor
export GH_EDITOR="code --wait"
 
# Better pager
export GH_PAGER="less -SRXF"
 
# Enable debug mode when needed
alias ghdebug="GH_DEBUG=api gh"

6. Dotfile Synchronization

Keep your gh config in your dotfiles:

# Symlink config
ln -sf ~/dotfiles/gh/config.yml ~/.config/gh/config.yml

This syncs your aliases, editor, protocol, and pager preferences across machines.

Complete Command Reference

CommandAliasPurpose
gh authAuthentication management
gh browseOpen pages in browser
gh codespacegh csCloud dev environments
gh gistCode snippet management
gh issueIssue management
gh orgOrganization management
gh prPull request management
gh projectProject board management
gh releaseRelease management
gh repoRepository management
gh aliasCommand shortcuts
gh apiRaw API requests
gh attestationArtifact verification
gh cacheActions cache management
gh completionShell completions
gh configCLI configuration
gh extensiongh extExtension management
gh gpg-keyGPG key management
gh labelLabel management
gh rulesetRuleset management
gh runActions run management
gh searchGitHub-wide search
gh secretSecret management
gh ssh-keySSH key management
gh statusActivity dashboard
gh variableVariable management
gh workflowActions workflow management

Where to Go from Here