Vercel CLIはgitではなく作業ツリーを直接デプロイする──git statusが本番の中身を表していない状態の見分け方
Vercel公式ドキュメントは「.vercelignoreで除外を指定していなければ、既定の除外を除きプロジェクト内の全ファイルがVercelにアップロードされる」と明記している。アップロードの単位はコミットではなくディレクトリである。当サイト(Next.js 16.2.7+Vercel CLI 53.2.0、git remote が空)では2026年8月14日16時18分時点でHEADのコミットが15時58分29秒、最新の本番デプロイが15時35分41秒と22分ずれており、16時17分時点のローカル記事362本に対し本番サイトマップは357本、差5本のうち3本が本番でHTTP 404を返した。
目次
Vercel CLIからvercel --prodでデプロイしている構成では、Vercelにアップロードされるのは「gitのコミット」ではなく「そのディレクトリのファイル」である。Vercel公式は.vercelignoreのページで「既定の除外を除き、プロジェクト内の全ファイルがアップロードされる」と書いており、判定に使われるのは.vercelignoreであってgitの管理状態ではない。したがって未コミット・未追跡のファイルもそのまま本番に載り、逆にコミット済みでもデプロイしていなければ本番には存在しない。自分のリポジトリがこの状態かどうかはgit remote -v・.vercel/project.jsonの有無・vercel project inspectの3点で判定でき、本番と作業ツリーのズレは「最新デプロイの作成時刻とHEADのコミット時刻」「ローカルのファイル一覧と本番サイトマップの差分」「個別URLのHTTPステータス」で突き合わせられる。
- Vercel公式は「Aside from the default exclusions, all files within your project are uploaded to Vercel if no source path is specified to be excluded in a
.vercelignoreconfiguration file」と書いている。アップロードの判定条件にgitの追跡状態は出てこない- 既定で除外されるファイル一覧には
.gitと.gitignoreが含まれ、同ページは「these ignored files are only relevant when using Vercel CLI」と注記している。gitの履歴そのものはアップロードされない- 2026年8月14日16時18分(日本時間)の当サイトの実測では、HEADのコミットは15時58分29秒、最新の本番デプロイは15時35分41秒。gitと本番は別々の時刻で進んでいた
症状1:git remote -v が何も返さないのに本番は動いている
2026年8月14日16時14分(日本時間)、当サイトのリポジトリで実行した結果をそのまま貼る。
$ git remote -v
$ echo $?
0
出力は1行も無く、終了コードは0である。リモートが1つも登録されていない(エラーではない)。この状態ではGitHubにpushする先が無いので、GitHub連携による自動デプロイは成立しない。それでも本番サイトは更新され続けている。更新しているのはVercel CLIである。
同じディレクトリには.vercelディレクトリがある。
$ ls -a .vercel
.
..
README.txt
project.json
.vercel/project.jsonのキーはorgId・projectId・projectNameの3つだった(値は識別子なので伏せる)。.vercel/README.txtはVercelが自動生成したもので、原文は次のとおりである。
> Why do I have a folder named ".vercel" in my project?
The ".vercel" folder is created when you link a directory to a Vercel project.
(なぜプロジェクトに「.vercel」という名前のフォルダがあるのか? 「.vercel」フォルダは、ディレクトリをVercelプロジェクトにリンクしたときに作成される)
リンクされているのはディレクトリであって、ブランチでもコミットでもない。
症状2:ローカルにあるファイルが本番で404を返す
同じ日の16時17分に、ローカルの記事ファイル一覧と本番サイトマップを突き合わせた。
$ ls content/news/*.md | wc -l
362
$ curl -s https://www.ai-jitan-hub.com/sitemap.xml -o /tmp/sm.xml -w "HTTP=%{http_code}\n"
HTTP=200
$ grep -o '<loc>[^<]*</loc>' /tmp/sm.xml | sed 's|<loc>||;s|</loc>||' \
| grep '/news/' | sed 's|.*/news/||' | sort -u | wc -l
357
差は5本だった。ただしこの5という数字をそのまま「未デプロイ本数」と読むと誤る。5本それぞれに本番でHTTPステータスを取ると、内訳が割れた。
| ローカルにあるslug | 本番のHTTPステータス | gitの追跡状態 |
|---|---|---|
deepfake-voice-clone-25m-hong-kong-fraud |
200 | 追跡済み(最終更新コミット3497961・11:12) |
spacex-cursor-anysphere-acquisition |
200 | 追跡済み(最終更新コミット3497961・11:12) |
http-200-empty-page-cloudflare-js |
404 | 未追跡 |
indexnow-google-not-participating |
404 | 未追跡 |
youtube-rss-feed-user-agent-404 |
404 | 未追跡 |
上2本はfrontmatterにcanonicalSlugが入っており、当サイトの仕様でサイトマップから意図的に外している(本番には存在してHTTP 200を返す)。サイトマップ差分5本のうち、本当に本番に無かったのは3本である。 差分の数え方を1回で確定させず、URLごとにステータスを取り直して初めて内訳が分かった。
$ curl -s -o /dev/null -w "%{http_code}\n" \
https://www.ai-jitan-hub.com/news/youtube-rss-feed-user-agent-404
404
症状3:最新デプロイの時刻がHEADのコミット時刻より古い
2026年8月14日16時16分〜16時18分17秒(日本時間)に取得した2つの時刻である。
$ git log -1 --format="%h %ad %s" --date=iso
1f53d5a 2026-08-14 15:58:29 +0900 判定:被リンク0でも新規記事は2週間以内にほぼ100%インデックスされる
$ npx vercel inspect https://ai-jitan-ktqk33e1a-ai-jitan-lab.vercel.app
General
name ai-jitan-hub
target production
status ● Ready
created Fri Aug 14 2026 15:35:41 GMT+0900 (日本標準時)
HEADのコミットは15時58分29秒、本番デプロイの作成は15時35分41秒。HEADのほうが22分48秒新しい。 この状態では「gitに入っている=本番に載っている」は成り立たない。逆向き(本番のほうが新しい=未コミットのものが載っている)も同じ理屈で起こりうる。
なおvercel inspectの出力はGeneral/Aliases/Buildsの3セクションで、コミットハッシュやブランチ名を示す行は含まれていなかった。vercel project inspect <プロジェクト名>の出力も同様で、grep -i "git\|repo"のヒットは0件だった(2026年8月14日16時16分実行)。
原因:Vercelは「ディレクトリ」を送り、gitは判定に使われない
1. アップロード対象は.vercelignoreで決まる
Vercel公式ドキュメント「Exclude Files from Deployments with .vercelignore」(last_updated 2025年3月12日・2026年8月14日確認)の「Uploaded Files」節はこう書いている。
Aside from the default exclusions, all files within your project are uploaded to Vercel if no source path is specified to be excluded in a
.vercelignoreconfiguration file
(既定の除外を別にすれば、.vercelignore設定ファイルで除外対象のパスを指定していない限り、プロジェクト内の全ファイルがVercelにアップロードされる)
同ページは.vercelignoreについて「This file works similarly to a .gitignore file, but it is specific to Vercel.(このファイルは.gitignoreと似た働きをするが、Vercel専用である)」とも書く。似ているだけで、同じものではない。
当サイトの.vercelignoreは1行だけだった。
og_candidates
つまりog_candidates以外は、gitで追跡されていようがいまいが、アップロード対象になる。
2. 既定で除外されるものに.gitが入っている
「Build Features for Customizing Deployments」(last_updated 2026年6月9日・2026年8月14日確認)の「Ignored files and folders」節はこう始まる。
Vercel ignores certain files and folders by default and prevents them from being uploaded during the deployment process for security and performance reasons. Please note that these ignored files are only relevant when using Vercel CLI.
(Vercelは特定のファイルとフォルダを既定で無視し、セキュリティとパフォーマンス上の理由からデプロイ処理中にアップロードされないようにする。これらの無視されるファイルはVercel CLIを使うときにのみ関係する点に注意)
同ページが挙げる一覧には次が含まれる(抜粋)。
.hg
.git
.gitmodules
.svn
.cache
.next
.now
.vercel
.npmignore
.dockerignore
.gitignore
.gitが除外されている以上、Vercel側にはコミット履歴もブランチも渡っていない(CLIデプロイの場合)。渡っているのはファイルの中身だけである。ここが「gitの状態が本番に反映される」という直感が壊れる地点になる。
3. GitデプロイとCLIデプロイは別の経路
「Deploying to Vercel」(last_updated 2026年6月17日・2026年8月14日確認)は、デプロイの作り方を5つ(Git/Vercel Drop/Vercel CLI/Deploy Hooks/Vercel REST API)に分けている。Gitについての記述は次のとおりである。
The most common way to create a deployment is by pushing code to a connected Git repository. When you import a Git repository to Vercel, each commit or pull request (on supported Git providers) automatically triggers a new deployment.
(デプロイを作る最も一般的な方法は、接続されたGitリポジトリにコードをpushすることである。GitリポジトリをVercelにインポートすると、コミットやプルリクエストのたびに新しいデプロイが自動的にトリガーされる)
CLIについてはこう書いている。
You can deploy your Projects directly from the command line using Vercel CLI. This method works whether your project is connected to Git or not.
(Vercel CLIを使えば、コマンドラインから直接プロジェクトをデプロイできる。この方法は、プロジェクトがGitに接続されていてもいなくても機能する)
「コミットがデプロイを引き起こす」のはGit経路の性質であって、CLI経路には無い。 同ページはCLIの初回デプロイについて「This links your local directory to your Vercel Project and creates a Production Deployment. A .vercel directory is added to store Project and Organization IDs.(これによりローカルディレクトリがVercelプロジェクトにリンクされ、本番デプロイが作られる。プロジェクトIDと組織IDを保存するために.vercelディレクトリが追加される)」と書く。リンクされる単位は繰り返しディレクトリである。
4. Git連携を張るにはローカルにremoteが要る
「vercel git」(last_updated 2026年3月17日・2026年8月14日確認)はvercel git connectの動作をこう説明する。
When run, Vercel CLI searches for a local
.gitconfig file containing at least one remote URL. If found, you can connect it to the Vercel Project linked to your directory.
(実行すると、Vercel CLIはremote URLを少なくとも1つ含むローカルの.git設定ファイルを探す。見つかれば、それをディレクトリにリンクされたVercelプロジェクトに接続できる)
当サイトはgit remote -vが空なので、この条件を満たしていない。「連携を張り忘れた」のではなく、張る前提そのものが無い状態である。
なお「Linking Projects with Vercel CLI」(last_updated 2026年6月9日・2026年8月14日確認)は、リンクの中身をこう定義している。
Once set up, a new
.verceldirectory is added to your directory. The.vercel/project.jsonfile contains theorgIdandprojectIdof your Vercel Project. To unlink your directory, remove the.verceldirectory.
(セットアップが済むと、ディレクトリに新しく.vercelディレクトリが追加される。.vercel/project.jsonファイルにはVercelプロジェクトのorgIdとprojectIdが入っている。ディレクトリのリンクを解除するには.vercelディレクトリを削除する)
対処
自分のリポジトリがこの状態かを判定する(3コマンド)
# 1) gitのリモートがあるか
git remote -v
# 2) CLIリンクが張られているか(キー名だけ見る。値は識別子なので表示しない)
python3 -c "import json;print(sorted(json.load(open('.vercel/project.json')).keys()))"
# 3) Vercel側のプロジェクト設定にGitリポジトリが出るか
npx vercel project inspect <プロジェクト名>
1が空で2にorgId・projectIdが入っているなら、そのディレクトリはCLIデプロイ専用の構成である。この場合、本番の中身を決めているのは作業ツリーであって、コミット履歴ではない。
本番と作業ツリーを突き合わせる
コンテンツ主体のサイトなら、この3つで十分に差が出る。
- 時刻を比べる。
git log -1 --date=isoのコミット時刻と、npx vercel inspect <本番デプロイURL>のcreatedを並べる。後者が古ければ、その差分の中身は本番に載っていない - 一覧の差分を取る。 ローカルのファイル一覧と本番の
sitemap.xmlをcommで突き合わせる。ただしサイトマップから意図的に外している記事があると差分は膨らむので、差分の数をそのまま結論にしない - URLごとにHTTPステータスを取る。 差分に出たslugを1本ずつ
curl -o /dev/null -w "%{http_code}"で叩く。404なら本番に無い、200ならサイトマップ側の都合である
巻き戻りを避ける運用
アップロード対象が作業ツリーである以上、作業ツリーを巻き戻せば、次のデプロイの中身も巻き戻る。 git checkoutやgit stashで手元のファイルを戻した直後にデプロイすれば、戻した内容がそのまま本番になる。この因果はドキュメントの記述から導けるが、当サイトはこの事故を実際に起こした記録を持っていない(後述の但し書きを参照)。実務上の手当ては次の3つである。
- デプロイ前に
git statusを見る。ただし**git statusが綺麗=本番と一致、ではない**。クリーンでも「コミット済みだが未デプロイ」は残る - 手元のファイルを巻き戻す操作の直後は、デプロイの前に上の突き合わせを1回挟む
- 恒久的に直すなら、リモートを追加して
vercel git connectでGit経路に寄せる。Git経路ならデプロイの単位がコミットになる
.vercelignoreは.gitignoreの代わりにならない
公式が「アップロードするかどうか」の判定条件として書いているのは.vercelignoreだけである。.gitignoreは「既定でアップロードされないファイル」の一覧に名前が載っているだけで、.gitignoreに書いたパターンがアップロード対象の判定に使われる、とは書かれていない。 本番に出したくないファイルがあるなら.vercelignore側に書く。当サイトはこの挙動を実測で検証していない。
観測条件(2026年8月14日・当サイト1件)
計測環境はNext.js 16.2.7+Vercel CLI 53.2.0、macOS(Darwin 24.1.0)、対象は/Users/koshitakayuta/projects/ai-jitan-hub。Vercelプロジェクトの作成日は2026年6月11日、Root Directoryは.、Framework PresetはNext.jsである(vercel project inspectで確認)。
| 時刻(JST) | 取得した内容 |
|---|---|
| 16:14:07 | git remote -vが空・終了コード0。.vercel/project.jsonのキーは3つ。.vercelignoreは1行(og_candidates)。未追跡ファイルは1本 |
| 16:16 | vercel project inspect実行。出力にGit/repositoryを含む行は0件 |
| 16:16 | vercel inspectで最新本番デプロイの作成時刻=2026-08-14 15:35:41 JSTを確認 |
| 16:17:05 | ローカルcontent/news/*.md=362本、本番サイトマップの/news/=357本、差5本 |
| 16:17:54 | 差5本のHTTPステータスを個別取得。200が2本(canonicalSlugあり)、404が3本 |
| 16:18:17 | HEAD=1f53d5a(2026-08-14 15:58:29 +0900)。未追跡ファイルは5本に増加 |
なおこの記事のファイル自体は16時18分より後に作成したため、上の362本・357本の集計には含まれていない。同じコマンドを今から実行すれば数字は変わる。
16時14分から16時18分までの4分間で、未追跡ファイルが1本から5本に増えている。 同じリポジトリに対して別のプロセスが同時に書き込んでいたためである。作業ツリーは「今この瞬間の状態」であって、記録した数字はすべて取得時刻とセットでしか意味を持たない。
正直な但し書き
git checkout/git stashで本番が巻き戻る事故を、当サイトは実際には踏んでいない。 記事中でそう書けるのは「アップロード対象が作業ツリーである」というVercel公式の記述からの推論までである。当サイトが観測したのは「作業ツリーにしか無いファイルは本番で404を返す」(3本)という一方向のズレだけで、逆方向(本番にあって作業ツリーに無い)は今回のスナップショットでは0件だった。
「未コミットのコードが本番で動いていた」という当日の記録は、いま再検証できない。 当サイトのセッションログには、関連記事の表示件数を8件にする変更が未コミットのまま本番で有効だった、という申し送りが残っている。git履歴で確認できるのは、getRelatedPosts(post, 8)がコミット26033ef(2026年8月14日05時10分03秒 +0900)で入り、それ以前はgetRelatedPosts(post, 3)だった(a2ae3ea・2026年7月10日20時36分18秒 +0900で導入)という点までである。コミット前の本番デプロイの中身を後から取り出す手段を当サイトは持っていないため、本記事はこの件を証拠として使っていない。
vercel project inspectにGitの行が無いことは、Git連携が無いことの証明にはならない。 CLIが連携時に必ずGit関連の行を出力する、という記載を公式ドキュメントで確認できていない。当サイトが確認したのは「出力にヒットが0件だった」という事実までである。判定の根拠として強いのはgit remote -vが空である点(vercel git connectの前提条件を満たさない)のほうである。
サイトマップ差分は最初「5本」と出た。 そのまま「未デプロイ5本」と書けば誤りだった。当サイトには重複記事をcanonicalSlugでまとめる仕組みがあり、2本はそれによってサイトマップから外れていた。差分を数えた直後に個別のHTTPステータスを取らなければ、この2本を混ぜたまま結論を書いていた。
.gitignoreのパターンがVercel CLIのアップロード判定に使われるかどうかは未検証である。 公式は.vercelignoreについてしか書いていない。当サイトは.gitignoreに書いたファイルが本番にアップロードされるかを直接確かめていないので、ここは「公式に記載が無い」以上のことを言えない。
Vercel公式ドキュメントの引用は英語版の原文を採り、訳は当サイトで付けた。 訳の責任は当サイトにある。またドキュメントのlast_updatedは取得時点でページに記載されていた値をそのまま書いており、当サイトが独立に検証したものではない。
出典
- Exclude Files from Deployments with .vercelignore | Vercel Docs(last_updated 2025年3月12日、2026年8月14日確認): https://vercel.com/docs/deployments/vercel-ignore
- Build Features for Customizing Deployments | Vercel Docs(last_updated 2026年6月9日、2026年8月14日確認): https://vercel.com/docs/builds/build-features
- Deploying to Vercel | Vercel Docs(last_updated 2026年6月17日、2026年8月14日確認): https://vercel.com/docs/deployments
- vercel deploy | Vercel Docs(last_updated 2026年7月23日、2026年8月14日確認): https://vercel.com/docs/cli/deploy
- Deploying Projects from Vercel CLI | Vercel Docs(last_updated 2026年7月23日、2026年8月14日確認): https://vercel.com/docs/cli/deploying-from-cli
- Linking Projects with Vercel CLI | Vercel Docs(last_updated 2026年6月9日、2026年8月14日確認): https://vercel.com/docs/cli/project-linking
- vercel git | Vercel Docs(last_updated 2026年3月17日、2026年8月14日確認): https://vercel.com/docs/cli/git
- AI時短ラボ 実測ログ: 2026年8月14日16時14分〜16時18分(日本時間)に
/Users/koshitakayuta/projects/ai-jitan-hubで取得したgit remote -v/git status --porcelain/git log/npx vercel project inspect/npx vercel inspect/curlの各出力
出典・参照資料
- 一次資料Exclude Files from Deployments with .vercelignore | Vercel Docs ↗
- 一次資料Build Features for Customizing Deployments | Vercel Docs ↗
- 一次資料Deploying to Vercel | Vercel Docs ↗
- 一次資料vercel deploy | Vercel Docs ↗
- 一次資料Deploying Projects from Vercel CLI | Vercel Docs ↗
- 一次資料Linking Projects with Vercel CLI | Vercel Docs ↗
- 一次資料vercel git | Vercel Docs ↗
AIニュースの解説を動画でも
YouTubeでは注目ニュースの背景を解説し、Xでは新着記事をお知らせしています。
コメント
まだコメントはありません。最初のコメントを書いてみませんか?
AIについて聞きたいことはありますか?
質問箱で無料で受け付けています。回答は公開され、他の方の参考にもなります。
質問箱を見る →新しい記事をメールで受け取る
AIの新しい発表を、出典付きで整理して届けます。