【bat】バッチファイルで自動デプロイを実現する完全ガイド|Git pull・ROBOCOPY・バックアップ・エラー処理・ログ記録まで

【bat】バッチファイルで自動デプロイを実現する完全ガイド|Git pull・ROBOCOPY・バックアップ・エラー処理・ログ記録まで bat

コードのデプロイ作業を毎回手動で行うのは時間がかかり、ミスも起きやすいです。バッチファイル(.bat)を使えば「git pull → バックアップ → コピー → サービス再起動 → ログ記録」の一連の流れをワンクリックで自動化できます。この記事ではシンプルな基本実装から、ROBOCOPY・エラー処理・ステージング/本番切り替えまで実践的に解説します。

この記事でわかること

  • git pull + xcopy によるシンプルな自動デプロイの基本構成
  • ROBOCOPY を使った差分コピー・ミラーリングデプロイ
  • デプロイ前に自動バックアップを取る方法
  • ERRORLEVEL でエラー時に処理を中断する安全なデプロイ
  • サービス停止→デプロイ→サービス起動 のフルフロー
  • 引数でステージング/本番環境を切り替える方法
スポンサーリンク

デプロイ方式の比較

方式 コマンド 差分コピー ミラーリング 推奨場面
xcopy xcopy /E /Y ×(全コピー) × シンプルな社内ツール・小規模デプロイ
ROBOCOPY robocopy /MIR ファイル数が多い・差分のみ転送したい
WinSCP(SCP/SFTP) winscp /script リモートサーバーへのアップロード
robocopy /E /XO robocopy /E /XO ◎(更新のみ) × 削除せず新しいファイルだけ追加したい

基本実装:git pull + xcopy + ログ記録

最もシンプルな自動デプロイの形です。設定変数を先頭にまとめることで、環境ごとのパス変更が1箇所で済みます。

@echo off
setlocal

REM ===== 設定(環境に合わせて変更) =====
set REPO_DIR=C:\projects\myapp
set DEPLOY_DIR=C:\inetpub\wwwroot\myapp
set LOG_FILE=C:\deploy_logs\deploy.log

REM ===== ログ開始 =====
echo =============================== >> %LOG_FILE%
echo [開始] %DATE% %TIME% >> %LOG_FILE%

REM ===== 最新コードを取得 =====
cd /d %REPO_DIR%
git pull origin main >> %LOG_FILE% 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] git pull に失敗しました >> %LOG_FILE%
    echo デプロイ失敗:git pull エラー
    pause & exit /b 1
)

REM ===== ファイルをデプロイ先にコピー =====
xcopy /E /Y /I "%REPO_DIR%\*" "%DEPLOY_DIR%\" >> %LOG_FILE% 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] xcopy に失敗しました >> %LOG_FILE%
    echo デプロイ失敗:コピーエラー
    pause & exit /b 1
)

echo [完了] %DATE% %TIME% >> %LOG_FILE%
echo =============================== >> %LOG_FILE%
echo デプロイ完了しました。
pause
endlocal
設定変数を先頭に集める
環境ごとに変わる値(REPO_DIR・DEPLOY_DIR・LOG_FILE)は冒頭の set にまとめると保守しやすくなります。各コマンドの後に if %ERRORLEVEL% neq 0 (...) でエラーチェックすることで、git pull が失敗したまま壊れたファイルをデプロイするリスクを防げます。

ROBOCOPY でミラーリングデプロイ

ファイル数が多い場合や、更新ファイルだけを転送したい場合は xcopy よりROBOCOPY が適しています。/MIR オプションで送信元と送信先を完全に同期(削除も含む)できます。ROBOCOPYの詳細な使い方はバッチファイルでフォルダをコピーする方法も参照してください。

@echo off
setlocal

set SRC=C:\projects\myapp
set DST=C:\inetpub\wwwroot\myapp
set LOG=C:\deploy_logs\robocopy.log

