同期バッチ

webの開発で開発用のブランチと本番用のブランチを分けてきているときに、開発用ブランチで加えた修正を本番ブランチにコピーしたいときがあると思います。

たとえば、こんな感じ。。。

trunk は開発用です。trunk で開発、テストした結果をリリースするときに public にコピーしてコミットする。 public にコミットした内容は再度テストされ、大丈夫ならば、本番サーバにデプロイされるみたいな。

デプロイはおいといて、 trunk からどうやって、 public に上げるかなんですけど、手でコピーするのはメンドイです。

svn マージでやるのが正攻法なんでしょうけど、変更部分だけさくっとコピーしたかったので、 rsync を使ってやるバッチを作ってみました。

rsynccwrsync を利用しています。

@echo off
rem 作業ディレクトリ
SET SVN_MARGE_MOTO_DIR=trunk
rem 本番をあげるブランチ
SET SVN_MARGE_SAKI_DIR=public
rem rsyncコマンド
SET RSYNC_COMMAND="C:\Program Files\cwRsync\bin\rsync.exe"

rem まずは両者アップデート
TortoiseProc.exe /command:update /path:"%SVN_MARGE_MOTO_DIR%" /closeonend:2
TortoiseProc.exe /command:update /path:"%SVN_MARGE_SAKI_DIR%" /closeonend:2

echo.
echo.
rem コマンドと変更されるファイルの確認
echo %RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --dry-run --checksum --delete --exclude .svn
%RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --dry-run --checksum --delete --exclude .svn

echo.
echo 同期してもいいですか?
pause

%RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --checksum --delete --exclude .svn
TortoiseProc.exe /command:commit /path:"%SVN_MARGE_SAKI_DIR%" /closeonend:0
pause

goto :EOF

せっかくだから、いろいろ機能をつけてみました。
たとえば、 trunk で一部ファイルをいじってまだコミットしていないんたけど、一部のコミット済みのファイルは public にあげたいとかゆー場合です。


@echo off
rem 作業ディレクトリ
SET SVN_MARGE_MOTO_DIR=trunk
rem 本番をあげるブランチ
SET SVN_MARGE_SAKI_DIR=public
rem rsyncコマンド
SET RSYNC_COMMAND="C:\Program Files\cwRsync\bin\rsync.exe"
rem 可憐度ディレクトリの取得 よーするに pwd
SET BASEDIR=%~dp0

rem まずは両者アップデート
TortoiseProc.exe /command:update /path:"%SVN_MARGE_MOTO_DIR%" /closeonend:2
TortoiseProc.exe /command:update /path:"%SVN_MARGE_SAKI_DIR%" /closeonend:2

echo コミットしていないファイルを無視するためスキャン中...
SET IGNOREFILES=
rem 不要ならここをコメントアウト
for /F "delims=" %%i in ('dir /B /S /O:N %SVN_MARGE_MOTO_DIR%\*.*') do  (
	set line=%%i
	call :sub
)

echo.
echo.
rem コマンドと変更されるファイルの確認
echo %RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --dry-run --checksum --delete --exclude .svn %IGNOREFILES%
%RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --dry-run --checksum --delete --exclude .svn %IGNOREFILES%

echo.
echo 同期してもいいですか?
pause

%RSYNC_COMMAND% %SVN_MARGE_MOTO_DIR%/* %SVN_MARGE_SAKI_DIR% -rv --checksum --delete --exclude .svn %IGNOREFILES%
TortoiseProc.exe /command:commit /path:"%SVN_MARGE_SAKI_DIR%" /closeonend:0
pause

goto :EOF


:sub
	rem ディレクトリは無視する.
	if exist "%line%\\" goto :EOF

	rem SVNディレクトリは無視する.
	echo "%line%" | find "\.svn" 1> NUL 2> NUL
	if %ERRORLEVEL% == 0 goto :EOF

	rem ディレクトリとファイル名に分解する.
	call :dirname "%line%"
	SET dir=%_RESULT_%

	call :basename "%line%"
	SET filename=%_RESULT_%

	rem 相対パスに変換
	rem see http://soudan1.biglobe.ne.jp/qa4372316.html
	call set rfilename=%%line:%BASEDIR%%SVN_MARGE_MOTO_DIR%\=%%
	rem \ を / に変換する
	set rfilename=%rfilename:\=/%

	fc /b "%dir%.svn\text-base\%filename%.svn-base" "%line%" 1> NUL 2>NUL
	if not %ERRORLEVEL% == 0 (
		set IGNOREFILES=%IGNOREFILES% --exclude "%rfilename%"
	)
	goto :EOF

rem ファイルパス操作.
rem 出展元: http://darknessofthesun.blog114.fc2.com/blog-entry-49.html
:dirname
	rem 第一引数で指定されたディレクトリまたはファイルを含むディレクトリを返す。
	rem 末尾に\が付いている。Ex. C:\temp\, C:\
	set _RESULT_=%~dp1
	goto :EOF

:basename
	rem 第一引数からドライブレター、パスを取り除きファイル名(ディレクトリ名)のみを返す。
	set _RESULT_=%~nx1
	if ""=="%2" goto :EOF
	if "%~x1"=="%2" set _RESULT_=%~n1
	goto :EOF

実行してみると、結構遅いです。
ただ、がんばって作ったのではっときます。。。。
もうバッチファイルは暗黒なテクノロジーがたくさんあって、わけわかめ。。。