2026/06/19(金)異なるGitリポジトリの履歴を連結する方法

投稿日:

あるリポジトリのファイルだけを抜いてきて新たにgit管理していたが、元々のリポジトリの履歴と繋げたくなったのでやった内容。

リベースやマージを経ないためコンフリクト解消が不要でお手軽。とにかく履歴さえくっつけばいい場合に向く。

確認環境

MSYS2上のGitで確認している

Env Ver
OS Windows 11 Pro
Gitの動作環境 msys2-x86_64-20260322
Git 2.53.0

前提

  • 元となったリポジトリをA、リポジトリAの履歴を捨てて新しく作ったリポジトリをBとする
  • どちらにもmainブランチしかないものとする

手順

  1. 事故が起きると面倒なため、まず作業用フォルダを作る
  2. リポジトリAをgit cloneする
  3. 最新のコミットハッシュを取得する
    git rev-parse HEAD
    
  4. この状態でリポジトリBをリモートリポジトリに追加する
    git remote add new リポジトリB
    
  5. リポジトリBを別ブランチにチェックアウトする
  6. チェックアウトしたブランチで最古のコミットハッシュを取得する。過去に連結歴のあるリポジトリでやると複数出るので注意
    git rev-list --max-parents=0 HEAD
    
  7. メインブランチに戻る
  8. 元となったリポジトリAに、新しいリポジトリBを繋ぎこむ。
    この時、リポジトリB側のコミットハッシュはすべて変更され、署名も消える
    git replace --graft リポジトリBの最古のコミットハッシュ リポジトリAの最新コミットハッシュ
    

一括でやるコマンド

上に書いたことをコマンドに落としただけのもの。動作確認はしていない。

$new_repo=/path/to/.git
BASE_END=$(git rev-parse HEAD)
git remote add dest $new_repo
git fetch new
git checkout -b new dest/main
NEW_START=$(git rev-list --max-parents=0 HEAD)
git replace --graft $NEW_START $BASE_END

あとがき

リベースもマージもgit mvも何もせず、異なるリポジトリを無理やり繋げたのにも拘らず、ファイル名の変更が繋がってるのが凄いと思った。

恐らくAとBで同じパスのファイルがあれば、それは同じものとして繋げてくれていると思うのだが、これは便利だ。

これによってリポジトリを分離する前の履歴が見れるようになり、過去の経緯が追えるようになったので助かった。

あとMSYS2のGitは非常にパフォーマンスが悪く重いので、こういう作業で使うと非常に遅かった。

2026/06/19(金)さくらのレンタルサーバーにCachetを設置したログ

ステータス管理画面のCachetをさくらのレンタルサーバーに設置したときのログ。

開発版の3.xを利用しているが、軽く叩いた感じはとりあえず使える気がする。

確認環境

確認時点でのさくらのレンタルサーバーではSQLiteでの動作は出来なかった。これはPHP拡張がJSONをサポートしていないからと思われる。

Env Ver
Cachet 3.x 2b0fc68988309647bdc0ba8e0b40862a3b8ddef4
cachethq/core 87be2387c06264c672dad94c87d00408bf34536d
PHP 8.3.31
MySQL 8.0

Cachetには正確なバージョン番号がなさそうなのでコミットハッシュを書いている。最新のハッシュのコードが入っていることを確認済。

またCachet 3.xの中身は事実上からっぽで、vendor/配下にあるcachethq/coreが本体なので、そちらのバージョンも併記している。

手順