REM /MIR  : ミラーリング(送信元にないファイルをDSTから削除)
REM /R:3  : 失敗時に3回リトライ
REM /W:5  : リトライ間隔5秒
REM /NP   : 進捗パーセント非表示(ログをすっきり)
REM /LOG+: : ログを追記
robocopy "%SRC%" "%DST%" /MIR /R:3 /W:5 /NP /LOG+:"%LOG%"

REM ROBOCOPYの終了コード: 0-7は正常、8以上はエラー
if %ERRORLEVEL% geq 8 (
    echo [ERROR] ROBOCOPY に失敗しました(ERRORLEVEL=%ERRORLEVEL%)
    exit /b 1
)
echo デプロイ完了(ROBOCOPY)
endlocal
ROBOCOPYの終了コード(ERRORLEVEL)は特殊
ROBOCOPYの終了コードは 0〜7 が正常、8以上がエラーです。通常のコマンドと違い、0以外=エラー ではありません。if %ERRORLEVEL% geq 8 でエラー判定してください。

デプロイ前に自動バックアップを取る

本番環境へのデプロイ前には、現行ファイルのバックアップが安全です。日付付きフォルダに退避することでロールバックが容易になります。

@echo off
setlocal

set DEPLOY_DIR=C:\inetpub\wwwroot\myapp
set BACKUP_BASE=C:\deploy_backups

REM タイムスタンプ付きバックアップフォルダ名を生成
REM 例: backup_20250319_143022
for /f "tokens=1-3 delims=/" %%a in ("%DATE%") do (
    set YDATE=%%c%%a%%b
)
for /f "tokens=1-3 delims=:." %%a in ("%TIME: =0%") do (
    set YTIME=%%a%%b%%c
)
set BACKUP_DIR=%BACKUP_BASE%\backup_%YDATE%_%YTIME%

echo バックアップ先: %BACKUP_DIR%
robocopy "%DEPLOY_DIR%" "%BACKUP_DIR%" /E /NP
if %ERRORLEVEL% geq 8 (
    echo [ERROR] バックアップに失敗しました
    pause & exit /b 1
)
echo バックアップ完了: %BACKUP_DIR%

REM バックアップ成功後にデプロイ開始
echo デプロイ処理を開始します...
endlocal
バックアップは世代管理も検討する
上記のままでは古いバックアップが溜まり続けます。バックアップ後に古いフォルダを削除する処理を追加するか、世代数(5世代など)を超えたら削除する仕組みを組み込みましょう。詳しくはログローテーション完全ガイドの手法が参考になります。

ERRORLEVEL でエラー時に処理を中断する

各コマンドの結果を ERRORLEVEL で確認し、失敗したら処理を中断することが安全なデプロイの基本です。エラーが起きても次の処理が続行されてしまうのは危険です。

@echo off
setlocal

REM エラー時に即座に処理を中断するサブルーチン
:check_error
if %ERRORLEVEL% neq 0 (
    echo [ERROR] %~1 に失敗しました(コード: %ERRORLEVEL%)
    echo %DATE% %TIME% [FAIL] %~1 >> C:\deploy_logs\deploy.log
    pause
    exit /b 1
)
goto :eof

:main
cd /d C:\projects\myapp

git fetch origin >> C:\deploy_logs\deploy.log 2>&1
call :check_error "git fetch"

git pull origin main >> C:\deploy_logs\deploy.log 2>&1
call :check_error "git pull"

robocopy "C:\projects\myapp" "C:\inetpub\wwwroot\myapp" /MIR /R:3 /W:5 /NP /LOG+:"C:\deploy_logs\robocopy.log"
if %ERRORLEVEL% geq 8 call :check_error "robocopy"

echo [SUCCESS] デプロイ完了 %DATE% %TIME% >> C:\deploy_logs\deploy.log
echo すべての処理が正常に完了しました。
endlocal
goto :eof

call :main
:check_error サブルーチンでコードを簡潔に
各コマンド後に長い if 文を書く代わりに、エラーチェック専用のサブルーチンに切り出すとスクリプト全体がすっきりします。call :check_error "処理名" の1行で済み、どの処理で失敗したかもログに残ります。エラー処理の詳細はエラー時に処理を中断・終了する方法を参照してください。

