Gitでやらかさないための事前予防策

  • 1079
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Gitでやらかした時に使える19個の奥義を書いてやらかしたときになんとかリカバリできるようにした。
今回は、そもそもやらかさないようにしたいよねっていうお話。

コミット編

.gitignoreを細かく指定しておく

.gitignoreを指定しておけば余計なファイルをコミットしちゃうことを予防できます

過去に似たようなプロジェクトがあるのならそれを流用しましょう。
ないのであれば.gitignore.ioで生成してそれをカスタムしましょう。

ワイルドカード指定ディレクトリまるごとの指定は副作用ある可能性があるので慎重に。

コミットメッセージのフォーマットを決めておく

コミットメッセージのフォーマットを決めておけば書き直したいということも減ります

コミットメッセージをやらかして直したいと思うことはよくあります。
そういうのって案外コミットメッセージが自由すぎることが問題だったりします。

ある程度ルールぎめしておけばそれほど的はずれなメッセージにもならず修正しなきゃってこともずいぶん減るかと思います。

また、チケット管理している場合はチケット管理番号などと合わせて記載すると一層捗ります。

例)
#[チケット番号] [動詞] [名詞] [副詞句、その他(オプション)]  

上記で動詞、名詞、副詞句等それぞれパターン化しておきチーム内で共有しておくといいでしょう。
皆が読みやすいし表現のブレがなくなります。

難しい言い回しを使っちゃうとあとで困ったりするので簡単な表現がいいですね。
基本は[動詞] [名詞]だけで表現して、どうしても表現力が足りない場合に後ろをつけるイメージです。

コミットメッセージで使用する英単語を揃えておく

コミットメッセージの単語を決めておけば理解が楽になります

ある程度標準セットを揃えておくと表現がぶれずにすみます。
やりだしたらキリがないのでプロジェクト毎にミニマムなセットを用意するのがいいと思います。

表現に困ったらGithubのリポジトリを適当に覗いてみるといいです。

動詞

動詞は現在形で書くのがいいようです。

意味 英単語
作成 create
削除 remove, delete
更新 update
更新(バージョン) upgrade
追加 add
利用 use
包含 include
修正 modify
修正(バグ) fix (a bug)
変更 change
移動 move
置換 replace
拡張 extend
有効化/無効化 enable/disable
整理 clean
連結 link
送信 send
開く/閉じる open/close

implement, improve, supportとか内容がわからない(抽象度が高い)動詞は使わないほうがいいです。

イメージしやすい動詞のみ使いましょう。

名詞

名詞は結構多いのであげません。
これも具体イメージが付けばなんでもよく、抽象的な名詞は避けましょう。

よく見るものだけちょっと。

意味 英単語
バグ bug
誤字脱字 typo
更新履歴 changelog
設定 config, settings
形式 format
記述 description
引数 argument

副詞句、その他

これはプロジェクトごとに結構違ったりするので熟語的な感じで徐々に貯めていくといいかと思います。

日本人は長ったらしいメッセージを残す傾向にあります。
わかりにくくなる傾向にあるので、使わないことに越したことはありません。

意味 英単語
...のために、・・・の間 for ...
...と一緒に with ...
...越しに over ...
...内で in ...
...経由で via ...
...から...に from ... to ...
...のかわりに instead of ...
必要ならば if necessary
...の(前/後)に before .../after ...

コミットの粒度を決めておく

コミットの粒度を決めておけば後でつまみ食いしたり打ち消したりしやすくなります

できれば1コミット1変更!!

そうすればコミットメッセージも簡潔になります。

逆に1コミットにいろんな変更を加えるとコミットメッセージも抽象的で長ったらしい表現になります。
また今後cherry-pickで活用したりしにくいものになったりします。

上で決めた英単語(特に動詞)で表現できる変更かどうかを振り返ってみると適切な粒度なのかどうかがわかります。

コミットが小さいと一部を別ブランチに切り出すのも容易になるので理由なき大コミットはやめましょう。

プルリクの粒度をゆるーい感じで決めておく

プルリクの粒度を決めておけば1度のレビュー量が減り楽になります

1プルリクに何十もの更新ファイルがあったりするとレビューの時大変です。

