プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Git で過去のコミットのメールアドレスを修正する

GitHub の設定でprivateのメールアドレスでのコミットは受け付けないように設定しています。

が、既に過去に公開したリポジトリ(避難所検索@伊勢のリポジトリ)をよく見てみたら、どうもこの設定前にコミットしたらしく、メールアドレスとして private のメールアドレスがばっちりと載ってしまっていました。

本当はよくないのですが、forkとかはされていなかったので、過去のコミットのメールアドレスを変更することにしました。 clone してくれた方にはご迷惑をおかけしてしまいますが、平にご容赦ください。

ということで、その際の作業メモです。

変更方法

ちょっと調べると過去コミットのメールアドレスの変更方法は簡単に見つかりました。git filter-branch を使えという方法です。

version control - How to change the author and committer name and e-mail of multiple commits in Git? - Stack Overflow

なかでも、GitHub が変更用のスクリプトを公開してくれているので、それを利用することにします。

https://help.github.com/articles/changing-author-info/help.github.com

ここで紹介されているスクリプトの内容を rewrite というファイルに保存して実行権限を与えておきます。

変更作業

実際の作業は、上記リンク先の説明に従って進めます。

最初にローカル上に作業用リポジトリをクローンして、作成した rewrite スクリプトを実行して Author/Commiter の書き換えを行います。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ ./rewrite
Rewrite 5127723affae8988878905cd4c88826f1ffc4614 (59/61) (17 seconds passed, remaining 0 predicted)
Ref 'refs/heads/master' was rewritten
Ref 'refs/tags/1.0beta' was rewritten
1.0beta -> 1.0beta (5127723affae8988878905cd4c88826f1ffc4614 -> 03acac1d9dd4b51aaf193e740e7ca464a362f05a)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$

git log でログを表示させると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ git log
commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, tag: 1.0beta)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

commit 65016265bd4c026bdb20edf1bd50cf47a8921573
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:51:52 2017 +0900

    現在位置の最寄りの避難所を任意のタイミングで検索できる機能を追加

commit d37b76b2a5a76061fd06a42c210e24bbe8f0ab28
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:39:59 2017 +0900

    アプリバーがスワイプで消えてしまい、元に戻せないのを修正

確かに変更されています。

これで、問題ないかと思って、push すると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Counting objects: 889, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (217/217), done.
Writing objects: 100% (889/889), 3.12 MiB | 1.20 MiB/s, done.
Total 889 (delta 427), reused 830 (delta 427)
remote: Resolving deltas: 100% (427/427), done.
remote: error: GH007: Your push would publish a private email address.
remote: You can make your email public or disable this protection by visiting:
remote: http://github.com/settings/emails
To https://github.com/junichim/ShelterAtIse.git
 + 5127723...03acac1 master -> master (forced update)
 ! [remote rejected] 1.0beta -> 1.0beta (push declined due to email privacy restrictions)
error: failed to push some refs to 'https://github.com/junichim/ShelterAtIse.git'
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse$

のようにpushが失敗しました。

実は作業用リポジトリをクローンする際に、--bare オプションを付けていませんでした。なので、それが原因かと考え、一度ローカルリポジトリを消して、--bare をつけて再度実行してみます。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ ../rewrite
Rewrite 03acac1d9dd4b51aaf193e740e7ca464a362f05a (119/119) (32 seconds passed, remaining 0 predicted)
WARNING: Ref 'refs/heads/master' is unchanged
Ref 'refs/tags/1.0beta' was rewritten
1.0beta -> 1.0beta (5127723affae8988878905cd4c88826f1ffc4614 -> 03acac1d9dd4b51aaf193e740e7ca464a362f05a)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

で、pushします。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Counting objects: 1, done.
Writing objects: 100% (1/1), 150 bytes | 75.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
remote: error: GH007: Your push would publish a private email address.
remote: You can make your email public or disable this protection by visiting:
remote: http://github.com/settings/emails
To https://github.com/junichim/ShelterAtIse.git
 ! [remote rejected] 1.0beta -> 1.0beta (push declined due to email privacy restrictions)
error: failed to push some refs to 'https://github.com/junichim/ShelterAtIse.git'
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