以下のコマンドはすべてzshで実行しているため、さくら標準のcshでは動かない箇所があるかもしれない。

  1. composerがなかったのでcomposerを入れた。ここから先は~/bin/にPATHが通っていることを前提で進める

    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    php -r "if (hash_file('sha384', 'composer-setup.php') === 'c8b085408188070d5f52bcfe4ecfbee5f727afa458b2573b8eaaf77b3419b0bf2768dc67c86944da1544f06fa544fd47') { echo 'Installer verified'.PHP_EOL; } else { echo 'Installer corrupt'.PHP_EOL; unlink('composer-setup.php'); exit(1); }"
    php composer-setup.php
    php -r "unlink('composer-setup.php');"
    
    mkdir ~/bin
    mv composer.phar ~/bin/composer
    
  2. Cacheの取得と設置

    git clone -b 3.x https://github.com/cachethq/cachet.git
    cd cachet
    
    composer install --no-dev -o
    # composerでエラーが出てupdateしろといわれたためupdate、これでインストールまでしてくれる
    composer update
    # 本体のアップデート
    composer update cachethq/core
    # 環境変数の編集
    cp .env.example .env
    
  3. .envの編集
    デフォルトでAPP_DEBUGがtrueなのでfalseにした方が良い。まだ開発版のためかTIMEZONEを設定してもトップ画面には反映されない。管理画面の一部では反映される。

    APP_DEBUG=false
    APP_TIMEZONE="Asia/Tokyo"
    APP_URL=https://status.example.com
    DB_CONNECTION=mysql
    DB_HOST=DBホスト
    DB_PORT=3306
    DB_DATABASE=データベース名
    DB_USERNAME=データベース名
    DB_PASSWORD=パスワード
    
  4. Cachetのセットアップ

    php artisan key:generate
    
    php artisan vendor:publish --tag=cachet
    php artisan migrate
    
    # envを閲覧不能にする
    cat <<'EOF' | tee .htaccess
    <Files .env>
    deny from all
    </Files>
    EOF
    
    # 403になることを確認
    curl https://status.example.com/.env
    
    php artisan cachet:make:user
    
  5. crontの設定。ステータスページ表示する機能しかないのにやる意味があるのかは謎。
    *   *   *   *   *   php /home/<username>/www/path/to/artisan schedule:run >> /dev/null 2>&1
    
  6. さくらのコンパネからドメインを開き、Web公開フォルダーをpath/to/cachet/publicにする。

備考

Cachet v3.x is currently in development and not yet released. The following instructions are intended for development purposes only and are subject to change.

現時点では上記のようにあり、開発版なのでバグはあると思われる。

トラブルシューティング

Illuminate\Database\QueryExceptionが出る

SQLiteを使っていて次のようなエラーが出る場合、MySQLに変えると直る。恐らくさくらのレンサバに入ってるSQLite拡張がjson_eachをサポートしてないのが原因。

!Illuminate\Database\QueryException

Internal Server Error


SQLSTATE[HY000]: General error: 1 no such table: json_each (Connection: sqlite, SQL: select *
from "webhook_subscriptions" where ("send_all_events" = 1 or exists (select 1 from
json_each("selected_events") where "json_each"."value" is component_updated)))

Expand vendor frames

app/Http/Middleware/TrustProxies.php :32

あとがき

ステータスページを作る以上の機能が中区、外形監視はしてくれなかった

外形監視をして、その結果をステータスに表示してくれるツールだと思っていたら、ステータスの設定を行う機能と、それを表示する機能しかなかった。

つまり手動でメンテナンス中とか出したり、外形監視からAPIを蹴って何か表示するのには使えるが、このツールにはそれ以上の機能はないようだ。

これはダッシュボードを作る画面とAPIを提供してくれるツールということだ。

親切だったユーザー作成ウィザード

install.phpにアクセスして設定を書き換えるみたいな、一瞬ではあるものの脆弱な瞬間がないのは便利だと思った。

簡単なものなら自作できそう

Cachetは画面操作によってステータスを変えたり、履歴を出したりできるが、curlを投げて落ちてたら画面に表示くらいならパパっと作れそうだなと思った。

とはいえ、画面のリッチさや、APIからも操作できることなどを考えると、そんなのを作るのも大変なので、Cachetのようなツールを使った方が楽なのは間違いない。

ほぼ自分しか使ってないサーバーのためにこんなリッチなものが必要なのか…?

