🐙 Bonus — gh CLI
Git seul ne sait rien de GitHub. Pour interagir avec ce qui
vit autour du repo (pull requests, issues, releases,
workflows Actions, secrets, codespaces), il faut soit cliquer
dans le navigateur, soit utiliser gh — le CLI
officiel GitHub. Une fois adopté, c'est l'outil qui supprime
le plus d'allers-retours navigateur de votre journée.
Ce module est volontairement exhaustif : il
couvre toutes les sous-commandes utiles, leurs options
critiques, les patterns d'automatisation (gh api,
gh + jq) et finit sur des workflows end-to-end
réels. Lisez-le une fois, gardez-le en référence.
~30
sous-commandes principales
100%
de l'API GitHub via gh api
10×
moins de clics navigateur
0
token à recopier (auth web)
❌ Mythe : "gh, c'est pour
scripter, donc compliqué."
🟢 Réalité : 80 % de l'usage tient sur
gh pr create, gh pr checkout,
gh pr view --web, gh run watch. Le
reste s'apprend au fur et à mesure.
Installation & authentification
Installer gh
$
$ brew install gh
$
$ sudo apt install gh
$
$ winget install --id GitHub.cli
$ gh --version
gh version 2.51.0 (2026-04-15)
Login — auth web (recommandé)
$ gh auth login
? What account do you want to log into? GitHub.com
? What is your preferred protocol for Git operations? HTTPS
? Authenticate Git with your GitHub credentials? Yes
? How would you like to authenticate GitHub CLI? Login with a web browser
! First copy your one-time code: A1B2-C3D4
Press Enter to open github.com in your browser...
$ gh auth status
github.com
✓ Logged in to github.com as julienmer (keyring)
✓ Git operations for github.com configured to use https protocol.
✓ Token: gho_*****
✓ Token scopes: gist, read:org, repo, workflow
Variantes utiles
$ gh auth login --with-token < mytoken.txt
$ gh auth login --hostname ghe.entreprise.com
$ gh auth refresh -s write:packages
$ gh auth token
$ gh auth switch
$ gh auth logout
✅
Multi-comptes (perso + pro) :
gh auth login
plusieurs fois,
gh auth switch pour basculer.
Pratique avec le
includeIf de
⚙️ .gitconfig magique.
Config & alias
$ gh config set git_protocol ssh
$ gh config set editor "code -w"
$ gh config set pager less
$ gh config set prompt enabled
$ gh config list
git_protocol: ssh
editor: code -w
pager: less
prompt: enabled
http_unix_socket:
browser:
Alias gh
$ gh alias set co 'pr checkout'
$ gh alias set prv 'pr view --web'
$ gh alias set prl 'pr list --author @me'
$ gh alias set ci 'run list --limit 5'
$ gh alias set bugs 'issue list --label bug --state open'
$ gh alias set --shell 'open-pr' 'gh pr view --web $(git branch --show-current)'
$ gh alias list
Repos
$ gh repo clone julienmerconsulting/clean-qa-academy
$ gh repo clone julienmerconsulting/clean-qa-academy -- --depth 1
$ gh repo create
$ gh repo create my-tool --public --source=. --push \
--description "CLI utility" \
--add-readme
$ gh repo fork org/projet --clone --remote
$ gh repo view julienmerconsulting/clean-qa-academy
$ gh repo view --web
$ gh repo list --limit 50
$ gh repo list myorg --visibility private
$ gh repo edit --description "new tagline" \
--add-topic qa --add-topic testing \
--default-branch main \
--visibility public
$ gh repo sync myuser/forked
$ gh repo set-default
$ gh repo archive owner/name
$ gh repo unarchive owner/name
$ gh repo delete owner/name --yes
⚠️ gh repo delete demande une confirmation interactive
par défaut. --yes bypass — utilisez avec extrême
prudence.
💎💎 Pull requests — le gros morceau
C'est l'usage principal de gh. Tout le cycle de
vie d'une PR — création, review, merge — peut se faire sans
quitter le terminal.
Créer une PR
$ gh pr create
$ gh pr create \
--title "feat(auth): OAuth refresh" \
--body "Closes #421. Implements token rotation." \
--base main \
--reviewer alice,bob \
--assignee @me \
--label backend,security \
--milestone "v2026.05"
$ gh pr create --title "…" --body-file ./PR_BODY.md
$ gh pr create --draft --title "WIP: auth refresh"
$ gh pr create --web
Lister, filtrer, voir
$ gh pr list
$ gh pr list --author @me
$ gh pr list --assignee @me --state open
$ gh pr list --label bug --label security
$ gh pr list --base develop --limit 50
$ gh pr view 421
$ gh pr view 421 --web
$ gh pr view
$ gh pr diff 421
$ gh pr diff 421 --name-only
$ gh pr status
Checkout de PR (le killer-feature)
$ gh pr checkout 421
$ gh pr checkout 421 --detach
$ git worktree add ../app-pr-421
$ cd ../app-pr-421 && gh pr checkout 421
Modifier une PR ouverte
$ gh pr edit 421 --title "feat(auth): OAuth refresh + rotation"
$ gh pr edit 421 --add-label backend --remove-label wip
$ gh pr edit 421 --add-reviewer charlie
$ gh pr edit 421 --milestone "v2026.05"
$ gh pr ready 421
$ gh pr ready 421 --undo
$ gh pr comment 421 --body "Updated, please re-review"
$ gh pr comment 421 --body-file ./reply.md
$ gh pr checks 421
$ gh pr checks 421 --watch
$ gh pr close 421
$ gh pr reopen 421
💎 Reviews depuis le terminal
$ gh pr review 421 --approve
$ gh pr review 421 --approve --body "LGTM, nice refactor 👍"
$ gh pr review 421 --request-changes \
--body "Race condition possible sur tokenRefresh, voir ligne 84"
$ gh pr review 421 --comment --body "Question sur l'init des scopes"
$ gh pr review 421 --request-changes --body-file ./review.md
💡 Pour des
line-comments précis (commenter une ligne
spécifique d'un diff), il faut passer par
gh api
(voir la section
gh api) ou par le
navigateur. Le CLI couvre la review globale, pas le commentaire
ligne par ligne.
Merge automatique
$ gh pr merge 421 --squash
$ gh pr merge 421 --rebase
$ gh pr merge 421 --merge
$ gh pr merge 421 --squash --delete-branch
$ gh pr merge 421 --squash \
--subject "feat(auth): OAuth refresh (#421)" \
--body "Closes #420. Adds token rotation."
$ gh pr merge 421 --auto --squash --delete-branch
$ gh pr merge 421 --disable-auto
✅ Pattern recommandé :
gh pr merge $PR --auto --squash --delete-branch
dès que la PR passe en review. La PR se merge toute seule
quand le dernier reviewer approuve et que la CI verdit.
Plus besoin de revenir surveiller.
Issues
Créer / éditer / fermer
$ gh issue create
$ gh issue create \
--title "OAuth refresh fails on token expiry" \
--body-file ./bug-report.md \
--label bug,backend \
--assignee @me \
--milestone "v2026.05"
$ gh issue edit 1234 --add-label priority:high
$ gh issue close 1234 --reason completed
$ gh issue close 1234 --reason not_planned
$ gh issue reopen 1234
Lister, voir, commenter
$ gh issue list
$ gh issue list --state all --label bug --limit 100
$ gh issue list --mention @me
$ gh issue list --milestone "v2026.05"
$ gh issue view 1234
$ gh issue view 1234 --comments
$ gh issue view 1234 --web
$ gh issue comment 1234 --body "Reproduit sur Safari iOS 18"
$ gh issue comment 1234 --body-file ./investigation.md
Branche depuis une issue
$ gh issue develop 1234 --checkout
$ gh issue develop 1234 --name fix/token-expiry --checkout
Transfert, pin, lock
$ gh issue transfer 1234 anotherorg/anotherrepo
$ gh issue pin 1234
$ gh issue unpin 1234
$ gh issue lock 1234 --reason off-topic
$ gh issue unlock 1234
Workflows & Actions
$ gh workflow list
NAME STATE ID
CI active 18234567
Deploy staging active 18234568
Release active 18234569
Lint disabled_manually 18234570
$ gh workflow view ci.yml
$ gh workflow view ci.yml --yaml
$ gh workflow run deploy.yml \
--ref main \
-f environment=staging \
-f dry_run=true
$ gh workflow disable ci.yml
$ gh workflow enable ci.yml
💎 Runs : suivi, debug, rerun
$ gh run list --limit 10
STATUS WORKFLOW EVENT BRANCH ELAPSED AGE
✓ CI push main 4m20s 2m ago
X CI pull_request feature/oauth 3m12s 8m ago
✓ Deploy workflow_run main 1m45s 11m ago
$ gh run list --workflow ci.yml --branch feature/oauth
$ gh run list --user @me --status failure
$ gh run view 12345678
$ gh run view 12345678 --log
$ gh run view 12345678 --log-failed
$ gh run view 12345678 --web
$ gh run watch
$ gh run watch 12345678 --exit-status
$ gh run rerun 12345678
$ gh run rerun 12345678 --failed
$ gh run rerun 12345678 --debug
$ gh run cancel 12345678
$ gh run download 12345678
$ gh run download 12345678 -n coverage-report -D ./reports/
✅ Combo killer pour CI :
gh pr create --fill && gh pr checks --watch.
Vous créez la PR (titre/body pré-remplis depuis les commits)
et vous attendez la fin de la CI dans le même terminal.
Releases
$ gh release create v2026.05.0
$ gh release create v2026.05.0 --generate-notes
$ gh release create v2026.05.0 \
--title "v2026.05.0 — OAuth refresh" \
--notes-file CHANGELOG.md \
--target main \
--prerelease \
./dist/app-macos.tar.gz \
./dist/app-linux.tar.gz \
./dist/app-windows.zip
$ gh release list --limit 20
$ gh release view v2026.05.0
$ gh release view --web v2026.05.0
$ gh release download v2026.05.0
$ gh release download v2026.05.0 --pattern '*macos*'
$ gh release upload v2026.05.0 ./extra-asset.zip
$ gh release delete v2026.05.0 --yes
$ gh release edit v2026.05.0 --prerelease=false --latest
Gists
$ gh gist create snippet.js
$ gh gist create snippet.js --public
$ gh gist create --filename note.md -
$ echo "# Hello" | gh gist create --filename hello.md --public
$ gh gist list
$ gh gist view <id>
$ gh gist edit <id> --filename snippet.js
$ gh gist clone <id> ./local-gist
$ gh gist delete <id>
Codespaces
$ gh codespace create
$ gh codespace create -R owner/repo -b feature/oauth \
-m standardLinux32gb
$ gh codespace list
$ gh codespace ssh
$ gh codespace ssh --codespace <name> -- "npm test"
$ gh codespace ports
$ gh codespace ports forward 3000:3000
$ gh codespace cp -r ./local-folder remote:/workspaces/repo/
$ gh codespace logs
$ gh codespace stop
$ gh codespace delete
Extensions
Les extensions gh sont des sous-commandes
installables qui étendent le CLI. Beaucoup sont des pépites.
$ gh extension list
$ gh extension browse
$ gh extension search "label"
$ gh extension install dlvhdr/gh-dash
$ gh extension install vilmibm/gh-screensaver
$ gh extension upgrade --all
$ gh extension remove gh-dash
Quelques extensions très utiles
| Extension |
Apport |
gh-dash |
Dashboard TUI pour suivre vos PR et issues en temps réel. |
gh-poi |
Nettoie en lot les branches locales déjà mergées. |
gh-copilot |
Suggestions de commandes par IA (gh copilot suggest). |
gh-graph |
Heatmap de contributions du terminal. |
gh-actions-importer |
Migration Jenkins/GitLab/Travis → GitHub Actions. |
Secrets & variables (Actions)
$ gh secret list
$ gh secret list --app dependabot
$ gh secret list --env production
$ echo -n "sk_live_..." | gh secret set STRIPE_KEY
$ gh secret set DEPLOY_KEY --body-file ./deploy_key.pem
$ gh secret set NPM_TOKEN --env production
$ gh secret set --org myorg INTERNAL_API_KEY --visibility selected \
--repos repo-a,repo-b
$ gh secret delete STRIPE_KEY
$ gh secret delete --env production NPM_TOKEN
$ gh variable list
$ gh variable set NODE_VERSION --body 20.11.1
$ gh variable delete NODE_VERSION
⚠️ Les secrets sont write-only via le CLI : impossible de les
relire. Si vous perdez la valeur, il faut la régénérer côté
provider.
Projects v2 (boards)
$ gh project list --owner julienmerconsulting
$ gh project view 4 --owner julienmerconsulting
$ gh project view 4 --owner julienmerconsulting --web
$ gh project item-add 4 --owner julienmerconsulting \
--url https://github.com/julienmerconsulting/clean-qa-academy/issues/123
$ gh project item-list 4 --owner julienmerconsulting --format json
$ gh project item-edit --id <item-id> --field-id <field-id> --text "Done"
💡 Pour des manipulations avancées de Projects v2, l'API
GraphQL via gh api graphql est souvent plus
efficace que les sous-commandes.
💎💎 gh api — la backdoor universelle
Quand le CLI ne couvre pas un endpoint, gh api
appelle n'importe quel endpoint REST ou GraphQL
de GitHub, en gérant l'auth, la pagination, les en-têtes, le
parsing JSON. C'est par lui que tous les scripts
maison passent.
REST de base
$ gh api /user
$ gh api /repos/julienmerconsulting/clean-qa-academy
$ gh api /repos/{owner}/{repo}/issues --paginate
$ gh api -X POST /repos/{owner}/{repo}/issues \
-f title="Bug" \
-f body="Steps to reproduce…" \
-F labels[]=bug -F labels[]=urgent
$ gh api -X GET /search/repositories \
-f q="language:python stars:>10000" \
--jq '.items[] | "\(.stargazers_count)\t\(.full_name)"'
GraphQL
$ gh api graphql -f query='
query($login:String!) {
user(login: $login) {
pullRequests(first: 5, states: OPEN) {
nodes { number title repository { nameWithOwner } }
}
}
}' -f login=julienmer
$ gh api graphql --paginate -f query='
query($endCursor: String) {
viewer {
repositories(first: 100, after: $endCursor) {
nodes { nameWithOwner }
pageInfo { hasNextPage endCursor }
}
}
}'
En-têtes & aperçus d'API
$ gh api -H "Accept: application/vnd.github.v3.raw" \
/repos/{owner}/{repo}/contents/README.md
$ gh api -i /user
$ gh api --include rate_limit
✅ Pourquoi gh api bat curl :
auth automatique, gestion native du {owner}/{repo},
pagination intégrée (--paginate), parsing
(--jq), et respect des limites de rate
automatiquement.
Search
Toute l'interface de recherche GitHub est exposée en CLI.
Pratique pour des inventaires ou des audits.
$ gh search repos "language:python qa testing" --limit 20
$ gh search code "setTimeout" --filename "*.test.js"
$ gh search prs --author @me --state open --review-requested @me
$ gh search issues --label good-first-issue --language rust
$ gh search commits "BREAKING CHANGE" --owner julienmerconsulting
Browse, status & cache
$ gh browse
$ gh browse src/auth.js
$ gh browse src/auth.js:42
$ gh browse src/auth.js --branch feature/oauth
$ gh status
$ gh cache list
$ gh cache delete <cache-id>
$ gh cache delete --all
💎 Combo gh + jq — scripts puissants
Toutes les commandes gh acceptent
--json <fields> et --jq <expr>.
Combinés, ils transforment gh en source de données
exploitable par n'importe quel script.
$ gh pr list --json number,title --jq '.[] | "\(.number)\t\(.title)"'
$ gh api --paginate /repos/{owner}/{repo}/commits \
-f since=$(date -u -d '30 days ago' +%FT%TZ) \
--jq '.[].author.login' | sort | uniq -c | sort -rn | head -10
$ gh pr list --json number,statusCheckRollup \
--jq '.[] | select(.statusCheckRollup[]?.conclusion == "FAILURE") | .number'
$ gh run list --limit 100 --json databaseId,status,createdAt \
--jq '.[] | select(.status == "failure") | .databaseId' \
| xargs -I{} gh run rerun {} --failed
$ gh pr list --json
Workflows end-to-end
1. Créer une feature, ouvrir la PR, attendre la CI
$ git switch -c feature/oauth
$ git push
$ gh pr create --fill --reviewer alice,bob
$ gh pr checks --watch
$ gh pr merge --auto --squash --delete-branch
2. Reviewer une PR sans toucher à votre feature en cours
$ git worktree add ../app-pr-421
$ cd ../app-pr-421 && gh pr checkout 421
$ npm install && npm test
$ gh pr review 421 --approve --body "LGTM, tested locally"
$ cd - && git worktree remove ../app-pr-421
3. Bisect une régression sur une PR
$ gh pr checkout 421
$ git bisect start
$ git bisect bad
$ git bisect good main
$ git bisect run npm test
$ gh pr comment 421 \
--body "Bisect : la régression vient de \`8b7e4f0\` (extract token helper)"
4. Release manuelle avec changelog auto
$ git tag -a v2026.05.0 -m "Release 2026.05"
$ git push origin v2026.05.0
$ gh release create v2026.05.0 \
--generate-notes \
--target main \
./dist/*.tar.gz
$ gh release view v2026.05.0 --web
5. Triage hebdo des issues "bug" non assignées
$ gh issue list --label bug --state open --assignee "" \
--json number,title,createdAt \
--jq '.[] | "#\(.number) — \(.title) [\(.createdAt[:10])]"'
6. Re-run automatique des CI flaky
$ gh run list --workflow ci.yml --branch main \
--limit 10 --json databaseId,status \
--jq '.[] | select(.status == "failure") | .databaseId' \
| head -3 | xargs -I{} gh run rerun {} --failed
Pièges classiques
-
Repo par défaut ambigu : dans un repo avec
plusieurs remotes (fork + upstream),
gh peut
cibler le mauvais. Solution :
gh repo set-default.
-
Token GH_TOKEN écrasé : si la variable d'env
GH_TOKEN est définie, elle a priorité sur
gh auth login. Vérifiez avec
gh auth status en cas de comportement bizarre.
-
Scopes manquants : certaines opérations
(workflows, packages) demandent des scopes additionnels.
gh auth refresh -s workflow,write:packages.
-
Rate limit silencieux :
gh api
sans --paginate peut renvoyer une page tronquée
sans warning. Pour les listes longues, toujours
--paginate.
-
Auto-merge bloqué : nécessite que la branch
protection rule autorise auto-merge dans les settings du
repo. Sinon
gh pr merge --auto échoue
silencieusement.
-
Codespaces : suppression définitive.
gh codespace delete supprime définitivement
(pas de poubelle). Pour juste suspendre, utilisez
gh codespace stop.
← Retour au catalogue de formations