開発スキル / Git実践編 / 2026.08.30

remote は、
GitHubのことではない

Git を始めようとすると、たいてい最初に GitHub のアカウントを作らされます。それで 「Git を使う = コードを外部サービスに置く」という理解ができあがる。 私も長いあいだ、そう思っていました。
remote はただのURLで、SSH越しの隣の机のMacでも、tailnet内のミニPCでも、同じディスクの別フォルダでも構いません。 ローカルLLMや社内データを扱うようになってから、この違いが効いてきました。

前提 Gitの基本操作を一度は触った 対象 端末が2台以上ある人 外部送信 ゼロで完結します
誤解 git ≠ GitHub

外に置かなくても、
動きました

GitHub はGitのホスティングサービスの1つであって、Git そのものではありません。 Git は 2005年に生まれ、GitHub は 2008年です。3年間、GitHub なしで回っていました。

「プライベートリポジトリにすれば安全」という考え方もありますが、 非公開であることと、外部に置いていないことは別です。 ローカルLLMを動かす動機が「データを外に出さないこと」なら、コードとプロンプトだけ外に出すのは筋が通りません。

この記事が扱う範囲

GitHub を否定するものではありません。公開したい、外部の人と協働する、CI を回す—— そういう目的があるなら GitHub は最適です。

ここで扱うのは「手元の2〜3台だけで、外に出さずに回したい」場合の構成です。 仕組みが分かれば、後から GitHub を足すこともできます(remote は複数持てます)。

正体 remote とは何か

4種類、どれでもいい

git remote add origin <ここ> の <ここ> に入るものは、次のどれでも構いません。

① ローカルパス /Volumes/backup/skills.git 同じMacの別フォルダでも、外付けSSDでもいい ② SSH ssh://satoshi@mac-mini/Users/satoshi/repos/skills.git 短縮形: satoshi@mac-mini:repos/skills.git ③ tailnet 越しのSSH ssh://satoshi@100.x.y.z/Users/satoshi/repos/skills.git Tailscale が配る固定IP。外からでも同じURLで通る ④ HTTP(S) https://github.com/… ← 私はこれしか知りませんでした

①が動くのを見たときに、いちばん腑に落ちました。ネットワークすら要らないからです。 同じMacの中で、フォルダを1つ remote にできます。

# 30秒で確かめる — ネットワーク不要
mkdir -p /tmp/demo/hub && cd /tmp/demo/hub
git init --bare skills.git          # ← これが remote になる

mkdir -p /tmp/demo/work && cd /tmp/demo/work
git init && echo hello > a.txt
git add . && git commit -m first
git remote add origin /tmp/demo/hub/skills.git   # ← ただのパス
git push -u origin main             # ← 通る

cd /tmp/demo && git clone hub/skills.git copy
ls copy                             # → a.txt がある

GitHub のアカウントもインターネットも使わずに、push と clone が成立しました。 remote の正体は、それだけのものです。

なぜ --bare なのか

作業ツリーがあると、
受け取れない

上で --bare を付けました。付けないと何が起きるか、実際に試すとこう出ます。

remote: error: refusing to update checked out branch: refs/heads/main
remote: error: By default, updating the current branch in a non-bare repository
remote: is denied, because it will make the index and work tree inconsistent
remote: with what you pushed, and will require 'git reset --hard' to match
remote: the work tree to HEAD.

理由は素直です。相手がそのブランチを開いて作業している最中に、こちらが履歴を書き換えたら、 相手の手元のファイルと記録が食い違うからです。Git はそれを拒みます。

--bare作業ツリーを持たないリポジトリです。中身は .git の中身そのもの。 誰も編集していないので、いつ push されても矛盾しません。だから中継役には bare を使います。

通常のリポジトリ bare リポジトリ myproject/ skills.git/ a.txt ← 作業ツリー HEAD src/ config .git/ ← 履歴 objects/ ← 履歴だけ refs/ 編集する人がいない = いつでも受け取れる
比較 SSHで取りに行くのとの違い

コピーは、進化しない

Mac が2台あるなら、SSH で片方から scprsync すれば、 スキルを持ってくること自体はできます。ではなぜ Git なのか。

scp / rsync で取りに行くgit remote で繋ぐ
方向片方向(取りに行く側だけ)双方向。どちらからでも push できる
両方で直したら後から上書きした方が勝つ分岐として残り、3-way merge で合流
誰が何をしたか残らないコミット単位で残る
なぜそうしたか残らないコミットメッセージに書ける
相手が寝ている時取れない手元の複製で作業を続けられる
戻したいとき元がもう無い任意の時点に戻せる

決定的なのは2行目だと思います。 「別のデバイスでもスキルを進化させたい」という時点で、両方が書き手になるということです。

コピーは、コピー先で改良しても本家に戻す道がありません。 戻すには手で差分を見て貼り直すことになり、それを何度かやると、どちらが正なのか誰にも分からなくなります。 これが「二度作る」の始まりです。

「取りに行く」から「両方で育てる」へ

SSH でコピーしてくる関係は、片方が親でもう片方が子です。子で育てたものは親に還りません。

git remote で繋ぐと、両方が対等な書き手になります。 どちらで作ったスキルも、もう一方に流れていく。 2台目は「取りに行く先」ではなく「一緒に育てる場所」になります。

構成 どう並べるか

2台なら直結、
3台以上ならハブ