相変わらず失敗します。何がまずいんだろうか?

しばらくあれこれ調べて考えていると、tag にも作成者があるんじゃないかな、と思い立ちました。

で、tagの情報を表示してみると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git show 1.0beta
tag 1.0beta
Tagger: mor <myprivate@email.address>
Date:   Fri Jul 7 15:30:58 2017 +0900


commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, tag: 1.0beta)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

(以下略)

当たりのようですね。tagのTaggerのところに、ばっちりprivateのメールアドレスが載ってました。

どうもこれが原因でpushに失敗していたようです。

tag の削除

tag も作成者(Tagger)が変更できるかと思って調べてみると、どうもtagについてはできないようです。 ということで、諦めて、tagについてはローカルおよびリモートで削除します。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git tag -d 1.0beta
Deleted tag '1.0beta' (was dbd1930)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --delete origin 1.0beta
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
To https://github.com/junichim/ShelterAtIse.git
 - [deleted]         1.0beta
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

そのあとに再度、pushします。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$ git push --force --tags origin 'refs/heads/*'
Username for 'https://github.com': junichim
Password for 'https://junichim@github.com':
Everything up-to-date
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/test4/ShelterAtIse.git$

問題なくpushできたようです。

最後に改めてタグを振って完了です。

振り返り

さて、上記に書いたように試行錯誤しながらいろいろとやりましたが、あとから表示されたログをよく見るとやっと状況がわかりました。

どうも最初の git push --force の段階で、masterブランチのpushは完了しており、各コミットの Author/Commiter は書き換えられて、tag の push(のみ)失敗したということのようです。 というのも、上記の途中でベアリポジトリをクローンして作業していると思いますが、rewrite しても master ブランチは書き換えが起こっていません。

つまり、この作業時点では、 Author/Commiter の書き換えのpushが失敗したと思っていたのですが、(リモートリポジトリの)状態としては、各コミットの Author/Commiter は書き換えられ、古いコミットに紐づいている tag が残っているという中途半端な状況になっていたようです。

たまたま確認用にこのタイミングでリモートリポジトリをクローンして、ログを見ていたのですが、それを見ると

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/check/ShelterAtIse$ git log
commit 03acac1d9dd4b51aaf193e740e7ca464a362f05a (HEAD -> master, origin/master, origin/HEAD)
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

commit 65016265bd4c026bdb20edf1bd50cf47a8921573
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:51:52 2017 +0900

    現在位置の最寄りの避難所を任意のタイミングで検索できる機能を追加

commit d37b76b2a5a76061fd06a42c210e24bbe8f0ab28
Author: junichim <junichim@users.noreply.github.com>
Date:   Fri Jul 7 10:39:59 2017 +0900

    アプリバーがスワイプで消えてしまい、元に戻せないのを修正

のようにAuthorが変更されていますが、タグについては、

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/tmp/check/ShelterAtIse$ git show 1.0beta
tag 1.0beta
Tagger: mor <myprivate@email.address>
Date:   Fri Jul 7 15:30:58 2017 +0900


commit 5127723affae8988878905cd4c88826f1ffc4614 (tag: 1.0beta)
Author: mor <myprivate@email.address>
Date:   Fri Jul 7 11:10:53 2017 +0900

    署名付きapk作成時にファイル名を自動で設定する処理を追加

(以下略)

と private のメールアドレスを持ち、Author変更前のコミット(ハッシュ値 5127723)を指していました。

Author変更スクリプトに書かれている git filter-branch のオプションを調べると --tag-name-filter cat は tag を新しいコミットに付け替えてくれるというオプションのようです。実際、作業途中で git show 1.0beta とタグの情報を見たときには、tagのメールアドレスはprivateのものですが、指しているコミットはAuthor更新後のもの(ハッシュ値 03acac1)となっていました。

で、最後にリモートからタグを消したことでこの状態が解消したんだと思います。

GitHub の設定で private メールアドレスのコミットを禁止しているので、ローカルでは tag 自体は新しいコミットを指すように付け替えられたけど、pushができなかったので、リモート上の tag は古いコミットを指しているままという、こんなややこしい状況になったんでしょうね。