まぁあった方が豪華だし…みたいな…。

保守やオペのコストの方が高いので結局使わずじまいになる可能性も無きにしも非ずではある。

2026/06/18(木)Forgejoをv11からv15に上げる

Forgejo v11のエディタがスマホから扱いづらいのでv15に上げて扱いやすくするのが目的。

この作業で解決する問題

Forgejo v11ではAndroid Edgeでエディタ上をロングタップするとJSでカスタマイズされたメニューが出てしまい、全選択や全選択→切り取りみたいなコンボができない問題があった。

Forgejo v15に上げることで、ブラウザ標準のコンテキストメニューが表示されるようになった。但し全選択→切り取りは上手くいかず、ファイル先頭を選択しそこから末尾までドラッグした上で切り取る必要があった。とはいえ、ほとんど全く操作できなかったところから操作できるようになっただけでも十分だ。

個人的にスマホでコードを触る場合、ほとんどは小規模な編集なので、いったんはこれでも事足りる。

参考までに、この変更はForgejo v14で行われていた。

前提条件

  • DBはSQLite
  • Forgejo 11.0.15+gitea-1.22.0から15.0.3へのアップグレード

手順

基本的にはアップグレードガイドを読みながらやる。

# v15の取得
wget https://codeberg.org/forgejo/forgejo/releases/download/v15.0.3/forgejo-15.0.3-linux-amd64

# バックアップの作成
sudo -u git /usr/local/bin/forgejo \
 --config /etc/forgejo/app.ini \
 dump --file /home/git/forgejo.zip

# ジョブキューを吐き出す
sudo -u git /usr/local/bin/forgejo \
 --config /etc/forgejo/app.ini \
 manager flush-queues

# サービスを止める
sudo systemctl stop forgejo.service
# バイナリを上書き
sudo cp forgejo-11.0.15-linux-amd64 /usr/local/bin/forgejo
sudo chmod 755 /usr/local/bin/forgejo
# サービスを再開
sudo systemctl start forgejo

あとがき

特に何事もなく移行でき、バックアップファイルも使うことがなかったので良かった。

UI全体としてもブラッシュアップされ、いい感じになっていると思った。

昨日の今日でv11がv15を上げた感じだが、そもそもなんでv11を入れたんだっけ…?と思ったが、多分リリースページの真ん中にv11がいて、v15は画面の上の方にあったので、前回のインストール作業時に見えていなかったのだと思う。

前回の記事でForgejoのIssueを立てるための検証をしたときに最新がv16だったので、やけにバージョンがすっ飛んでるな、WinampやPHP方式か?と思ったら、単に私が見落としていただけだったか…という感じだ。

あと全然関係ないのだが、Forgejoのコントリビューターはオタクっぽい人が多いなと思ったのと、Forgejo同様にFOSSを使っていてCodebergでも採用されているAnubisの開発者もなかなかのオタクに見えるので、この二つのFOSSに何かの縁を感じたりもした。

2026/06/18(木)第五話 今日もサイトの改築をしたが、結果は控えめ

更新日:
投稿日:

今日のサイト改築の話 第四話の続き。Forgejoを設置して公開するまでをやったログと長いあとがきは4.5話の可能性もある。

Pタグの行頭字下げをやめた

ビュー 改修前 改修後
SP
PC

上の表はやめる前と、やめた後の見た目の比較。

adiaryを導入して少ししてから今まで長らく行頭の字下げが必要な気がしていたのだが、サイトのスタイリングをしていく中で空白が出すぎることや、他のマージンやパディングとの兼ね合いの調整、Pの中に画像を入れる、入れないによる差などが気になり始め、行頭字下げを廃止することにした。

これに伴いこのブログの行頭字下げも解除されている。

Web文書ではスタイリングの観点からインデントがない方が良いと判断したため。

廃止しても良いと思った理由としては行頭開けは原稿用紙や新聞、書籍など行間が詰まった媒体で段落の頭を判別しやすくするために配置されているものと考えたところによる。