Mac A(作業) Mac B(作業) 2台 — 直結 互いを remote に登録するだけ 両方に bare を1つずつ置く必要あり Mac / Win Linux 常時起動の1台 bare を置く 3台以上 — ハブ型 全員が同じ1箇所に push / pull する

2台なら、お互いを remote に登録するだけで足りるようです。ただしどちらも作業ツリーを持っているので、 push を受けるための bare をそれぞれに1つ用意することになります。少し面倒です。

3台目が出てきたところで、私はハブ型に切り替えました。常時起動している1台(ミニPCでもNASでも構いません)に bare を置き、全員がそこを見る。組み合わせが増えても、繋ぎ先は常に1箇所です。

ハブは「サーバソフト」ではありません

Git のサーバに必要なのはSSHで入れることと、bareリポジトリがあることだけです。 専用のサービスをインストールする必要はありません。

普段使っていない古いMacでも、常時起動のミニPCでも、ssh で入れるなら今日からハブになれます。

生成 コマンドを作る

3つ埋めれば、
そのまま貼れます

セットアップ・コマンド生成器

ハブ側とクライアント側で叩くコマンドを組み立てます。Tailscale を使うなら、ホスト名の欄に 100.x.y.z か MagicDNS 名を入れてください。それだけで外出先からも同じ手順が通ります。

STEP 1 / ハブ側で1回だけ

      
STEP 2 / 中身がある端末(初回だけ)

      
STEP 3 / もう1台で受け取る

      
STEP 4 / 以後の毎日

      

STEP 3 の注意

受け取る側にすでに同じフォルダがある場合、clone は空のディレクトリにしか展開できません。 生成したコマンドでは、いったん別名で clone してから中身を移す形にしてあります。

移す前に、元のフォルダを必ず退避してください。片側にしかない設定が消えると、 それこそ「片寄り」の最悪の形になります。

tailnet なぜVPNと相性がいいか

住所が、変わらない

SSH で繋ぐと決めた瞬間、相手のIPアドレスをどう指すかという問題が出ます。 自宅では 192.168.1.x、カフェからは繋がらない、実家では別の番号。 remote のURLを毎回書き換えることになります。

Tailscale のような tailnet を張ると、各デバイスに場所によらない固定のアドレスが与えられます。

tailnet なし 自宅 ssh://satoshi@192.168.1.42/... 場所ごとに変わる 外出 繋がらない(NATの内側) → ポート開放? DDNS? 固定IP契約? 全部やりたくない tailnet あり どこでも ssh://satoshi@100.x.y.z/... ← 1つのURLで済む → remote は一度書けば書き換え不要。ポート開放も不要

そしてもう一つ大きいのが、通信が tailnet の中で閉じることです。 コードもプロンプトも、インターネット上のどのサービスにも渡りません。

ローカルLLM開発では、ここが要件になります

ローカルでモデルを動かす動機は、たいてい「データを外に出さないこと」です。 推論を手元でやっているのに、それを呼び出すコード・プロンプト・評価用データだけ外部に置くのは、 説明としても整合しません。

tailnet 内の bare リポジトリなら、推論も、コードも、履歴も、すべて自分の管理下に収まります。 社内で説明する時にも、この線引きは通しやすいはずです。

Tailscale の認証の考え方そのものは 通れたこと自体が認証である — Tailscale の VPN と SSH に書いてあります。

運用 何を置くか

まず .claude/ を1本

私は全部を一度に管理下に置こうとして、一度やめました。いちばん効くもの1本からのほうが続いています。

入れてはいけないもの

APIキー・トークン・パスワード・顧客データ・未公開の出願情報。 外部に出していなくても、履歴に残ると端末が1台盗まれた時に全部漏れます。

.gitignore.env*_token* を先に書いてから git init してください。 順序が逆だと、最初のコミットに入ります。

仕組みを知る

なぜこれで動くのか

ここまでは手順の話でした。なぜ remote がただのURLでよいのか、なぜ両方で直しても合流できるのかは、 Git の内部構造から出てきます。

この3つは、三台で、同じものを二度作る — Gitの内部構造を8層で読む で Layer 4・5・7 として扱っています。手を動かしてから読むと、腑に落ちる速度が違います。

なぜ「経緯を残す」ことが効くのか

手順ではなく効き方の側は 分かっていないことが、分からない に書きました。git・サイドチャット・書いて公開するの三つが、それぞれ違うものを頭の外に出しています。

私がまだ確かめていないこと

この構成で回してはいますが、試せていないことが残っています。

ハブが落ちたときの復旧。各端末が完全な複製を持つから大丈夫なはず、と理解していますが、 実際に壊して戻す訓練をしていません。「はず」で止まっています。
3台以上でのブランチの分け方。いまは端末ごとに分けていますが、これが良いのかは分かっていません。
SSH鍵の配り方。台数が増えたときの管理を、まだ手でやっています。

書いた手順は私の手元で動いているというだけで、これが定石なのかは判断できていません。 もっと良いやり方をご存じでしたら教えてください。

今日やるなら、この順で

① 上の「30秒で確かめる」を実際に叩く。ネットワークなしで push が通ることを自分の目で見る。
② 生成器で自分の環境のコマンドを作り、~/.claude/skills/ を1本繋ぐ。
③ 2台目から1行直して push してみる。ここで初めて「両方が書き手になる」感触が分かります。