まとめ

というわけで、

  • 過去コミットのメールアドレスを変更する際に、
  • GitHub の private アドレスのコミット禁止設定をしている場合は、
  • 最初から tag を消しておいて、
  • Author/Commiter の変更作業をする

というのが無難なようです。

表示されるメッセージはちゃんと読め、ということですね。あー、めんどくさかった。

Twilio FAX 送信をもうちょっと使いやすくした

以前、 Twilio で FAX 送信を試した記事を書きました。

blog.mori-soft.com

ですが、fax 送信の度にさくらのレンサバにファイルをアップロードして、curlをたたいて、というのはさすがに不便なので、一連の処理をスクリプトにして、もうちょっと使いやすくしてみました。

ということで、備忘録代わりのメモ書きです。

作成したスクリプト

さて、上記の記事ではさくらインターネットのレンタルサーバーに、送信したい FAX 原稿(PDFファイル)をアップロードして、そのURLを指定して Twilio で送信するという手順になっていました。

なので、スクリプトは

  • fax送信 : faxSend
  • アップロード : faxRawUpload
  • (アップロードしたファイルを使って)FAXを送信 : faxRawSend
  • 送ったfaxのステータス確認 : faxStatus

の4つから構成しました。実際にユーザーが使うのは faxSend と faxstatus の2つだけになります。

とりあえず完成したものをGistに上げておきます。

コマンドラインで Twilio の FAX 送信を行うスクリプトのサンプル · GitHub

気になった点を順に説明しておきます。

faxRawUpload : アップロード用のスクリプト

アップロード用のスクリプトでは scp を利用してPDFファイルをアップロードします。 ただ、普通に scp で接続するとパスワードを聞かれるので、これを回避するために公開鍵認証を使います(パスワード直書きはなるべく避けたい)。

公開鍵認証で接続するため、サーバー側の ~/.ssh/authorized_keys に公開鍵を設定しますが、その際に、

no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,
command="if [[ ${SSH_ORIGINAL_COMMAND} =~ ^scp[[:space:]]-t[[:space:]]target/$ ]]; then ${SSH_ORIGINAL_COMMAND}; else echo Access Denied.; fi",
 ssh-rsa AA・・・
(改行を入れていますが、実際は1行です)

のように command を指定して実行可能なコマンドを制限しておきます。

なお、$SSH_ORIGINAL_COMMAND にはクライアント側で指定したコマンドが入ります。ただ、 scp の場合はどうもクライアント側で記述したコマンドそのものが入るのではなく、-t や -f といった隠しオプションを使ったサーバー側のコマンドに変換されているようです。

上記の記述の場合、渡されたコマンドが

scp -t targetdir (コピー先がtargetdir)

であれば、scpコマンドを実行して、それ以外ならメッセージを出して終了するというものになっています。

参考
余談

なお、最初は sftp のバッチモードを使おうとおもったのですが、よくよく考えたら、scpで事足りるのでそれを採用しました。 参考にしたリンク張っておくので、ご興味ある方は試してみてください。

faxRawSend : 送信(のみ)のスクリプト

次にアップロードしたPDFファイルを使って、Twilio のAPIをたたいて送信するスクリプトです。

APIの呼び出しは以前の記事と同じです。

APIの戻り値が json で返ってきますので、 jq を使って必要な情報(ステータスとfaxsid)だけ出力するようにしています。

しかし、bashでjsonを扱うのに jq なんて便利なものがあるんですね。ありがたい、ありがたい。

faxSend : 送信スクリプト

これがユーザーが呼び出す送信スクリプトになります。

引数をチェックして、内部で faxRawUpload, faxRawSend を呼び出すだけです。

faxStatus : ステータス確認

FAX送信APIをたたくと結果はすぐに帰ってきますが、実際にFAXが送られるまでは少しタイムラグがあります。 そこで、送信時に得られる faxsid を使って、ステータスを問い合わせて、いまどういう状態になっているか確認できるようにしておきます。

ステータスには

  • queued
  • sending
  • delivered

などがあります。詳しくは、下記のリンク先の status の説明をご覧ください。