Webは紙媒体と違い、余白を自由にとることができるから段落は空行で示すことができる。このことから行頭開けをするのは過剰ではないかと思い、廃止を決定した。

勿論、行頭字下げがあることで、より段落が判別しやすくなるとかもあると思うのだが、スタイリングをするときに行頭の空白が増えすぎること、画像などを巻き込むとややこしくなること、引用時のスタイルが破綻すること、CSS同士の相互干渉により考慮すべきことが増えることから、行頭インデントを廃止することとした。

あとがき

本日の活動が減った理由の一つとしては、ForgejoのOGPで日本語が文字化けすることに対して、Issueを立てることに力を入れていたことがある。

調べたところForgejoではGo言語組み込みフォントであるGo RegularをOGPの生成に使っており、このフォントはWGL4フォントファミリしかサポートしていないらしい。WGL4というのはWindows Glyph List 4のことで、端的に言うとWindowsに搭載されている欧文向けのフォントグリフの代表的なものらしい。

つまりForgejoでは欧文の代表的な文字しか表示できないというわけだ。というわけで日本語や繁体字・簡体字・ハングルなどのアジア文字をサポートすればアジア人が助かるというIssueを立てたが、一年以上前から議論されていたようで、即クローズされた。フォント問題が複雑で難しいらしい。わかる。私も名刺のフォント選定で死ぬほど悩んだもん。

と、まぁこんなのはほとんど言い訳で、次にやることが決まっていないというのが大きい。サイトの全体レイアウトの調整をしようにも指針を決めてないし、監視などの強化についてもドラフト状態のままである。なので、次すべきはタスク整理と、ロードマップ作りになってくるだろう。

あとはいい加減溜まってるブログネタを書かないと腐るので書くべきである。

というわけでサイト改築日記シリーズはいったん打ち切りになると思う。

一応今でも速攻で成果を出せるものとしてCachetの構築があるにはあるのだが、ちょっと勢いのまま走ってきた部分もあるので、一度立ち止まりたい気がしている。いや、そう言いつつ明日にはCachet置きましたとか書いてそうだが、それはそれでまぁ…。

そういえばGitHubからForgejoに移行した関係でページフッタにあるExtendsへのリポジトリリンクを変更したのと、Gistにあった資材をForgejoに移動してきたりもした。ついでに文字数カウンタを作って以来、長らく放置していたリガチャやサロゲートペアに対応する処理のテストコードを書ききった[1]。偉いと思う。

テストコードがあると、テストコードから、ああこれは正しい挙動なんだなというのが読み取れるので便利である。例えば👨‍👩‍👧‍👨‍👩‍👧‍👨‍👩‍👧‍👨‍👩‍👧‍あ゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙゙が゙゙゙゙ざ゙゙を4文字としてテストしているコードがあるが、このことからこの文字列が4文字になることが実装者の仕様として決まっていることが分かる。

Windowsでは先ほどの文字列はキャレットが四回移動するため、Windows的にも四文字の扱いだ。こういうのは決めの問題だが、テストコードがあることで、決めが分かるという話である。


  1. 但し実際のページのコードは大幅に簡略化しており、コードとしてみると別物なので、このテストコードが実際に機能しているとは言えない。このリポジトリのコードは元々別の目的で作ったもので、それを流用して例のツールを作ったという感じだ。

2026/06/17(水)Claude CodeとCodexでMCPサーバーを設定する方法

投稿日:

公式ドキュメントは読みづらいしLLM本人はまともに説明しないし、ググっても具体的でパッと解る記事が出てこなかったので書く。

確認環境

Env Ver
Codex CLI 0.0140.0
Claude Code 2.1.179

Codex

設定例

~/.codex/config.tomlを開き、ファイルの最後に以下を追記

[mcp_servers.hoge]
command = "/path/to/some-command"

[mcp_servers.hoge.env]
URL = "https://example.com"
API_KEY = "xxxxxxxxxx"

