コンテンツにスキップ

a-Shellとobsidian-gitを使用してプライベートリポジトリで管理するMarkdownファイル(Mkdocs)をマルチデバイス(Windows/Mac/iPhone/iPad)で更新する方法

経緯

  • 技術系のTips記事(静的サイト)をMaterial for Mkdocs(以降MkDocsと表現する)で作成したドキュメント(Markdown)をGitHubで管理し、Netlifyでデプロイすることでwebサイトとして公開していた。
  • 個人の作業ログやメモはObsidianアプリを使用して管理していた。
  • データはWindows/Mac/iPhone/iPadで参照、更新するため、データの保存先(保管庫:Obsidian vault)はiCloudを指定して保存していた。
  • MkDocsはWebページとして生成されるが、materialテーマにより統一的なデザインで構成されるためスマートフォンやPCで見やすい。ただし、ドキュメント更新は主にPCでVSCodeから行う必要があった。
  • 文章量が多い場合はPCでも良いが、毎回起動するのは手間だと感じていた。そこで、スマートフォンでもドキュメントを更新する方法がないか検討していた。
  • 一例として、はてなブログでは、スマートフォン向けもアプリが公開されており、PC、スマートフォンで両方で更新可能な例も存在する。

仕様検討

要件

  • ドキュメント表示はMkDocs、更新はObsidian、または、VSCodeとする。
  • ドキュメント(コード)はGitで管理し、セキュリティを考慮してGitHubのプライベートリポジトリで管理する。
  • 費用はなるべく抑えたい。希望は無料で利用できること。

技術選定

  • Obsidianでは、ウェブサイト上に公開するサービスとしてObsidian Publishが提供されているが、月額制のサービスであるため対象から除いた。2

  • マルチデバイスで更新可能にするために保管庫はiCloudで設定することが前提になる。ローカル保管庫の変更を自動的に同期するサービス(リモートでも設定次第で可能)として、Obsidian Syncが提供されているが、こちらも有料の月額サービスであるため対象から除いた。3

  • ObsidianでGitを利用する方法として、Obsidian-Gitプラグインを利用することで、元データをgitのリポジトリの情報で設定できる。PCでは任意のローカルディレクトリを指定可能なので問題なし。iPhone,iPadの場合は、ファイル(ローカル)のobsidianフォルダ以下のみ対象であるため、ここにgit cloneする必要があるが、これはa-Shellアプリを使用すれば対応可能であった。4

設定方法

事前準備

  • GitHubのPAT(Fine-grained-token)> ContentsにRead and writeを付与する
  • Tokens (classic)の場合はrepo スコープを付与する

リポジトリのクローン

iPhone / iPadの向け
  1. a-Shellアプリをインストールし、gitコマンドをインストールする
  2. a-ShellアプリでpickFolderコマンドを実行してファイル > obsidianフォルダに移動する
  3. git cloneコマンドでプライベートリポジトリのURLを指定してクローンする
  4. passwordが表示されるため、PATを入力する
  5. obsidianアプリでクローンしたリポジトリをvaultに設定する
Windows / Macの向け
  1. リポジトリをクローンする(PATによる認証が要求された場合は入力する)
  2. obsidianアプリでクローンしたリポジトリをvaultに設定する

コミット&プッシュ

操作について以下でまとめています。

トラブルシューティング
  • push時にRemote did not reply using the "smart" HTTP protocol.となる場合はa-ShellアプリでPATを再設定する。
  • 設定してもうまくいかない場合はクローンからやり直す。

デプロイ環境構成

概要

本構成の設計方針は、プライベートリポジトリでセキュアかつコストをかけない運用の実現です。
そこで、ホスティングサービスとしてNetlifyを使用し、ドキュメント(コード)の生成とデプロイ処理はGitHub Actionsを使用する構成とします。

処理フロー
1
2
3
Git Push → GitHub Actions → Netlifyデプロイ → CDN
     ↓         ↓
   自動実行   ビルド完了
技術選定の理由
1. Netlify選択の背景
  • プライベートリポジトリ対応:Netlify無料プランでもプライベートリポジトリから静的サイトのホスティングが可能
  • GitHub Pagesとの比較:GitHub Pagesではプライベートリポジトリ利用に月額$4のGitHub Proが必要 1
  • 豊富な機能:CDN配信、自動SSL、カスタムドメイン、リダイレクト設定等が無料で利用可能
2. GitHub Actions採用の利点
  • セキュリティの向上:ソースコードはGitHub環境内でのみ処理され、Netlifyには静的ファイルのみ送信
  • コスト効率:プライベートリポジトリにおける、GitHub Actionsの利用では、GitHubの無料プランで月2,000分まで利用可能1
  • ビルド速度の改善:従来のNetlify単独方式と比較して処理時間が5-8分→3-5分に短縮
運用コスト
項目 従来方式(Netlify単独) 現在方式(GitHub Actions + Netlify)
GitHub 無料(無制限リポジトリ) 無料(Actions 2,000分/月)
Netlify ビルド分数:60分/月消費 ビルド分数:0分消費
月額コスト $0(無料枠内) $0(無料枠内、余裕率98%)
年間換算 $0 $0
セキュリティ設計
  • 最小権限アクセス:Netlifyにはデプロイ専用トークンのみを付与
  • ソースコード非公開:GitHub環境でビルドし、成果物のみをNetlifyへ送信
  • 認証情報管理:GitHub Secretsで一元的に管理
実装詳細