レビューで何をみるのか(仕様?シンタックス?)次第で粒度は変わると思いますがプロジェクトごとにルールを決めておくのがいいかと思います。

例)

* 画面毎、画面パーツ毎
* モデル毎
* コマンド実行毎
* リファクタ、マイグレーション毎
* バグ修正毎
* ファイル追加毎
* 設定変更毎

・・・・

ちなみに、コードレビューでシンタックスチェックするのは個人的には人間様の時間を有効活用していない気がします。
なので、シンタックスチェックはツールにまかせて、人間様は仕様適合のチェックや設計の綺麗さ(?)チェックだけするのがいいのではないかなーと思ったりします。

そうすると結構画面単位でコミットすると都合いいことが多かったです。

確認者もこの画面だけ見ればいいのねって感じになるので。

ブランチ編

ブランチ名のフォーマットを決めておく

ブランチ名のフォーマットを決めておけば作り直したいということも減ります

例)内容的には今後のコミットをまとめた表現に(抽象的に)
[チケット番号]-[動詞]-[名詞]

コミットの場合は具体的な表現で変更がわかりやすいほうがいいと書きました。
一方ブランチ名は、複数コミットのまとめ的な存在なので多少抽象的に書いてもいいかなと思います。

ブランチ切り戦略を決める

ブランチ切りの戦略を決めておけば、同時にリリースするコミットだけをまとめることができます

git-flow, github-flowにかかわらず大きめの機能を作る場合はブランチ切りの戦略を決めておいたほうがよいでしょう。

大きいfeatureの場合おそらく複数人が開発に携わるでしょう。
そして最終的にはその作業内容を1つにまとめてリリースすることになるのでしょう。

その場合、各人がそれぞれ個別にmasterやdevelopから直接ブランチ切って直接そこにプルリク&マージしていてはトラブった時にいろいろ大変です。

大きめの機能を作る場合は、それをまとめる親ブランチを1つ作っておくのがいいかと思います。

私はよく以下の様な運用をしていました。

* 新しくブランチ切る場合はmasterやdevelopからではなく親ブランチから切る
* masterやdevelopにマージする前にその親ブランチに全員のコミットをまとめる
* 親ブランチはCIで監視しておいて自動でテスト回るようにする
* 最終的には親ブランチをdevelop,masterにマージしてリリースする

こうすると他の機能に関するブランチの作業内容が混じってこないので余計なことを考えずにすみます。

ブランチのイメージは以下の様なかんじ。

* master
    * develop
        * feature/親ブランチ → CIで自動テスト
            * feature/子ブランチ1
            * feature/子ブランチ2
            * ・・・

もちろん大きめのfeatureは作らず小さくリリースできればそのほうが幸せですが、事業上そうもできないことが多々ありますので。

ブランチ同期・マージ・取り消し戦略を決める

ブランチの戦略を決めておけば、リリースに不要な別のコミットが入りこんでどうしようもなくなる状況を予防できます

ブランチの切り方同様、同期やマージの仕方も重要です。

開発者の中で調整しながら決めていく感じでしょうか。
検討すべきは例えば以下のような点。

* いつmasterの更新を親・子ブランチに取り込むか
    * ひと通りテストが終わった後で全部取り込み?
    * 適宜必要に応じてコミット単位でcherrypick?
    * merge or rebase ?
* マージするときにコミットをまとめるか
    * 大量のコミットを小さくまとめる?
    * なんなら1つのコミットにsquashする?
    * まとめずそのままマージする
* マージを取り消したい場合どうするか
    * revert or reset?
    * ブランチ一時凍結?

これはgitの習熟度によってどのような戦略をとるのか大きく変わってくる気がします。

マージ時にコンフリクトするのが怖い場合(大丈夫ですよ!)、一度差分を確認しておくと気分的に安心できますね。

# コンフリクトしそうならgit pullはせずに差分をみてみる
$ git fetch
$ git diff FETCH_HEAD

タグつけのルールを決めておく

タグの具体的な利用方法を明確にした上で適切にタグ付けしましょう。
タグを使う用途がないのであればタグ付けは不要です。

