作業ノート

様々なまとめ、雑感など

gitでトピックブランチをマージ中にリモートブランチが更新されたときの対応

例えば自分の環境で

$ git merge --no-ff feature/add-c

トピックブランチをmasterブランチにマージして

$ git push
error: failed to push some refs to '********'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

pushしても、できなかったときの対応。

$ git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0
Unpacking objects: 100% (3/3), done.
From ********
   baf2594..2d4f9f4  master     -> origin/master

fetchしてリモートブランチと同期をとり

$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 2 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean

statusを確認すると、masterブランチとリモートブランチが分岐した状態になっている。

ここでは、自分の環境はトピックブランチ(feature/add-c)をマージした状態で

$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
*   5361769 - (HEAD -> master) Merge branch 'feature/add-c' (2 minutes ago) <te2u>
|\
| * f3fbe42 - (feature/add-c) add c (3 minutes ago) <te2u>
|/
* baf2594 - add a (17 minutes ago) <te2u>

リモートブランチは別のトピックブランチ(feature/add-b)をマージした状態とする。

$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative origin/master
*   2d4f9f4 - (origin/master) Merge branch 'feature/add-b' (14 minutes ago) <te2u>
|\
| * ec63e2a - add b (16 minutes ago) <te2u>
|/
* baf2594 - add a (18 minutes ago) <te2u>

メインブランチにトピックブランチ以外のマージを作るのは避けたいのでrebaseしたいところだが、ここで

$ git rebase origin/master
First, rewinding head to replay your work on top of it...
Applying: add c

そのままrebaseすると

$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
* 0f50808 - (HEAD -> master) add c (23 seconds ago) <te2u>
*   2d4f9f4 - (origin/master) Merge branch 'feature/add-b' (16 minutes ago) <te2u>
|\
| * ec63e2a - add b (18 minutes ago) <te2u>
|/
* baf2594 - add a (20 minutes ago) <te2u>

自分の環境で作成したマージコミットが失われてしまう。

マージコミットが失われないようにするには、rebaseするときに

$ git rebase --preserve-merges origin/master
Successfully rebased and updated refs/heads/master.

preserve-mergesオプションをつけて実行する。こうすると

$ git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
*   93ab538 - (HEAD -> master) Merge branch 'feature/add-c' (11 seconds ago) <te2u>
|\
| * d3dedd9 - add c (11 seconds ago) <te2u>
|/
*   2d4f9f4 - (origin/master) Merge branch 'feature/add-b' (19 minutes ago) <te2u>
|\
| * ec63e2a - add b (20 minutes ago) <te2u>
|/
* baf2594 - add a (22 minutes ago) <te2u>

リモートブランチのHEADに、自分の環境でマージしたときのブランチが残った形で適用される。あとは

$ git push
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 317 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To ********
   d8219f9..2bb1372  master -> master

pushして、リモートブランチを更新する。

PHPのfor文で、配列の数を評価するときの違いによるベンチマークを取ってみた

きっかけは仕事でコードレビューをしていたときに、以下のようなfor文をみたこと。

for ($i = 0, $count = count($data); $i < $count; $i++) {
    // 何らかの処理
}

$countはfor文の条件判定でしか使用されていなかったので、そのときは変数を使わずに直接書けばいいのにと思った。

for ($i = 0; $i < count($data); $i++) {
    // 何らかの処理
}

一方でそれぞれのパフォーマンスが気になったので、模したコードで確認してみた。

確認環境のOSはCentOS 7.1。

$ cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

phpは5.6.11。

$ php -v
PHP 5.6.11 (cli) (built: Jul 12 2015 20:13:00)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies

ベンチマーク取得のコードは下記のエントリーのコードを使用した。

d.hatena.ne.jp

実際に書いたコード。

以下は実行結果の一つ。

$ php bench_count.php
1
$count          :     0.0000 sec   @ 0.0000 sec (336.00%)
count()         :     0.0000 sec   @ 0.0000 sec (100.00%)
1
$count          :     0.0000 sec   @ 0.0000 sec (100.00%)
count()         :     0.0000 sec   @ 0.0000 sec (123.53%)
10
$count          :     0.0000 sec   @ 0.0000 sec (100.00%)
count()         :     0.0000 sec   @ 0.0000 sec (160.17%)
100
$count          :     0.0003 sec   @ 0.0000 sec (100.00%)
count()         :     0.0004 sec   @ 0.0000 sec (165.26%)
1000
$count          :     0.0027 sec   @ 0.0000 sec (100.00%)
count()         :     0.0048 sec   @ 0.0000 sec (180.65%)
10000
$count          :     0.0277 sec   @ 0.0000 sec (100.00%)
count()         :     0.0454 sec   @ 0.0000 sec (163.59%)
100000
$count          :     0.2720 sec   @ 0.0000 sec (100.00%)
count()         :     0.4506 sec   @ 0.0000 sec (165.69%)
1000000
$count          :     2.7292 sec   @ 0.0000 sec (100.00%)
count()         :     4.5232 sec   @ 0.0000 sec (165.73%)

1回から1000000回まで、実行回数を変えてそれぞれのパフォーマンスを相対的に確認する。 1回実行のテストを2回行っているのは、その内容に関わらずどうしても最初に実行したテストが遅くなったため。

何回か確認したが関数を毎回評価する方が遅く、その差は大体1.2倍から2倍ほど。 変数に比べて関数の方が遅いのは予想していたものの、相対的に見てここまで差があると変数にしたいのもわかる。

参照整合性制約で参照されるテーブルから、定義したテーブルと制約名を取得するSQL

以下はFOOテーブルのカラムを参照するテーブルと制約名を取得するSQL。

SELECT
    uc.table_name,
    uc.constraint_name
FROM user_constraints uc
JOIN user_constraints ruc ON
    ruc.owner = uc.r_owner AND ruc.constraint_name = uc.r_constraint_name
WHERE
    uc.constraint_type = 'R' AND ruc.table_name = 'FOO'
;

使用するのはuser_constraintsビュー。

constraint_typeRとなっているのが参照整合性制約の定義。これは該当テーブル名と制約名、参照先テーブルの一意制約名からなる。

参照整合性制約の定義を取得するビュー(uc)と、参照先の一意制約の定義を取得するするビューを(ruc)内部結合して、該当の定義を取得する。

参考