jp.twilio.com

まとめ

突貫で作ってみたのですが、上記のスクリプトを使うと、FAX送信と送信結果の確認が結構簡単にできるようになりました。これなら、FAX送信の頻度が少ないうちは十分使えそうです。

まあ、本当は Web アプリでも仕立てて、送ったFAXのステータスをGUIで確認するようにすればなおいいのでしょうが、フレッツ光の光電話代をいかにお安くできるか?というのが今回の動機なのでとりあえずはこれでいいかなと思っています。

にしても、 Twilio で遊ぶと結構楽しいです。 次のネタないかなー。

自宅のLANケーブル配線について

いろいろあって、昨年末から一戸建てに住むことになりました。

で、IT系の仕事をしているはしくれとして、せっかく家を建てるなら、各部屋にLAN配線を行いたいと思うのが人情です。まあ、昨今は無線LANというものもありますが、今一つ信頼していないので、有線を引きたいと思った次第です。 配線自体は電気屋さんに相談したら、二つ返事でできますよ、とのこと。

ただ、LANの規格も日進月歩なんで、いまの1ギガビットイーサ(1000BASE-T)なんて何年かしたら遅いよ、というふうになるかもしれません。 なので、少なくとも現時点で見えてきている、10ギガビットイーサ(10GBASE-T)には対応できるようにしたいと思います。

はて、どうすればよいだろうか?

というわけで、いろいろと調査したことをメモっときます。

規格

10GbEというとカテゴリー7のケーブルがいるのかな?と漠然と思っていたので、まずはLANケーブルの規格を改めて調べてみました。 詳しくは、下記のリンク先などを見てもらえればよいかと思います。

【10GBASE-T、ついに普及?】CAT5/CAT5eの利用を断念 CAT6/6A/6e/7のみサポート【期待のネット新技術】 - INTERNET Watch

10GbE時代を見据えると家庭内LANケーブルはCat 6?Cat 7?色々調べて買ってみた | TeraDas

で、これらを踏まえて結論からいうと、10Gに対応するためには、カテゴリー6、6A(6E)、7あたりのケーブルを使う必要があるようです。

6Eは6Aとほぼ同等だけど、メーカー等の独自規格のようです。 カテゴリー6は37m以内(場合によっては55m以内)なら、10GbEでもいけるとのこと。それ以上の距離が必要なら6Aまたは7が必要。

カテゴリー7は、STPが基本で、ケーブルもシールドされていて、コネクタもRJ-45と互換性があるとはいえ、別規格。何より、シールドのアースを取る必要があるとのことでした。

採用したのはカテゴリー6

最初は、せっかくなのでカテゴリー7のケーブル引いて、とか夢想してましたが、上記を詳しく調べるにつれて、(少なくとも現時点では)こりゃ家庭内LANで採用なんてできないなという印象に変わりました。

反対に、ケーブル長が短ければカテゴリー6でも十分ということがわかりました。

家の建設現場に出向いて電気屋さんに聞いてみると、今回の配線だとスイッチングハブを設置する場所から一番遠いところでも11~12m程度を見ておけばよいとのこと。 壁に出てくる端子にケーブルをつなぐことを考えても、十分37m以下に収まります。

しかも、カテゴリー6のケーブルならこの電気屋さんが持ってるので、こちらで調達して支給しなくてもよいとのことでした(カテゴリー6Aのケーブル購入して、引き回してもらおうかとも考えたのですが、実質的にあまり意味がなさそうなのでやめました)。

ということで、一応将来的に10Gのイーサネットがやってきても対応できるようになったはずです。

これで対応する日が楽しみです。

ちなみに

光回線を引こうとおもったら、周辺の建物の関係上なんと電柱を立てないと引けないということがわかりました。

ということで、人生で初めて電柱立てました(自分のじゃないですけどね)。

f:id:junichim:20190122113430j:plain

追記

あと、10GBASE-Tとは少し違いますが、既存のケーブルで、2.5G/5Gを実現する規格(IEEE 802.3bz)というのも登場してきているようです。

gigazine.net

こっちのほうが既存のインフラ(ケーブル)を流用できるので普及は早そうですね。