PoC(検証コード)を書いていると、最初は「とりあえず一時ディレクトリ」で始めがちです。ところが検証がうまくいって「これは製品にする」となった瞬間、その一時ディレクトリは消えると困る資産に変わります。
先日まさにこの場面があり、コマンドラインだけで一時作業を独立プロジェクトへ昇格させました。ディレクトリ整備・移設・VSCodeワークスペース・Python仮想環境・git初期化・引き継ぎドキュメントまで、数分の作業です。本記事はその再利用できる型と、地味にハマった .gitignore の罠を共有します。
環境は macOS。言語は Python(+一部 Swift)。コマンドはそのまま流用できます。
0. いつ「昇格」させるか
判断基準はシンプルです。次のどれかに当てはまったら、一時領域から独立プロジェクトへ移します。
- 置き場所が消える(セッション用の一時ディレクトリ、
/tmpなど) - git 管理・テスト・依存固定が欲しくなった
- 他の人/別セッションが続きをやる可能性が出てきた
「分析」から「開発」に変わったサイン、と言い換えてもいいです。
1. 器を作って中身を移す(消える前に)
まずディレクトリを作り、丸ごと移します。ポイントは移設後に必ず動作確認すること。相対パス依存やコンパイル済みバイナリは、場所が変わると壊れがちだからです。
SRC=/tmp/work/ocr-poc # 一時領域
DST=/Users/you/works/company/projects/invoice-ocr # 本拠地
mkdir -p "$DST/poc" "$DST/docs"
cp -R "$SRC/." "$DST/poc/"
# コンパイル物は移設先で作り直す(パスの健全性を担保)
rm -f "$DST/poc/macvision_ocr"
swiftc -O "$DST/poc/macvision_ocr.swift" -o "$DST/poc/macvision_ocr"
# ★移設後に再実行して、同じ結果が出るかを確認する
cd "$DST/poc" && python3 extract_local.py && python3 eval.py
「移したら壊れていた」を防ぐために、移設=コピー+再実行での再現確認までがワンセットです。ここで前と同じスコアが出れば、パス依存の事故がないと分かります。
2. VSCode ワークスペース(.code-workspace)を作る
フォルダをただ開くのではなく、.code-workspace ファイルを置くと、インタプリタ・整形・除外・推奨拡張をプロジェクトに固定できます。チームでも同じ設定で開けます。
// invoice-ocr.code-workspace
{
"folders": [{ "path": "." }],
"settings": {
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.terminal.activateEnvironment": true,
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": { "source.organizeImports": "explicit" }
},
"files.exclude": {
"**/__pycache__": true,
"poc/results": true,
"poc/samples/*.png": true,
"poc/macvision_ocr": true
}
},
"extensions": {
"recommendations": ["ms-python.python", "charliermarsh.ruff", "swiftlang.swift-vscode"]
}
}
開くのもコマンド一発です(VS Code の code CLI)。
code /Users/you/works/company/projects/invoice-ocr/invoice-ocr.code-workspace
files.exclude に生成物(画像・結果・バイナリ)を入れておくと、エクスプローラや検索が散らからず、レビューもしやすくなります。
3. Python 仮想環境(.venv)と依存
プロジェクト専用の仮想環境を作り、ワークスペースの python.defaultInterpreterPath をそこに向けます。
cd "$DST"
python3 -m venv .venv
.venv/bin/pip install -q ruff # 開発ツール(整形/リンタ)
依存は本番用と開発用を分けておくと運用が楽です。
# requirements.txt … 本番依存(まだ無ければ空でよい)
# requirements-dev.txt … 開発用
ruff
4. git init と .gitignore の罠(実話)
最後に git 化します。ここで実際にハマったのが .gitignore です。
# 生成物・秘密情報はコミットしない
.venv/
poc/results/
poc/samples/*.png
poc/macvision_ocr # ← これが罠
.env
*service-account*.json
*.pem
.gitignore は 行末コメントに対応していません。上のように poc/macvision_ocr # ← これが罠 と書くと、パターンが「余白+コメント込みの文字列」として解釈され、マッチしなくなります。実際、初回の git add でコンパイル済みバイナリがコミット対象に紛れ込みました。
正しくはコメントを行頭に置きます。
# Swiftコンパイル済みバイナリ
poc/macvision_ocr
そして「入るべきものだけが入っているか」を、コミット前に必ず検証します。
git init -q
git add -A
git status --short # 追加されるファイル一覧を目視
git ls-files --error-unmatch poc/macvision_ocr \
&& echo "NG: バイナリが追跡されている" \
|| echo "OK: 除外できている"
混入していたら git rm --cached <path> で外し、.gitignore を直してから改めて git add。最後にコミットします。
git commit -q -m "初期化: PoC を独立プロジェクトへ移設(2系統エンジン)"
秘密情報(.env・サービスアカウントの鍵 *service-account*.json・*.pem)は最初の .gitignore から除外しておくのが事故防止の鉄則です。
5. 引き継ぎを1本残す(HANDOVER.md)
別セッション/別担当が続けられるよう、HANDOVER.md を1本置きます。盛り込む項目は決まっています。
- 目的 / 現在地 / リポジトリ構成
- 実行手順(最短) / 環境の要点・ハマりどころ
- 未決事項 / 次の一手 / 意思決定ログ(なぜそうしたか)
「READMEは使い方、HANDOVERは文脈と判断」——この2本があると、時間が空いても、担当が変わっても、すぐ再開できます。
まとめ:昇格チェックリスト
□ 器を作って丸ごと移す(mkdir → cp -R)
□ 移設後に再実行して結果を再現(パス事故の検出)。バイナリは作り直す
□ .code-workspace を置く(interpreter/整形/除外/推奨拡張)
□ .venv を作り、ワークスペースの interpreter を向ける
□ requirements(.txt / -dev.txt)を分ける
□ .gitignore はコメントを行頭に。秘密情報を最初から除外
□ git add 後に status と ls-files --error-unmatch で検証してからコミット
□ HANDOVER.md を残す(目的・構成・未決・次の一手・決定ログ)
一時作業のまま放置すると、良い検証結果ほど「消えると痛い」リスクになります。うまくいった瞬間に昇格させる——CLIならこの一連が数分で終わります。
Analyzegear