サービス停止 → デプロイ → サービス起動 のフルフロー

IIS・Tomcat・アプリケーションサーバーなど、稼働中のサービスを止めてからデプロイする場面では以下のフローで安全に実行できます。

@echo off
setlocal

set SERVICE_NAME=W3SVC
set SRC=C:\projects\myapp
set DST=C:\inetpub\wwwroot\myapp
set LOG=C:\deploy_logs\deploy.log

echo [1/4] サービス停止: %SERVICE_NAME% >> %LOG%
net stop %SERVICE_NAME% >> %LOG% 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] サービス停止に失敗しました >> %LOG%
    pause & exit /b 1
)

echo [2/4] デプロイ開始 >> %LOG%
robocopy "%SRC%" "%DST%" /MIR /R:3 /W:5 /NP /LOG+:"%LOG%"
if %ERRORLEVEL% geq 8 (
    echo [ERROR] ROBOCOPYに失敗 - サービスを再起動します >> %LOG%
    net start %SERVICE_NAME% >> %LOG% 2>&1
    exit /b 1
)

echo [3/4] サービス起動: %SERVICE_NAME% >> %LOG%
net start %SERVICE_NAME% >> %LOG% 2>&1
if %ERRORLEVEL% neq 0 (
    echo [ERROR] サービス起動に失敗しました >> %LOG%
    pause & exit /b 1
)

echo [4/4] デプロイ完了: %DATE% %TIME% >> %LOG%
echo デプロイが正常に完了しました。
endlocal
デプロイ失敗時もサービスを必ず起動する
ROBOCOPY失敗時のエラーブロック内でも net start を呼んでいます。デプロイが失敗したままサービスが停止しているとサービス停止障害になるため、エラー時でも必ずサービスを再起動してから終了してください。サービス制御の詳細はWindowsサービス起動・停止の完全ガイドを参照してください。

引数でステージング/本番環境を切り替える

同じスクリプトをステージングと本番で使い回せるよう、引数(%1)で環境を切り替える構成が便利です。

@echo off
setlocal

REM 使い方:
REM   deploy.bat staging  → ステージング環境にデプロイ
REM   deploy.bat prod     → 本番環境にデプロイ

if "%1"=="staging" (
    set TARGET=\\staging-server\wwwroot\myapp
    set ENV_NAME=ステージング
) else if "%1"=="prod" (
    set TARGET=\\prod-server\wwwroot\myapp
    set ENV_NAME=本番
) else (
    echo 使い方: %~nx0 [staging^|prod]
    exit /b 1
)

echo ===================================
echo  デプロイ先: %ENV_NAME% (%TARGET%)
echo ===================================

REM 本番デプロイは確認を求める
if "%1"=="prod" (
    set /p CONFIRM=本番にデプロイします。続行しますか?[y/N]: 
    if /i not "%CONFIRM%"=="y" (
        echo キャンセルしました。
        exit /b 0
    )
)

robocopy "C:\projects\myapp" "%TARGET%" /MIR /R:3 /W:5 /NP
if %ERRORLEVEL% geq 8 (
    echo [ERROR] デプロイに失敗しました
    exit /b 1
)
echo [完了] %ENV_NAME%環境へのデプロイが完了しました。
endlocal
本番デプロイ前に確認ステップを挟む
set /p CONFIRM=... で確認を求めることで、deploy.bat prod を誤って実行した際の事故を防げます。「y」以外はキャンセルするため、エンターキーを押しただけでは実行されません。

ログ記録と管理の工夫

デプロイログは後から問題を追跡するための重要な情報です。タイムスタンプ・実行コマンド・終了コードを記録する習慣をつけましょう。

@echo off
setlocal

set LOG=C:\deploy_logs\deploy.log

REM タイムスタンプ付きでログに書く関数的な使い方
REM call :log "メッセージ"
goto :main