* タグをいつ付けるのか
    * git-flowだとreleaseブランチからmasterにマージする時にリリース用のタグをつけるようです
* バージョン番号の桁数周り
    * メジャーバージョンアップにするかマイナーバージョンアップにするかの判断(3.9 → 3.10 or 4.0 みたいな話)
    * 2桁以上の場合0で埋めるて桁数合わせするかどうか

その他

大事なファイルの管理方法

パスワードやAPIキーのようなものをどのように管理するかは結構大事です。

* プライベートリポジトリなら
    * 最悪リポジトリ内で管理する&リポジトリ閲覧をかなり制限する
    * オンプレミスなファイルサーバー等で別途管理する
    * 特定の人だけがローカルで管理する
* 公開リポジトリなら
    * オンプレミスなファイルサーバー等で別途管理する
    * 特定の人だけがローカルで管理する

GitHubなどの公開リポジトリは特に気をつけましょう。
まちがって大事なファイルをpushしてしまった場合、ファイルを削除して再pushしても履歴から復元できてしまうので要注意です。

そんな場合は一度リポジトリ自体を作りなおす(再init)などして、履歴を消したほうがよいでしょう。

最近そういう無意識な漏洩&悪用が話題に上がっていましたね。

ツールを導入する

git-flowを使う

gitflow

git-flowのコマンドラインツールを使うことでブランチ開始〜終了までを面倒みてもらうと便利です。

これだけでもブランチを間違って削除したりといった誤爆がある程度防げるのではないでしょうか?

コマンド打つのが面倒なら、コマンドのエイリアスを設定したりすると捗りますね。

Source Treeを導入する

SourceTree

SourceTreeはCUIに慣れていない人でもお手軽にGit管理できるのでお勧めです。
Git Flowにも対応していますし、視覚的にもわかりやすいです。

ブランチ操作などはGUIでやるようにすれば間違いは減るかもしれません。

tigを導入する

tig

tigは、CUIなgit管理ツールです。
サーバー上で開発しなければならない人はこれを使うと捗ります。

初期状態だとそれほど大したことをできませんが、カスタマイズ次第では、pull/pushやもっと込み入ったことも何でもできるようになります。

.tigrcや.bashrcなどでゴリゴリにカスタムしましょう。

リリース時の切り戻しは予め手順書を作っておく

リリースして障害が起こったら切り戻す必要がありますが、切り戻しの仕方もいろいろあって迷うことがあります。
障害が起こるとパニックになって普段しないようなやらかしをしてしまい被害がさらに膨れる可能性があります。

そんなことのないように、でかめのリリースの場合は最悪の事も考えて切り戻し手順も作っておきましょう

  • capistranoなどをつかってロールバックする
  • 1つ前のリビジョンを指定して再デプロイする
  • masterへのマージコミットを打ち消してデプロイする

などなど場面に応じて使い分けましょう

あとはひたすら練習あるのみ

適当なサンプルでひたすら練習する 

いろいろ導入しても結局自分の手に馴染むように使い込まないと実践では使えません。

でもいきなり実践で使うのは怖いってことも往々にしてあります。
特に危険そうなコマンドはなおのこと。

そんな場合は、Githubの適当なリポジトリを使って試すのがいいかと思います。

練習方法は簡単。

* なんでもいいからリポジトリをローカルにcloneしてくる
* 練習に最適そうな過去のコミットを探す
    * 例えばマージ直後とかブランチの途中とか
* その過去のコミットをcheckoutする
* ブランチを切って適当にコマンド試す
* 満足したらリポジトリは消すなりなんなりと

要は、ローカルだけで閉じるならなにやっても問題ないねってことです。
GitHubのリポジトリをもってきてもいいし、現在開発しているものをもう1つ別の場所にもってきてもいいです。

ネット上にあるコマンドを挙動を確認しながら練習するとすぐに身につきます。

開発中のリポジトリを別に用意して一度試打してみる

野良リポジトリではなく、現在開発中のリポジトリで試したい場合もあります。
その場合は、一旦開発中のものは置いておいて、それとは別の場所にクローンしてきてそこで試しましょう。
そうすれば最悪失敗しても問題ないはずです。