GitHub Actionsワークフローは下記の通りです。
このワークフローでは以下のパフォーマンス最適化を考慮しています。

  • 依存関係キャッシュ:Poetryおよびnpmパッケージのキャッシングにより高速化
  • 段階的デプロイ:エラー時の早期終了で無駄なリソース消費を防止
  • 自動通知:Discord連携によるデプロイ状況の即時通知
private-repo_build_mkdocs_deploy_netlify.yml
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
name: Build private repository code and deploy to Netlify

on:
  push:
    branches:
      - main
  workflow_dispatch:  # Allow manual trigger from the Actions tab

env:
  NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
  NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
  NETLIFY_SITE_URL: https://your-site-name.netlify.app  # Replace with your actual Netlify site URL

permissions:
  contents: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    outputs:
      deploy_url: ${{ steps.netlify-deploy.outputs.deploy_url }}

    steps:
      # Checkout source code
      - uses: actions/checkout@v4
        with:
          # Fetch full git history for accurate date information
          # Required by git-revision-date-localized-plugin during build
          # Without this, the plugin can't access file modification dates
          fetch-depth: 0

      # Set up Python environment
      - uses: actions/setup-python@v5
        with:
          python-version: 3.13

      # Cache Poetry dependencies and MkDocs build artifacts
      - name: Cache Poetry and MkDocs
        uses: actions/cache@v4
        with:
          path: |
            ~/.cache/pip
            ~/.cache/pypoetry
            ~/.virtualenvs
            .cache
          key: mkdocs-poetry-${{ runner.os }}-${{ hashFiles('poetry.lock') }}
          restore-keys: |
            mkdocs-poetry-${{ runner.os }}-

      # Install Poetry package manager (check if already installed)
      - name: Install Poetry
        run: |
          if ! command -v poetry &> /dev/null; then
            curl -sSL https://install.python-poetry.org | python3 -
          fi

      # Install project dependencies via Poetry
      # Excludes development dependencies for optimization
      - name: Poetry Setup
        run: poetry install --no-interaction --no-root --without=dev --sync

      # Build MkDocs static site
      - name: Build Documentation
        run: poetry run mkdocs build

      # Cache npm packages for Netlify CLI
      - name: Cache npm packages
        uses: actions/cache@v4
        with:
          path: ~/.npm
          key: npm-netlify-cli-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
          restore-keys: |
            npm-netlify-cli-${{ runner.os }}-

      # Install Netlify CLI (skip if already installed)
      - name: Install Netlify CLI
        run: |
          if ! command -v netlify &> /dev/null; then
            npm install -g netlify-cli
          fi

      # Deploy built site to Netlify production
      - name: Deploy to Netlify
        id: netlify-deploy
        run: |
          netlify deploy --dir=site --prod --message "Deploy from GitHub Actions"
          echo "deploy_url=$NETLIFY_SITE_URL" >> "$GITHUB_OUTPUT"
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

  # Send deployment notification to Discord
  send_notification:
    needs: [deploy]
    runs-on: ubuntu-latest
    # Skip notifications for Dependabot-initiated workflows
    if: github.actor != 'dependabot[bot]'
    steps:
      - name: Send Discord Notification
        env:
          DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
          WORKFLOW_ACTOR: ${{ github.actor }}
          DEPLOY_URL: ${{ needs.deploy.outputs.deploy_url }}
        run: |
          # Build workflow details URL
          workflow_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"

          # Set status emoji based on deployment result
          status="${{ contains(needs.deploy.result, 'failure') && 'FAILED ❌' || 'SUCCESS ✅' }}"

          # Prepare Discord message content
          message="## Deploy Completed
          ### Workflow Information
          • **Name:** ${{ github.workflow }}
          • **Status:** ${status}
          • **Run:** [View Details]($workflow_url)
          • **Actor:** ${WORKFLOW_ACTOR}
          • **Deploy URL:** ${DEPLOY_URL}"

          # Generate ISO 8601 timestamp
          timestamp="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"

          # Create Discord embed JSON payload
          # Color: red (16711680) for failure, green (65280) for success
          json_payload=$(jq -n \
            --arg title "${{ github.workflow }} - Deploy Status" \
            --arg description "$message" \
            --argjson color "${{ contains(needs.deploy.result, 'failure') && '16711680' || '65280' }}" \
            --arg timestamp "$timestamp" \
            '{
              "embeds": [
                {
                  "title": $title,
                  "description": $description,
                  "color": $color,
                  "timestamp": $timestamp
                }
              ]
            }')

          # Send notification to Discord webhook
          curl -X POST -H "Content-Type: application/json" \
            -d "$json_payload" \
            "$DISCORD_WEBHOOK_URL"

その他

obsidian gitプラグインを使ってみてドキュメント更新をした感想として、確かにスマホで更新できるのは楽だと感じた。ただ、文章が増えるとPCでの更新の方が楽だと感じた。今後しばらく運用するが、今後も継続する場合は、便利なプラグインやショートカットなどをうまく活用して、いかにスマホでも更新しやすい環境を作るかことがポイントになると考える。


  1. 2025年5月10日現在 

  2. 興味はあるので今後使用する可能性はある。調べると、tadashi-aikawaのPKMとして公開されているMinervaではObsidian Publishを使用して運用されている。使用する場合は内容が参考になるため共有させていただきます。 

  3. Obsidian Syncに記載の通り、機能も充実しているので利用価値は高いと言える。 

  4. gitコマンドのインストールが必要(インストール方法詳細

このページは役に立ちましたか?
フィードバックありがとうございます!