https://github.com/uu59/zerotax
違い
Chrome dev版でしか試してないけどFirefoxとかでもいけると思う。
まずバイト初日、サーバに入れるようになったあと、scpとrsyncを適当に使って指示された変更に関係しそうなファイルをダウンロードします。だいたい揃ったらgit init; git add -A; git commit -m "ファイル取ってきた(noedit)"でとりあえずの体制は構築できました。
ここから開発を進めていくわけですが、色々と難関があります。
git diffが文字化けして使えないlvやnkfにパイプしても、そもそも異なる文字コードの文字列が混在してるのでどうしようもありません。これを解決するにはdiff.externalを設定して、ファイルごとに自前でdiffを取ります。
$ cat ~/mydiff.bash
#!/bin/bash
old=$2
new=$5
# バイナリは無視
if [ -n "`file -b --mime ${new} | grep text/`" ];then
# 最後の | catがないとdiff external diedとか言われる
# 普段は`colordiff`でもいいけど git diff > foo.diffとかすると制御コードが入ったままなので注意
diff -Naub <(lv $old) <(lv $new) --label $old --label $new | cat
fi
$ git config diff.external $HOME/mydiff.bash
$ git diff
ちゃんと出る
普通のgit diffより体感できるくらい遅いですが背に腹は代えられないので仕方ないです。git log -pなどgit diff以外のところでは化けますが、これも諦めます。
このmydiff.bashは後でまた活用します。
変更によっては5つも6つもアップロードしないといけないわけで、これを手作業でやってればいずれ必ずミスをします。なので自動化しましょう。
$ cat ./upload-changed-files.bash
#!/bin/bash
git status --porcelain | awk '{print $2}' | xargs -n1 -I% -t scp % server:/path/to/root/%
$ .. 何か作業 ..
$ ./upload-changed-files.bash
(git statusで検知できる)変更されたファイルが一括でアップロードされる
git statusよりfind . -mtime -1を使ったほうがよさそうに見えますが、gitの管理下にない=プロジェクトに関係のないファイルがアップロードされる可能性があるのでやめました。rsyncも同様の理由で却下です。
変更する→アップロード→やっぱりなかったことにする、のときにやや不便ですが、空行を追加したりgit reset --soft HEAD~などとしてgit statusに検知させるか、そのファイルだけ手でscpすれば必要充分だったのでこれでいいです。
どうせgitと連携するのならgit-前のコミットから触ったファイルを全部サーバにアップロードするとかgit-助けてみたいなサブコマンドを作ってもよかったわけですが、一応お仕事なので面白みのない解決にしました。
VCSが有効に使われてれば各自がgit logしてくれればいいわけですが、そういう環境ではないので変更箇所をまとめて報告してと言われます。作業内容というよりももっとミクロな、どのファイルのどこをどう触ったか、という情報が必要なのでgit log --since="1 day ago" > $(date +%F).txtじゃダメです。git log -pにしても先述のように文字化けするのでダメです。
仕方ないので以下のようなスクリプトを書いてレポートを生成するようにしました。
$ cat ./report.sh
#!/bin/bash
DIR=$(cd $(dirname $0); pwd)"/reports"
HASH=$1
YMD=$(git log $HASH -1 --format='%ai' | awk '{print $1}')
FILE=$DIR/$YMD.txt
echo >> $FILE
echo "============================================" >> $FILE
git log -1 $HASH >> $FILE
git diff $HASH~..$HASH | lv >> $FILE
echo >> $FILE
$ mkdir reports
$ git rev-list master | xargs -n1 ./report.sh
reports/yyyy-mm-dd.txt に作業内容とdiffが保存される
$ git rev-list --since="1 day ago" master | xargs -n1 ./report.sh
今日1日の作業だけ出す
これでgitを使わなくてもgit log -p相当の情報が見れます。
レポートを作っただけじゃあれなので、ファイルサーバに提出するところまで自動化しておきます。
$ cat ./report-send.sh
#!/bin/bash
# レポート生成
rm -rf ./reports
mkdir ./reports
git rev-list master | xargs -n1 ./report.sh
# ファイルサーバに置く
smbclient -t cp932 -U user '//sharedserver/' "password" -D '/path/to/myarea' -c "prompt;recurse;mput reports/"
# reports-YYYY-MM-DD.zipも作って置く
zip -r reports-`date +%F`.zip reports/
smbclient -t cp932 -U user '//sharedserver/' "password" -D '/path/to/myarea' -c "prompt;recurse;mput reports.zip"
echo お疲れ様でした
$ ./report-send.sh
お疲れ様でした
レポート生成関連はプロジェクトのreportブランチで管理し、git rev-list masterとすることでプロジェクト本体の変更とは切り離して運用します。完全に分けてもよかったんですが、適当なところにディレクトリを作るよりは適当なブランチを作ったほうが楽な気がする、という理由でこうなっています。
ちなみに自分が変更してないファイルをリポジトリに追加するときはコミットメッセージに”noedit”とつけていますが、if [ -z "$(git log --oneline $HASH | grep noedit)" ];then exit 0;fiのような処理を追加すれば純粋に自分がやった変更だけをレポートに出すことも可能でしょう。今のところそこまで要求されてないので(というか元々誰がいつどこを変更したのか追えてないので)、特にチェックしていません。
修正を始める前に以下のようなスクリプトでサーバのファイルをチェックしてから変更するようにします。
$ cat scp-diff.bash
#!/bin/bash
FILE=$1
colordiff -Naub <(ssh server "cat /path/to/root/$FILE") <(cat $FILE) | lv -c
echo -n "upload or download? (u/d)"
read INPUT
case "$INPUT" in
"d")
scp server:/path/to/root/$FILE $FILE
;;
"u")
scp $FILE server:/path/to/root/$FILE
;;
*)
;;
esac
$ ./scp-diff.bash foo/bar/baz.php
手元のbaz.phpと現在サーバにあるbaz.phpのdiffが見れる
lvを閉じるとアップロードするかダウンロードするかきいてくる。必要なければC-cで終わる。
gitで管理してるので、うっかり先にファイルを編集したあとサーバのファイルが置き換わってることに気づいても大丈夫。
$ ./scp-diff.bash foo.php
見たことないdiffが出てくるな。変更されてたのか。
$ git add -A; git commit -m tmp
$ ./scp-diff.bash foo.php
ダウンロード
$ git add -u; git commit -m "誰かの変更を適用(noedit)"
$ git rebase -i HEAD~2
# tmp と 誰かの変更を適用 の順番を入れ替える(先に誰かの変更を〜をコミットしたかのようにする)
pick 987abcd tmp
pick abcd123 誰かの変更を適用(noedit)
$ git reset --soft HEAD~
$ git status --cached
さっきの編集途中のやつが出てくる
作業する前にrsyncあたりでサーバのファイルと同期できれば理想的ですが、–excludeしにくい場所にGB単位でログファイルが散乱していてどうしようもないので半自動な感じになっています。
知らない間に変更されてるかどうかは最初に一度チェックすればいいので、以降は変更ごとに上に書いた一括アップロードスクリプトを走らせます。
快適とは言いがたいですが何もしないよりはマシです。
なんかほとんどbashスクリプトお披露目会みたいになりましたが、メンバーの誰もgit(というかバージョン管理)を使っておらず、コードベースも古く、まともなデプロイも期待できないような環境であってもgitは使えるし使えば便利だということが伝わればいいです。
Part 1とか言ってますがPart 2の予定は未定です。
お金がなくなりそうなので某所でプログラミングのバイトをしています。そこでは2000年代初頭に書かれたPHPスクリプト群が特にリファインされずに使われ続けており、また開発体制も昔ながらのまま維持されています。VCS(gitとか)とITS(Tracとか)とテスト(ユニットテストやCIなどの自動化されたテスト)のサポートに慣れきった身には辛い環境です。
まずVCSがないので誰かが自分の知らない間にファイルを変更していたり、変更箇所や理由や履歴が追えなかったりそもそも誰がやったのかすらわからなかったり、「hogehoge.phpアップしました」「はい」といった謎の通信が発生したりなどの弊害があります。GW明けに来てみたら以前に追加した機能がなぜか削除されていたのでオフラインで探偵ぽいことをしたりもしました。
ITSがないので要望やらバグ報告やらが各人からばらばらに提出されており、また作業の進捗も担当者も作業者以外には絶対にわからないようになっています。要望は専用のメールアドレスにメールで送り、それを受信する人(受信係)が紙に印刷し、その紙を見て自分が作業し、作業が終わると適当にペンでチェックを入れ、すべて完了したらメール係と発案者に報告し、そこから仕様変更やバグ修正などがあれば発案者に直接御用聞きしにいき、完了ということになれば紙を破棄する、といったワークフローです。当然上に挙げたように与り知らない変更が発生してたり、同様の要望が複数の発案者から挙げられたり、メールを通さない非正規ルートでの依頼(発案者→自分)があったり、互いに矛盾する要望が来て発案者AとBの間に立って仲介したりするわけで、機能そのものは3分で追加できるのにそれ以外の部分で数時間、または関係者不在により数日かかることも多々ありました。不経済な話です。
そしてユニットテストやCIといった自動化されたテストもないため、変な挙動をしている部分がわざとなのかバグなのか判断できないことも多かったです。似たようなことをしてるけどなんで片方はhtmlspecialcharsを通してるのにもう一方は通してないのか、コードと人間の双方から調べてみた結果、生のまま出力してるほうは「HTMLをそのまま出す版」だったらしいのでバグではなく仕様らしい。また自分がそこに関連する部分を変更するときはこれを意識しておかないとどっちもエスケープしてしまうバグを作ってしまうので注意しなければならない。など。
基本的にプロジェクトというものは運用期間が長くなるにつれ開発そのものより政治的判断の比重が大きくなるのは避けられないと思っているので、雑用が多い分にはまあ仕方ないかなという気持ちがあって特に不満とかではないです。また一時的な雇用契約というのは互いに充分認識しているので、「.svnってフォルダがいっぱいあって邪魔なので消したった」という発言を聞いても「そうですか」くらいの感想しかないです。
しかしながら、その少ない開発部分においてgitもRedmineもPHPUnitも使えないのは非常にストレスフルです。gitがなければ変更するごとにバックアップを取る必要があるし、Redmineがなければ自分のタスク管理や意見調整に手間暇を取られるし、テストがなければ不安に苛まれて祈るしかありません。これはよくない。かといってネイティブ在籍しているプログラマ2名にバージョン管理を教えたり、関係各位にRedmineを布教するとなるとバイトの領分を超えてるわけで、そこに会社が金銭を払うのもおかしな話ですし無償でやる気もありません。自分がVCS/ITS/テストがなくて不安なら、自分だけで解決しましょう。
というわけで前置きはこれくらいにして、gitで管理されてないプロジェクトを私的にgitで管理した話をします。
他の人がもっと詳しくわかりやすく書いてるので設定手順などは省略。自分用に用途・感想・懸念事項などをメモしておく。
/bin/cat <<_EOT_ | /sbin/iptables-restoreで適用するようにした。ファイル分けなくていいので管理が楽。logs.group_by{|a| a.status}とかで適当に集計できる。便利なのか不便なのかはっきりしない。
dig @210.224.163.3 aaaaa.blog.fc2.comとかしてみたけど100ms程度でいけた。でもたまにキャッシュされないのか3回やって3回とも100msだったり(ttlも86400から減らない)、かと思えば5回目くらいから常に0msで返ってきたり(ttl減る=キャッシュ済み)といまいちよくわからない。少なくとも数秒かかるようなことはなかった。