Tech Racho エンジニアの「?」を「!」に。
  • 開発

Gitで巨大プロジェクトを扱うときに少し便利なupdate-ref

ビルドに時間がかかる(数十分~数時間以上)プロジェクトを扱うときに役立つかもしれない、Gitの小ネタです。

Gitには git help しても出てこない( git help -a すれば出る)便利なコマンドがたくさんあり(※)、そのうちの1つ update-ref のご紹介です。

※他には例えば update-index --assume-unchanged なども有名ですね。

どんなときに欲しくなるか

こんな感じの、あるヘッダファイルに多数のソースファイルが依存するプロジェクトがあったとします。

repos
 |- common.hpp
 |- source1.cpp
 |- source2.cpp
 |- source3.cpp
 |- source4.cpp
 |- source5.cpp
 |- ...

まずは master ブランチにいます。

$ git status
On branch master
nothing to commit, working tree clean

新機能を開発するので、featureブランチを切ります。

$ git checkout -b feature/hoge
Switched to a new branch 'feature/hoge'

featureブランチでは新機能開発のため、共通ヘッダを更新しました。

$ vi config.hpp

ローカルでビルド・テストしてみて、動作は良好です。

$ cmake .
$ ninja

出来上がったのでpushしてMerge Request / Pull Requestを出します。

$ git commit -am "new feature"
[feature/hoge 45817d2] new feature
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git push origin feature/hoge
Total 0 (delta 0), reused 0 (delta 0)
To git@example.com:practice.git
 * [new branch]      feature/hoge -> feature/hoge

無事レビューを通過し、Web UI上でマージボタンが押されました。

o new feature [feature/hoge]
o initial commit [master]

↓

o Merge branch 'feature/hoge' into 'master' [origin/master]
|-
| | new feature
|-
o master [master]

ここで、自分もブランチから戻るのに、

$ git checkout master
$ git pull origin master

のようにしてしまうと、1行目のコマンドの時点でconfig.hppが一旦古いバージョンに戻ってしまいます
その後2行目のコマンドで新しいバージョンになりますが、ファイルのタイムスタンプが更新されるので、リビルドが必要になります。
リビルドに数時間かかるようなプロジェクトでは、これは致命的です。

update-refの登場

update-ref は、対象のブランチが指すコミットを書き換えるのに使えます。ワークツリーは feature/hoge にいるままで、 master の指す先を origin/master と同じにしてしまいましょう。

$ git fetch
$ git update-ref refs/heads/master origin/master
$ git checkout master

この順番で操作すると、3行目のコマンドでmasterブランチに切り替えても、config.hppの中身に変更がないためタイムスタンプも変わりません。したがって、無駄なリビルドは回避されます。

※なお、gitコマンドを使わず .git/refs/heads/master を書き換えても同じ結果が得られますが、gitコマンドのほうが若干事故りにくいでしょう。

それ以外の対応案と補足

update-refを使わず、この方法でも良いと思います。

$ git branch -D master
$ git fetch
$ git checkout -b master origin/master

社内で聞いてみたら、「masterに直接pushしない運用にしている以上、手元にmasterブランチがある意味がないし、事故の元だから手元にmasterブランチは作らない」という声もありました。

常にこのような形でブランチ運用するわけですね。

$ git fetch
$ git checkout -b feature/new origin/master

言われてみると、とても理にかなった方法です。gitは人によって使いこなし方が違うので、聞いてみると発見があって面白いですね。

僕の場合は癖のレベルですが「とりあえず最新版をビルドしたい」「これから何をやるかまだ決まってないからブランチ名が思いつかない」などによってmasterが欲しい人なので、 update-ref を使い続けています。

その後追記

これで良いのではという指摘をいただきました。こっちのほうが簡単ですね 💦

$ git fetch
$ git branch -f master origin/master

関連記事

【社内勉強会】バージョン管理の重要性とGitの運用について


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。