要約
- 記事管理の中心は
Qiita CLIで十分 - 10分で導入できるので、Qiita記事を継続的に管理したい人には導入をおすすめしたい
-
qiita pullで既存記事の取得が可能 -
publish --allとpublish <basename>は挙動が異なる
はじめに
Qiita 記事を Obsidian で管理していましたが、同期が面倒だったり、ブラウザとObsidianの行き来が面倒でした。
Qiita CLIの存在は知っていましたが、最初から導入する人は多くないと思います。しかし、記事が増えてきたり、AIで執筆することが多くなった今、ローカルやGitHubで執筆できる環境を整えることは、今後の作業量の削減につながると考え、重い腰をあげた次第です。
Qiita CLI の公式リポジトリはこちらです。
この記事では、実際に Qiita CLI で既存記事を pull し、ファイル名を整理し、GitHub Actions まで通して分かったことをまとめます。
ただ、これで記事を量産したいわけではなく、わたしが学んだことや気づきの共有をスムーズにすることが目的です。
この記事は、GitHub Actionsで動く、Qiita CLI経由でアップロードしています。
結論
-
qiita initでプロジェクトを作成 -
qiita loginでトークン発行、ローカルに保存 -
qiita pullで既存記事の取得 -
qiita new YYYY-MM-DD-topicで記事を新規作成 - GitHubにプッシュしてCI経由でアップロード
-
miseとjustで継続的な運用
qiita init で基本的なフォルダ構造、GitHub Actionsのワークフローまで作成されます。
qiita login ではトークンのペーストが求められます。登録した認証情報は、デフォルトでは ~/.config/qiita-cli/credentials.json に保存されます。
参考のため、リポジトリをPublicで置いてます。時間がない方はこのリポジトリをざっと見ていただければと思います。
Qiita CLI で管理する構成
今回のリポジトリは、現状だと次のような構成です。
.
├── .github/
│ └── workflows/
│ └── publish.yml
├── .gitignore
├── README.md
├── justfile
├── mise.toml
├── public/
│ ├── .remote/
│ ├── 2025-07-19-freezed-union.md
│ ├── 2025-07-24-discord-minutes-bot.md
│ ├── ...
│ └── 2026-06-07-qiita-github-integration.md
├── qiita.config.json
└── templates/
└── nekonata-qiita-template.md
ここで重要なのは public/ です。
Qiita CLI は public/ 配下の Markdown を記事として扱います。GitHub 連携時も、この public/ を含むリポジトリ全体を push します。
一方で、public/.remote/ は Qiita CLI の内部比較用データなので Git 管理しません。
frontmatter は必須
Qiita CLI は frontmatter 前提です。
例えば新規作成した記事は、次のような形式になります。
---
title: test
tags:
- ''
private: false
updated_at: ''
id: null
organization_url_name: null
slide: false
ignorePublish: false
---
# new article body
この中で運用上とても大事なのが id です。
- 新規記事の時点では
id: null - 初回 publish 後に Qiita 側の ID が入る
- 以後はこの
idで既存記事として追跡される
既存の記事の扱い
qiita pull というコマンドが用意されていて、既存の記事を落とすことができます。
qiita pull
既存記事がある状態では、まず pull してから整える方が自然です。
qiita pull すると、最初は Qiita の記事IDベースのファイル名で落ちてきます。
タイトルに絵文字がある場合は、Unicode エスケープされます。
title: "Flutterのスクリーンショットにデバイスフレームを合成するGo製ツールとCI/CDの話\U0001F431"
ファイル名自体は次のように記事IDベースで落ちてきます。
public/a301c5f545da1a99dd01.md
これをそのまま使ってもよいのですが、運用しづらいので今回は slug 形式に揃えました。
public/2025-08-31-fvm-to-mise.md
frontmatter の id を変えなければ、ファイル名は変えても問題ありませんでした。
画像の扱い
Qiita CLI 側に画像を直接管理する仕組みはなさそうです。
https://qiita.com/settings/uploading_images からアップロードして、発行されたURLを貼る運用の想定のようです。
以下のようにアップロードUIがあるので、選択かペーストで画像をアップロードします。
アップロード後は、Markdownの形式でコピーできます。
便利ですね。
publish の挙動は2種類ある
qiita publish --all
これは、差分がある記事だけを更新します。
実際に rename 後の状態で実行したところ、何も変更していなければ次のようになりました。
Nothing to publish
つまり、通常運用の本命は基本こちらです。
GitHub Actions で使っている increments/qiita-cli/actions/publish@v1 の中身も確認したところ、内部では qiita publish --all --root ... を実行していました。
qiita publish <basename>
これは、指定した記事を更新します。
差分がなくても Updated: ... になることがありました。
つまり、1本指定 publish は「差分確認用」ではなく、「この1本を更新する」コマンドとして扱った方がよさそうです。あまり出番はなさそうです。
Preview は編集画面ではない
qiita preview はブラウザ上の編集画面ではありません。
役割としては:
- 編集: ローカルエディタ
- 表示確認:
qiita preview - 投稿・更新:
qiita publish
という分担です。
Qiita Web のエディタのようにブラウザ上で本文を直接育てるというより、ローカル編集中心の運用になります。
タグ確認は API を使うと楽
タグ運用も、意外と先に整えておいた方が楽でした。
Qiita ではタグ表記に揺れがあるので、適当に付けるより既存タグを確認してから決めた方がよいです。
例えば:
GitHubActionsGitHub ActionsCICDCI/CD
のように、似た表記でも実際の使用状況は違います。
そこで、リポジトリ側にはタグ確認用の補助コマンドを追加しました。
just top-tags Flutter
just top-tags-pick
just tag-info GitHubActions
justfile の中身は次のようにしています。
top-tags pattern='':
#!/usr/bin/env sh
curl -fsSL 'https://qiita.com/api/v2/tags?page=1&per_page=100&sort=count' \
| jq -r '.[].id' \
| if [ -n "{{pattern}}" ]; then grep -i "{{pattern}}"; else cat; fi
top-tags-pick:
#!/usr/bin/env sh
curl -fsSL 'https://qiita.com/api/v2/tags?page=1&per_page=100&sort=count' \
| jq -r '.[].id' \
| fzf
tag-info tag:
#!/usr/bin/env sh
json=$(curl -fsSL "https://qiita.com/api/v2/tags/{{tag}}") || {
echo "{{tag}} not found"
exit 1
}
echo "$json" | jq -r '"\(.id) exists (items: \(.items_count), followers: \(.followers_count))"'
top-tags
top-tags は、Qiita API の GET /api/v2/tags?sort=count を使って、よく使われているタグを確認するためのコマンドです。
これは候補探索向きです。
ただし API の制約上、per_page は最大 100 です。なので top-tags 系は「人気タグの入口を見る」用途と割り切るのが自然でした。
tag-info
tag-info は GET /api/v2/tags/:tag_id を使って、特定タグの存在と件数を確認するコマンドです。
例えば:
just tag-info GitHubActions
実行すると、このように件数を確認できます。
GitHubActions exists (items: 4058, followers: 352)
- タグが存在するか
items_countfollowers_count
まで確認できます。
新規記事でタグを決めるときは、
-
top-tagsで候補を探す - マイナーなタグは
tag-infoで表記と件数を確認する
という流れがかなり使いやすいと感じました。
GitHub Actions 連携
CI の導線もかなり素直でした。
やることは次の通りです。
- GitHub リポジトリを作る
-
QIITA_TOKENを GitHub Actions secrets に登録する -
qiita initで生成された workflow を push する -
mainへの push で publish を確認する
実際、この構成で GitHub Actions は問題なく動作しました。
おまけ: mise と just
ここは私の好みなので、おまけとして書いておきます。
mise は、Node.js や CLI ツールなどの開発ツールとバージョンをプロジェクト単位で管理するためのツールです。
just は、プロジェクトごとのコマンドを justfile にまとめて実行しやすくするコマンドランナーです。
リポジトリでは、必要なツールの列挙は mise.toml、よく使う操作の入口は justfile に分けています。
例えば mise.toml に @qiita/qiita-cli や just を置いておけば、mise install で環境を戻せますし、別マシンでも簡単に復旧できます。また、バージョンも固定でき、どのツールのどのバージョンに依存しているか一目瞭然です。
また、qiita new や qiita publish --all のような操作を just 経由に寄せておくと、細かいコマンドを毎回思い出さなくて済みます。
mise にもタスク機能はありますが、ここでは使っていません。タスク実行は just の DSL の方がシンプルで、ツール管理とコマンド実行の責務を分ける方が分かりやすいと考えています。
最終的な運用フロー
今のところ、次のフローが一番扱いやすそうです。
既存記事を取り込むとき
qiita pull
必要なら slug 形式へ rename します。
新規記事を書くとき
qiita new YYYY-MM-DD-topic
その後に:
- 書きたいことをAIに渡して、テンプレートをベースに草案を書かせる
-
top-tagsやtag-infoでタグを確認する -
organization_url_name: nekonataを設定する -
qiita previewで画像、Callout、埋め込みリンクなどを確認 - GitHub にプッシュして反映
まとめ
Qiita と GitHub の連携は、Qiita CLI を使うと10分で構築できる。
今回の整理で特に大事だったのは次の3点でした。
- 既存記事は
pullで取り込む - 記事の同一性はファイル名ではなく frontmatter の
idで管理される - 通常の更新は
publish --allを使う
これで、既存記事の整理から新規記事作成、CI での publish まで、一通りの運用の形ができました。
今後は AGENTS.md の構築や Skills 導入、CI 強化による事故の削減や preview の簡易化、スマホからの執筆体験の向上など、まだ改善できそうです。
思ったより簡単だったので、まだ導入していない方は、この記事を AI に渡してセットアップのたたき台にしてみてください。

