mk-toolブログ

エンジニアと家のことをごちゃごちゃと書いてます

PullRequestの差分が正しく出ない

PullRequestの差分が正しく出ない問題に遭遇しました。 それぞれのブランチが全く同じ内容のファイルなのにもかかわらず、です。

PullRequestの差分が正しく出ない理由は、新しく作ったブランチとtargetブランチのcommitIdが異なることに原因がありました。 (私の場合、原因は100%これにありました)

ここでは、新しく作ったブランチをdevelopとして、targetブランチをmainとします。 気をつけたほうが良い作業は、cherrypickやhotfix作業が挙げられますが、それ以外の場合でもこれを理解していれば解決の助けになるかもです。 PullRequestはcommitをもとに差分が比較されます。「commitをもとに差分が比較される」です。 何を言いたいかというと、commit自体が「ソースコードの差分」を持っているわけではありません。

コミットはスナップショットであり差分ではない - GitHubブログ

commitはスナップショットであり、PullRequestが差分を計算する際は、新しく作ったブランチとtargetブランチのcommitのスナップショット同士が比較されます。 さて、cherrypickやhotfixを行うとmainブランチには、developブランチにはないcommitが作成されます。

cherrypickは、developにあるcommitをmainブランチに持っていく作業のように見えますが、厳密にはdevelopブランチとmainブランチのcommitIdは異なります。

git log

でcommitIdを見てみるとわかります。 「新しく作ったブランチとtargetブランチのcommitのスナップショット同士が比較されます」と先ほど言いました。developブランチには無いcommitがmainブランチに存在した場合、それは比較対象から外れます。

表を作りました。commitId4にいくらcommiId3と同じソースコードが存在したとしても、developブランチが比較できるのはmainブランチのcommitId2までです。いくらmainブランチのHEADがcommitId4でもdevelopブランチの中にcommitId4の情報がないので比較ができません。 そのため、同じ内容のファイルなのに差分が正しく出ない問題が起きます。

develop      | main
commitId5 |
                   | commitId4
commitId3  |
commitId2 | commitId2
commitId1 | commitId1

これは、developブランチをrebaseすればなおります。rebaseは、developブランチにmainブランチの変更を取り込むことを意味します。

git checkout main
git pull
git checkout develop
git pull
git merge main

取り込むと先ほどの表は以下のようになります。 以前は、PullRequestの比較対象はmainブランチのcommitId2でしたが、commitId4が比較対象に含まれました。commitId4はcommitId3と同じソースコードを持つため、「commitId4にいくらcommiId3と同じソースコードが存在したとしても差分として出てしまう」といった問題がこれで解消されます。

develop      | main
commitId5 |
commitId4 | commitId4
commitId3  |
commitId2 | commitId2
commitId1 | commitId1

解決方法は単純ですが、なぜそうなるかを知っていれば、自信を持ってリリース作業を行えますね。

masterブランチにcommitしたという濡れ衣

本当にあった怖い話、何かを知っていれば全く怖くない話。

masterブランチ(masterとかmainとか、とりあえずその辺の名前)に直接commitしていないのに、直接masterにcommitしましたよね?、という問い合わせ。 確かに git log でAuthorを見てみると、Authorは自分になっている。。。 でも私はそんなにバカではないはず、、、なのに git log がそう言っているなら私は何も言い返せない、、、という状況になった。

実はこれ、リリース時にcherrypickされてリリースされていた。cherrypickをすると、

そのcommitは同じcommitメッセージで同じAuthorでmasterブランチに直接新しいcommitが作成される

という事態になる。 ただ、cherrypickをすると、committerはcherrypickした人の名前になるため、committerを表示すれば「私じゃありません!!」と証明することができる。

git log --pretty=format:"[%ad] %h %an : %s: %cn"

(参照:https://qiita.com/harukasan/items/9149542584385e8dea75)

困ったことに、 git log や SourceTree ではAuthorしか出ないので、このような怖い話になる。

この情報に至れなかった人は「masterに直接commitしちゃったヤバい人」みたいな状態になるのかな。。。

Dockerコンテナ内からlocalhostのmysqlへの接続ができない

hostアドレスに docker.for.mac.host.internal を設定するとうまく動く。

hostのIPアドレス/sbin/ip route|awk '/default/ { print $3 }' のように取得できるが、それを使ってもコンテナ内からmysqlへの接続はできなかった。 (が、host のIPアドレスを使ってcurlを実行しても問題なく動くので、それが問題をよりややこしくする)

mysql -u xxx -h 127.0.0.1 -p -P 33066

moment.jsで東京の時刻をISO形式で表示

いくら、timezoneを東京に設定しても、ISO形式での表示はUTCになるな〜、と思って調べたら、引数に true を入れなければいけなかったみたい。

momentjs.com

const moment = require('moment-timezone')
moment.tz.setDefault('Asia/Tokyo')
const date = moment(new Date())
console.log(`${date.toISOString(true)}`)

CloudStorageとのCORSを解消する

手順

  1. Cloud SDK を install
  2. 既存の設定を取得する
  3. cors対策用のファイルを作成
  4. デプロイ
  5. 設定が書き換わっていることを確認

詳細

1. Cloud SDK を install

Cloud SDK Command Line Tools  |  Cloud SDK: Command Line Interface

2. 既存の設定を取得する

gsutil cors get gs://BUCKET_NAME

3. cors対策用のファイルを作成

touch cors.json

そして、2で取得した既存の値を入れる。 それに加えて、新しく追加したいドメイン名を加える。

4. デプロイ

gsutil cors set cors.json gs://BUCKET_NAME

5. 設定が書き換わっていることを確認

gsutil cors get gs://BUCKET_NAME