書式

MCPサーバー名の部分は解りやすい名前を入れておくといい。PukiwikiのMCPならpukiwiki、Redmineならredmineなど。

[mcp_servers.<MCPサーバー名>]
command = "MCPサーバーの起動コマンド"

[mcp_servers.<MCPサーバー名>.env]
このセクションには<KEY> = "<VALUE>"形式で環境変数を列挙する
必要な環境変数がなければ、このセクションは作らなくてよい

Claude Code

設定例

~/.claude.jsonを開き、projects."/path/to".mcpServersをこんな感じで書き換える。

"mcpServers": {
    "hoge": {
        "type": "stdio",
        "command": "/path/to/some-command",
        "env": {
            "URL": "https://example.com",
            "API_KEY": "xxxxxxxxxx"
        }
    }
},

書式

MCPサーバー名の部分は解りやすい名前を入れておくといい。PukiwikiのMCPならpukiwiki、Redmineならredmineなど。

"mcpServers": {
    "<MCPサーバー名>": {
        "type": "stdio", ← おまじない
        "command": "/path/to/some-command", ← MCPサーバーの起動コマンド
        "env": { ← ここに環境引数をKEY: VALUE形式で書く。なければこのセクションは不要
            "URL": "https://example.com",
            "API_KEY": "xxxxxxxxxx"
        }
    }
},

mcp addで追加した場合に起きていること

claude mcp add hoge -- npx -y git@github.com:Hoge/hoge-mcp.git

このコマンドで追加すると、~/.claude.jsonに叩いたカレントディレクトリの設定として以下が追加される。

"mcpServers": {
  "hoge": {
    "type": "stdio",
    "command": "npx",
    "args": [
      "-y",
      "git@github.com:Hoge/hoge-mcp.git"
    ],
    "env": {}
  }
},

やってることは要するにnpx -y git@github.com:Hoge/hoge-mcp.gitを実行しているだけである。

Node.js製のMCPサーバーをローカルにクローンして設定する場合の手順の一例

  1. まずはリポジトリをローカルに持ってくる
    cd ~
    mkdir mcp
    cd mcp
    git clone git@github.com:Hoge/hoge-mcp.git
    cd hoge-mcp
    pnpm i && pnpm build
    pnpm approve-builds
    pnpm build
    chmod u+x dist/index.js
    
  2. 使うLLMに応じて設定を行う

    • Codex
      ~/.codex/config.tomlを開き、ファイルの最後に以下を追記

      [mcp_servers.hoge]
      command = "/home/fuga/mcp/hoge-mcp/dist/index.js"
      
      [mcp_servers.hoge.env]
      URL = "https://hoge.example.com"
      API_KEY = "xxxxxxxxxx"
      
    • Claude Code
      1. MCPを使いたいパスでclaude mcp add hoge -- hogeを叩く
      2. ~/.claude.jsonを開き、先ほど叩いたパスのエントリを探し、mcpServersのところを次の形式で書き換える
        "mcpServers": {
           "hoge": {
               "type": "stdio",
               "command": "/home/fuga/mcp/hoge-mcp/dist/index.js",
               "env": {
                   "URL": "https://hoge.example.com",
                   "API_KEY": "xxxxxxxxxx"
               }
           }
        },
        

MCPサーバーの使い方

基本的にLLMが勝手にコールするので意識しなくてよい。

トラブルシューティング

MCPサーバーが起動しない、エラーを吐く

まずはMCPサーバーそのものを単純に起動できるか確認する。

叩き方としてはcommandに書いてあるコマンドを叩けばよい。argsenvがある場合は引数や環境変数も設定する。

そうすれば実行権限がないとか、参照するファイルが足りないとか、何かしらエラーが出るはずなので、それで確認すればよい。

あとがき

なんでたったこれほどのことなのに驚くほど情報がないのだろう?みんな脳死でLLMを叩いて意味も理解しないまま使っているのだろうか…。