:log
echo %DATE% %TIME% %~1 >> %LOG%
echo %~1
goto :eof

:main
call :log "===== デプロイ開始 ====="

git pull origin main >> %LOG% 2>&1
call :log "git pull 終了コード: %ERRORLEVEL%"

robocopy "C:\projects\myapp" "C:\inetpub\wwwroot\myapp" /MIR /R:2 /W:3 /NP /LOG+:"%LOG%"
call :log "ROBOCOPY 終了コード: %ERRORLEVEL%"

call :log "===== デプロイ終了 ====="
endlocal
goto :eof
ログローテーション(古いログを自動削除)
ログファイルが溜まり続ける場合は、forfiles コマンドで古いログを自動削除できます。
forfiles /p C:\deploy_logs /m *.log /d -30 /c "cmd /c del @file"
(30日以上前のログファイルを削除)
詳しくはログローテーション完全ガイドを参照してください。

まとめ

バッチファイルで自動デプロイを構成する際のポイントをまとめます。

  • 設定変数(パス・サービス名)は先頭にまとめて保守しやすくする
  • 各コマンド後に ERRORLEVEL を確認し、失敗時は即中断する
  • xcopy は簡単・ROBOCOPY は高機能(差分・ミラー・リトライ)
  • デプロイ前に日付付きフォルダでバックアップを取る
  • サービス停止中にデプロイし、失敗時もサービスを必ず再起動する
  • 引数で環境(staging/prod)を切り替え、本番は確認を挟む
  • タイムスタンプ付きログを記録し、後から問題を追跡できるようにする

関連記事: バッチファイルでフォルダをコピーする方法 / Windowsサービス起動・停止の完全ガイド / WinSCPでSFTPファイル転送する方法

よくある質問(FAQ)

Qgit pull が「Permission denied」エラーになります。
ASSH鍵の設定が必要です。バッチファイルはシステムユーザーや別のユーザーとして実行されることがあり、鍵ファイルが見つからないケースがほとんどです。git config --global credential.helper wincred でWindows資格情報を使うか、SSHエージェントで鍵を登録してください。タスクスケジューラから実行する場合は「最上位の特権で実行」にチェックを入れ、同じユーザーのSSH設定を確認してください。
Qネットワークドライブ(\\server\share)へのコピーが失敗します。
Aバッチを実行するユーザーがネットワークドライブへのアクセス権を持っているか確認してください。タスクスケジューラ経由の場合、SYSTEMアカウントはネットワーク共有にアクセスできないことがあります。専用のサービスアカウントを作成してアクセス権を付与するか、net use \\server\share /user:USERNAME PASSWORD でマウントしてからコピーしてください。
Qデプロイ完了をメールで通知したいです。
Aバッチファイル単体ではメール送信は困難ですが、PowerShellと組み合わせると実現できます。powershell -Command "Send-MailMessage -To 'to@example.com' -From 'from@example.com' -Subject 'デプロイ完了' -SmtpServer 'smtp.example.com'"をバッチの最後に呼ぶか、Windowsタスクスケジューラの「完了時の操作」でメール送信を設定してください。
Q定時に自動でデプロイを実行したいです。
AWindowsタスクスケジューラに登録することで定期実行が可能です。「タスクスケジューラ」を開き、「タスクの作成」→「トリガー」で実行時刻を設定し、「操作」でバッチファイルのフルパスを指定してください。「ユーザーがログオンしているかどうかにかかわらず実行する」にチェックを入れるとログオフ中でも動作します。
Qデプロイ中にファイルが使用中でコピーできないことがあります。
Aアプリケーションが起動中にDLLや実行ファイルを使用しているとコピーできません。サービスを停止(net stop サービス名)してからコピーし、コピー後に再起動する手順が正攻法です。サービス停止が難しい場合はVSSシャドウコピー(vssadmin)を使う方法もありますが、設定が複雑です。詳しくはWindowsサービス起動・停止の完全ガイドを参照してください。