情報 |
---|
これは cybozu.com インフラ開発チームが社内で使用しているマニュアルを一部修正したものです。 のインフラ開発チームが社内で使用しているマニュアルを一部修正したものです。 文中の GitHub はほとんどの場合、サイボウズ社内で利用している GitHub Enterprise のことを指しています。 |
...
での動作を前提としています。フィードバックはこちらにお願いします。 |
目次 | ||
---|---|---|
|
Git
...
git は難しいとよく言われます。実際に使ってみてわかったことは、git の仕組みそのものは比較的に単純なのですが、「このように使うべき」という作業の流れ(ワークフロー)が git のコマンド体系には欠けているため、非常にたくさんの機能が乱雑に並んでいるように思え、どう使うのかよくわからないというのが難しさの正体です。
特定のワークフローを規定せずにユーザーの自由に任せているのはおそらく git が意識的にしていることです。ワークフローを確立するまではいろいろと使い方に悩むというデメリットの反面、利用方法が縛られないのでチームレベルのプロジェクトはもちろん、個人での利用や世界各地で行われる分散開発(Linux カーネル開発)と、あらゆる開発プロジェクトで利用できる柔軟性を備えています。
特にブランチとマージの管理が優れているので、ガルーンのように非常に複雑な分岐をしている製品であっても、特定の不具合の修正を他のブランチに取り込むといったことが簡単にできます。
とは
Git は分散バージョン管理システムと呼ばれるものの一つです。Subversion と比較すると、高機能だが複雑で難しいと言えます。「分散」とついているのは Subversion のように中央レポジトリがあるのではなく、各個人が手元に所有する分散したレポジトリを同期して使うモデルを採用しているためです。とはいえ、現実的にはほとんどのチームで GitHub でホストする共有の中央レポジトリを持つことになるでしょう。こうした場合 git の最大の特徴は後述するブランチとマージの管理が優れていることです。例えば、特定の不具合の修正を他のブランチに取り込むといったことが簡単にできます。
Git の仕組み
Subversion のことは忘れましょう。利用できる機能は表面上似ているものも多いのですが、それを実現している内部の方式がまったく異なるため、たとえばマージで行われていることは 。利用できる機能は表面上似ているものも多いのですが、それを実現している内部の方式がまったく異なるため、たとえばマージで行われていることは Subversion の知識で理解しようとしてもうまくいきません。マージやチェックアウトやブランチという言葉は共通で使われていますが、Subversion の動作から理解しようとしても無理です。
まずはこの資料を読んでみましょう。まずは以下の資料を読んでおきましょう。
コミットオブジェクト/グラフ
git は分散バージョン管理システムであるのが一番の特徴であるように言われますが、分散して開発されたコードをうまくマージできる内部構造が最大の特徴と理解したほうが良いです。分散開発を可能にする内部構造を知らずして、git の動作を理解することはできません。
内部構造の中心となっているのは、コミットオブジェクトのグラフ(正確には DAG)です。Subversion のコミットはファイル単位の diff に過ぎませんでしたが(Subversion は直線的なリビジョン管理しか存在しないので、それで十分)、git ではコミットはグラフのノードのことで、DAG 構造を示すために1つ以上の親ノードの情報が含まれています。
git ではマージ操作は複数の枝が合流することで、マージコミットオブジェクトで表現されます。マージコミットには二つ以上の親ノードの情報が含まれているわけです。また、コミットグラフには他のレポジトリ(リモートレポジトリ。単にリモートと呼ぶことも多い)のグラフを持ってくることもできます。これらコミットグラフやリモート、タグ、ブランチを図解している良いサイトが以下にありますので、一読してみてください。
ブランチ
コミットグラフの DAG の先端をブランチと呼びます。新たに枝を分岐したいときは、git branch
コマンドでつくります。
ローカルブランチの一覧を見るには、git branch
とします。以下の用語が理解できたと思います。
- コミット(オブジェクト)
- コミットグラフ
- ブランチ
- マージ
- ファストフォワードマージ
- マージコミット
- リベース
あとはリモートレポジトリの取り扱い方法を学んでおきましょう。
リモートレポジトリ
Git は分散したレポジトリを同期することで、共同作業をできるようにします。同期するにはまず手元にリモートレポジトリを取り寄せます。取り寄せ方は二通りあります。
リモートレポジトリのクローンを手元に作成する方法
書式設定済み $ git
...
* がついているのが現在作業中のブランチです。
作業ブランチを切り替えるには、git checkout
を使います。
...
clone https://github.com/ymmt2005/hazama-tools $ cd hazama-tools $ git
...
remote
...
show origin
ローカルレポジトリにリモートレポジトリの情報を追加する方法
書式設定済み $ git
...
remote
...
add stable https://github.com/ymmt2005/test.git $ git
...
fetch stable $
...
git remote show
...
実際に試すとわかりますが、ブランチの作成や切り替えは瞬時に完了します。git では新機能の開発や不具合の改修といったひとつひとつのタスクごとにブランチを作成し、開発が完了してから master にマージするのが定石です。ごく単純な修正以外は、master 上で直接開発するのは避け、ブランチで開発してください。
c.f. A successful Git branching model (翻訳版)
リモートレポジトリ
...
origin stable
git clone
は origin
という名前でリモートレポジトリを手元に取り寄せます。実際には以下のような操作と同等のことをしています。
- git init
空のレポジトリを作り、 git remote add origin
URL
URL にあるリモートレポジトリをorigin
という名前で登録して、git fetch origin
origin
のコミットグラフを取り寄せる
二つ以上のリモートレポジトリを取り寄せるのは、この git remote add
以降の操作を繰り返しているだけです。
取り寄せた後は、なにかを、いじって、リモートに反映したいですね。まずなにをいじるのでしょう?
答えはリモートブランチです。どんなブランチがあるか git branch -r
で確認してみましょう。
書式設定済み |
---|
$ git clone github:hazama/infra $ cd infra $ git branch -r branch -r origin/HEAD -> origin/master origin/INFRA-xx1000 origin/master stable/master |
origin に master
, INFRA-1000
と stable に master
ブランチがあることがわかります。origin/master
に対してなにかフィーチャーを実装することにしたとしましょう。次にやることは、ローカルブランチを origin/master
から分岐して作ることです。
書式設定済み |
---|
$ git checkout remote show-b INFRA-1001 origin/master *$ remotegit originbranch * INFRA-1001 master $ git remote show origin * remote origin Fetch URL: github:hazama/test_infra Push URL: github:hazama/test_infra HEAD branch: master Remote branches: INFRA-xx 1000 tracked master tracked Local branchbranches configured for 'git pull': INFRA-1001 merges with remote master master merges with remote master Local refrefs configured for 'git push': master pushes to master (uppushes to date) |
Local branch configured for ...
という箇所が、ローカルレポジトリのブランチがどのリモートレポジトリのブランチと結びついているかの設定情報です。git pull
や git push
するときに、対象となるリモートブランチの指定が省略可能になります。設定されていない純粋なローカルブランチであっても、別途設定することが可能です。
...
master |
INFRA-1001
というローカルブランチが作成され、origin/master
を追跡しているのがわかります。
この INFRA-1001
ブランチで作業し、コミットすると、そのコミットはローカルレポジトリに保存されます。
ローカルレポジトリに保存したコミットグラフをリモートに反映するには git push
を使います。
書式設定済み |
---|
$ git fetchcommit origin remote: Counting objects: 24, done. remote: Compressing objects: 100% (11/11), done. remote: Total 16 (delta 10), reused 11 (delta 5) Unpacking objects: 100% (16/16), done. From github:hazama/test_infra * [new branch] INFRA-xxx -> origin/INFRA-xxx aeb7209..8f880da master -> origin/master * [new branch] review_INFRA-xxx -> origin/review_INFRA-xxx |
INFRA-xxx
や review_INFRA-xxx
というリモートレポジトリの情報が追加された情報が表示されています。
リモートレポジトリに対して何か作業をしたいときは、リモートレポジトリを追跡するトラッキングブランチを作成します。単純に、リモートブランチからローカルブランチを作成すればトラッキング情報が設定されます。
書式設定済み |
---|
$ git checkout -b INFRA-yy origin/master
Branch INFRA-yy set up to track remote branch master from origin.
Switched to a new branch 'INFRA-yy'
$ git remote show origin
* remote origin
Fetch URL: github:hazama/test_infra
Push URL: github:hazama/test_infra
HEAD branch: master
Remote branches:
master tracked
Local branches configured for 'git pull':
master merges with remote master
INFRA-yy merges with remote master
Local refs configured for 'git push':
master pushes to master (local out of date)
|
ローカルで開発したコミットグラフをリモートに反映するには git push
します。
書式設定済み |
---|
$ git commit -a -m 'finished.'
$ git fetch origin
$ git rebase
$ git checkout master
$ git merge --squash INFRA-yy
$ git commit -m INFRA-yy
$ git push -u origin master
|
フォークしているプロジェクトの場合、上流(アップストリーム)レポジトリの変更を取り込んだりパッチや PULL リクエストを送りたくなります。そういうときは、アップストリームレポジトリを追加することができます。以下の例では forest/infra
を stable
という名前のリモートとして追加しています。
書式設定済み |
---|
$ git remote add stable github:forest/infra
$ git fetch stable
$ git checkout -b INFRA-yy-for-stable stable/master
$ git cherry-pick COMMIT
|
警告 |
---|
|
ファストフォワード(fast foward)マージ
ファストフォワードという用語がしばしば出てくるので解説しておきます。二つのブランチをマージする際に、マージするコミットがマージ先のブランチに単追加されるだけの状況のとき、ファストフォワードマージという特殊なマージとなります。
一般的にはマージ操作ではマージコミットというコミットオブジェクトが作られます。これは二つのブランチが合流したことを示すもので、親コミットが二つ以上記録されます。一方、ファストフォワードマージではマージコミットオブジェクトは作成されず、単純にマージ元にのみあるコミットオブジェクトがマージ先に追加されるだけです。
具体的には、以下のような操作のときに行われるのがファストフォワードマージです。
書式設定済み |
---|
$ git checkout -b branch master
(branch 上でのみ作業)
$ git commit -m 'hoge'
$ git checkout master
$ git merge branch
$ git branch -d branch
|
master と branch の違いは branch で追加されたコミットのみなので、branch で追加されたコミットオブジェクトが master に追加されるだけとなります。マージコミットオブジェクトは作成されないので、マージがあったことをあとで確認することはできません。
git merge --no-ff
とすることで、ファストフォワードが可能な場合でもマージコミットオブジェクトを作成することができます。マージしたことを記録に残したい場合に使います。後述する GitHub のプルリクエストを GUI で処理するときも、常にマージコミットオブジェクトが作成されます。
チュートリアル
git は利用者が多いのでチュートリアル資料もたくさんあります。以下がおすすめです。
- サルでもわかるGit入門
いろいろ見た中で一番とっつきやすいと思いました。 - こわくない Git
merge と rebase の違いなどを丁寧に解説しています。必読。 - ぎっとぎとにしてやんよ
@teppeis 作の tips 集。必読。 - コミットメッセージの書き方
現在形の英語で書くとか。 - Git Cheat Sheet
レポジトリ、インデックス(ステージングエリア)、ワーキングコピー、スタッシュの関係が図示されています。 - man 7 gitrevisions
revision の指定方法。HEAD~3 や :/text といった便利記法の使い方がわかります。 - ProGit
Official, PDF - Git From the Bottom Up
PDF, 日本語訳(html)
GitHub 概説
git は基本的には個人で使うための機能しかなく、レポジトリを共有管理する機能は充実していません。
レポジトリの共有管理をするためには gitolite のようなオープンソースツールもありますが、gitolite プロジェクト自体も GitHub でホスティングされているように、git レポジトリホスティング機能としては GitHub がダントツに優れています。
社内の GitHub Enterprise には以下の URL でアクセスできます。
レポジトリ管理
GitHub (Enterprise) ではレポジトリは個々の利用者が自由に作ることができます。共有レポジトリをフォークすることも自由です。
共有レポジトリを管理するために Organization という仕組みがあり、Organization は複数の Owner が共同管理できます。
Organization では Team を複数作成して、それぞれのチームごとに PUSH, PULL の権限を制御できます。
Organization は誰でも作ることができます。社内の GitHub では以下の URL から。
コミュニケーション
GitHub ではコミットや差分の行単位でコメントをつけることができます。コメントは GitHub の通知機能やメールで通知されます。
メール通知は個人設定で止めることもできます。特定のレポジトリを watch すると、そのレポジトリの変更が通知されます。
ユーザーの顔写真には Gravatar というサービスを利用して表示しています。顔写真がないと誰が操作したのかわかりにくいので、GitHub に登録したら必ず Gravatar を設定しましょう。Gravatar でアバターを指定するメールアドレスは、GitHub で登録されているメールアドレスにしてください(メールアドレスが主キーです)。
あとは "@ユーザー名" と書くとそのユーザーに通知してくれるメンション機能があります。
PULL リクエスト
GitHub で特に有名な機能に PULL リクエストがあります。フォークしたレポジトリ間やブランチ間で、特定の差分を取り込んでもらうように GUI で依頼する機能で、依頼を受けた側はボタン一つでマージできます。差分の行単位でコメントをつけることができるので、レビューツールとしても非常に便利に使えます。
PULL リクエストは担当者を指定できるので、レビューを依頼するユーザーに設定しましょう。
ヒント |
---|
PULL リクエストはフォークしたレポジトリ間でなくとも、ひとつのレポジトリのブランチ間でも投げることができます。 |
情報 |
---|
PULL リクエストは実際には |
Gist
レポジトリ管理とは無関連の、コードスニペットを共有する機能です。
GitHub のおまけ的機能ですが、script タグで他のページに埋め込める等なかなか便利です。
Wiki
GitHub はマークダウン記法 でコメントやドキュメントを書く機能があります。
各レポジトリにはこのマークダウン記法でページを作成できる Wiki 機能が付属しています。
Wiki システムは Gollum というもので、詳細はリンク先を読んでください。
簡単な使い方:
ページ間リンクは
[[
で書く書式設定済み [[PageName]] [[Title|PageName]]
- Git レポジトリの中は好きなようにディレクトリを作っていい
ページもどう配置してもいいが、幅優先探索で最初にみつかったものが表示される。 - マークダウン記法の使い方は以下を参照
Issues
レポジトリごとにタスクや不具合を管理する Issues 機能がありますが、非常に簡素なものですので kintone や JIRA の代わりにはなりません。
API
GitHub 本家と同じ API が利用できます。
API を利用すると PULL リクエストをコマンドラインから送るようなことができます。
アーカイブ
レポジトリではなく、ファイルだけを取得する git archive
機能は GitHub では提供されていません。クローンしてください。
毎日のビルドにつかうなら、こんな感じ。svn export
よりむしろ高速です。
書式設定済み |
---|
$ git clone repo
(初回のみ)
$ cd repo
$ rm -rf *
$ git fetch origin
$ git reset --hard
(これでまっさらな最新のソースが手に入ります)
|
共有レポジトリ
Forest, Hazama で共有するレポジトリは GitHub の forest, hazama Organization で管理されています。
警告 |
---|
共有レポジトリの master ブランチには直接 PUSH してはいけません。 |
forest
forest は install-forest で運用環境にインストールする infra
レポジトリを管理しています。infra レポジトリに PUSH できる(PULLリクエストを処理できる)のは当面森本さんと山本だけです。Forest の人が git に慣れたら、Forest メンバーは PULL リクエストを処理できるようにしようと思います。
hazama
hazama は forest/infra
を開発用にクローンしています。また、install-forest に直接関係しない tbs
や js
や ubuntu
はそれぞれ個別のレポジトリとして hazama で管理しています。Forest, Hazama の人は誰でも PULL リクエストを処理できます。
hazama/tools
には開発用のツールがありますので、まずこれを手元にクローンしてください。
最初にやること
- GitHub にログインしてパスワードを変更する
招待メールが届いているはずですので、処理してください - Gravatar でアバターを登録する
登録メールアドレスは GitHub と同じものにしてください 手元の Ubuntu 12.04 に git を入れる
書式設定済み $ sudo apt-get install git git-doc
ユーザー名とメールアドレスを GitHub と同じになるように設定する
書式設定済み $ git config --global user.name morimoto $ git config --global user.email kenji_morimoto@cybozu.co.jp
おまじないをしておく
書式設定済み $ git config --global merge.ff false $ git config --global pull.rebase true
(オプション) GitHub のパスワードを
$HOME/.gitconfig
に保存する
保存しておくと、git hazama review
のときに GitHub パスワードを聞かれずに済みます書式設定済み $ git config --global user.password XXXX $ chmod 600 $HOME/.gitconfig
kintone のユーザー名とパスワードを
$HOME/.gitconfig
に保存する
パスワードはオプションですが、以下略。書式設定済み $ git config --global kintone.user hyamamoto $ git config --global kintone.password XXXX
GitHub 用の ssh キーを生成して設定する
-C で指定するメールアドレスは GitHub と同じにしてください。書式設定済み $ ssh-keygen -t rsa -C kenji_morimoto@cybozu.co.jp -f $HOME/.ssh/github $ vi ~/.ssh/config # add following lines Host github HostName github.dev.cybozu.co.jp User git IdentityFile ~/.ssh/github
- GitHub に SSH の公開鍵を登録する
$HOME/.ssh/github.pub
の中身を設定画面で登録してください。 hazama/tools
レポジトリをクローンして PATH を設定する書式設定済み $ git clone github:hazama/tools $ echo "export PATH=$(pwd)/tools/bin:\$PATH" >> $HOME/.bashrc $ . $HOME/.bashrc $ git hazama (動作確認)
レポジトリをクローンする
git hazama setup
で適切にリモートレポジトリ(stable)を設定してくれます書式設定済み $ git hazama setup infra $ cd infra $ git remote -v show origin github:hazama/infra (fetch) origin github:hazama/infra (push) stable github:forest/infra (fetch) stable github:forest/infra (push)
これで infra
レポジトリの開発をする準備は完了です。
他のレポジトリも同様ですが、stable リモートは不要なので単にクローンすれば OK です。
git hazama setup
してもいいですが、単にクローンするだけです。
書式設定済み |
---|
$ git clone github:hazama/tbs
$ cd tbs
$ git remote -v show
origin github:hazama/tbs (fetch)
origin github:hazama/tbs (push)
|
練習
いきなり本番の環境を触って壊さないよう、練習用のレポジトリ practice
を用意してあります。
infra
レポジトリと同様の操作ができるので、まずは以下の手順で準備をしてください。
書式設定済み |
---|
$ git hazama setup practice
|
practice
では infra
と同じように下記のワークフローを実行できるので、誰かと一緒に練習してみてください。
forest/practice
は Hazama, Forest の人全員に PUSH 権限を与えているので、PULL リクエストを処理できます。
練習の際には Hazama タスク管理 に練習用のチケットを登録して、そのチケットで練習してください。
...
タスク管理の方法
kintone の Hazama タスク管理 アプリを使います。
Forest の人も、git の変更を伴うものは必ず Hazama タスク管理で実施するようにしてください。
大まかな流れは以下になります。
- (PG1) タスクを登録する
- (PG1) 開発し、Development Review にする
Development Review にする際に、GitHub のhazama/infra
に PULL リクエストを投げる。
PULLリクエストの担当者にはレビュワーの PG2 を指定する。 - (PG2) リクエスト内容をレビューし、不備があればコメントする(クローズはしない)
- (PG1) レビュワーに差し戻されたら、トピックブランチに修正コミットを追加して PUSH する
- (PG2) レビュー OK なら PULL リクエストをマージし、Testing にする
- (PG1) マージされたのを確認して
install-forest dev
し、適用する - (QA) 試験をし、不具合があれば Reopen する
- (PG1) リオープンされたら修正をトピックブランチに PUSH し、再度 PULL リクエストを投げる
- (PG2) ditto
- (QA) 試験合格したらステータスを Staging にする
- (PG1) Staging になった関連タスクを運用環境への期日の直前に PULL リクエストを投げる
PULL リクエストを投げたら、タスクは Close する。 - (Forest)
forest/infra
にマージする。
マージしたら適用手順に従いinstall-forest prod
,install-forest bk
する。
開発レビューまでの作業
一時ブランチを作る
書式設定済み $ git hazama dev Branch dev set up to track remote branch master from upstream. Switched to a new branch 'dev'
開発する
途中で何度コミットしても構いません。最低1日に1回はコミットしてorigin/master
をマージしましょう。
途中のコミットはあとで捨てるので、コミットコメントは適当で構いません。書式設定済み $ git commit -a -m 'blur blur' $ git fetch origin $ git merge --no-ff origin/master (コンフリクトしたら修正して commit する) (git rebase は間違うと痛いので、使わないこと)
開発が完了したら
git hazama review
コマンドを実行する書式設定済み $ git hazama review dev xx (xx は実際には INFRA-535 なら 535 を指定します) $ git branch -D dev (ブランチ削除は意図的に hazama review でやらないようにしているので、自分で消す)
このコマンドでは以下のようなことが実行されます
- トピックブランチ INFRA-xx を作成
git merge --squash dev
git push origin INFRA-xx
- GitHub API で
hazama/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
- GitHub 上で PULL リクエストを確認する
レビュー担当者を指定できるので、指定しておきましょう レビュワーに PULL リクエストをレビューしてもらう
PULL リクエストは行単位でコメントをつけることができます。
レビュワーは承認したらマージボタンを押してマージしてください。
承認できないときはクローズせず、修正を追加コミットするよう指示します。情報 大幅改修などが必要の場合は、PULLリクエストをマージせずにクローズすることもあります。
その場合は、以下のようなフローになります。- まだorigin/masterにマージされたコミットがない場合
→ git push origin :INFRA-xxでブランチを消してやり直す。 - すでにorigin/masterにマージされたコミットがある場合(試験後に差し戻されたときなど)
→ 「試験で不具合がみつかったときの作業」と同じ
- まだorigin/masterにマージされたコミットがない場合
レビューが却下されたら、INFRA-xx ブランチから dev ブランチを作り開発を続ける
ちょっとした修正なら dev 作らず INFRA-xx で直接作業しても構いません。書式設定済み $ git checkout -b dev INFRA-xx (開発) $ git commit -m 'hoge' $ git checkout INFRA-xx $ git merge --ff --squash dev $ git commit -m 'INFRA-xx: fix a bug.' $ git push origin INFRA-xx $ git branch -D dev
トピックブランチに PUSH すると、以前の PULL リクエストに反映されるので、再度レビューしてもらう。
情報 マスターが更新されたため、レビュー承認後にマージが行えない場合があります。
この場合は、マスターを merge して、コンフリクトを解決してください。書式設定済み $ git fetch origin $ git merge --no-ff origin/master
レビューが通ってマージされたら、ローカルブランチを消す
(リモートブランチは消さない)書式設定済み $ git checkout master $ git pull (マージ後のソースに更新される) $ git branch -d INFRA-xx (-D で強制しなくても、マージされていたら消せるはず)
試験で不具合がみつかったときの作業
origin/INFRA-xx
からローカルブランチを作成する書式設定済み $ git checkout -b INFRA-xx origin/INFRA-xx $ git fetch origin $ git merge --no-ff origin/master
修正してコミットする
書式設定済み $ git commit -a -m "INFRA-xx: fix something."
git hazama fix
コマンドを実行する書式設定済み $ git hazama fix xx (xx は実際には INFRA-535 なら 535 を指定します)
このコマンドでは以下のようなことが実行されます
git push origin INFRA-xx
- GitHub API で
hazama/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
マージされたらローカルブランチを消す
(リモートブランチは消さない)書式設定済み $ git checkout master $ git pull $ git branch -d INFRA-xx
forest/infra
へのマージ
hazama/infra
関連のタスクは、試験完了後に forest/infra
にマージする必要があります。
マージしてほしい時期が近付いてきたら、forest に PULL リクエストを投げます。
GitHub の PULL リクエスト機能は投げる先のレポジトリ forest/infra@master
に対して、指定したブランチに存在するコミットをマージするように動作します。すでに作ってある INFRA-xx
トピックブランチは hazama/infra
にある、取り込まれるべきでないコミットも含んでいますので、INFRA-xx
から PULL リクエストを送ってはいけません。以下のように作業する必要があります。
forest/infra@master
からトピックブランチを作成する
こうするとhazama/infra
でまだあててはいけないコミットを含まないことが保証できます- 作成したブランチに
INFRA-xx
作成後に追加されたコミットをgit cherry-pick
で適用する
INFRA-xx
作成後に追加されたコミットを特定するのは、機械的にやるのはなかなか骨です。
c.f. Finding a branch point with Git? - コンフリクトが発生したら、修正をコミットして
git cherry-pick --continue
する - トピックブランチを origin に PUSH して PULL リクエストを
forest/infra
に投げる
以上のことをやってくれる git hazama pick
と git hazama stage
というコマンドがあります。
使い方は以下の通りです。
git hazama pick
で cherry-pick まで実行する
コンフリクトする場合はエラーで止まりますので、指示される通りに解決してください書式設定済み $ git hazama pick xx (xx は INFRA-353 なら 353 を指定) (INFRA-xx-forest トピックブランチを作成して cherry-pick します)
情報 コンフリクトするはずなんてないのにおかしい、といった場合は cherry-pick を中断してください。
書式設定済み $ git cherry-pick --abort $ git checkout master $ git branch -D INFRA-xx-forest
コンフリクトが解決したら、修正してコミットして continue します
書式設定済み $ vi ... $ git add ... $ git cherry-pick --continue
コミットメッセージには'INFRA-xx: fix conflicts.'と入れます。
git hazama stage
でトピックブランチを PUSH して PULL リクエストを投げます書式設定済み $ git hazama stage xx
このコマンドでは以下のようなことが実行されます
git push origin INFRA-xx-forest
- GitHub API で
forest/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
- GitHub 上で PULL リクエストを確認
マージされたらローカルブランチを消す
書式設定済み $ git checkout master $ git fetch stable $ git branch -d INFRA-xx-forest (-D で強制しなくても、マージされていたら消せるはず)
ベストプラクティス
git 編
- master で作業しない
必ずブランチを作って作業しましょう。 - git pull は基本的に使わない
git fetch して、適宜 merge しましょう。
作業しない master ブランチは、git pull で更新して構いません。 - 一度 PUSH したブランチは rebase してはいけない
PUSH したあと、PUSH した履歴を書き換えちゃうことになるので、ダメ、絶対。 - むしろ git rebase しない
以下参考に。 - トップディレクトリには
.gitignore
を置いておく
こうすれば、他の人と add したくないファイルの設定を共有できます。
GitHub 編
- レポジトリは小分けにする
GitHub では誰でも自由にレポジトリを作れるので、関連性の薄いモジュールをひとつのレポジトリで管理する必要はありません。
小分けにしている方が、フォークやクローンが速くて良いです。 - 共有レポジトリの変更は PULL リクエストで
いきなり master に PUSH するのは止しましょう。
ブランチから PULL リクエストを投げて、レビューを受けるようにしてください。 - むやみに共有レポジトリをフォークしない
リソースがもったいないので、大きなレポジトリはむやみにフォークしてはいけません。
PUSH 権限がない別のチームのレポジトリに PULL リクエストを投げるようなときに、フォークしましょう。
その他これはというものがあれば、議論して追加しましょう。
Subversion からの移行
svn2git
という Ruby のツールを使います。Ubuntu 12.04 ではこんな感じ。
authors.txt
は GitHub のユーザー名/メールアドレスと同じになるようにしましょう。
書式設定済み |
---|
$ sudo apt-get install git-svn ruby1.9.1 $ sudo gem install svn2git $ cd $HOME $ cat >authors.txt <<EOF hyamamoto = ymmt <ymmt@cybozu.com> yusuke_kon = kon <yusuke_kon@cybozu.co.jp> toshishige-hagihara = hagihara <toshishige-hagihara@cybozu.co.jp> hidekazu_suzuki = hidekazu <hidekazu_suzuki@cybozu.co.jp> akihiro-kasuya = kasuya <akihiro-kasuya@cybozu.co.jp> ty_c = ty <ty_c@cybozu.co.jp> kotaro-ono = ono <kotaro-ono@cybozu.co.jp> kenji_morimoto = morimoto <kenji_morimoto@cybozu.co.jp> shinnosuke-saito = shinn <shinnosuke-saito@cybozu.co.jp> yuichi_tanaka = yuichi_tanaka <yuichi_tanaka@cybozu.co.jp> teppei_sato = teppei_sato <teppei_sato@cybozu.co.jp> yuki_okada = yuki_okada <yuki_okada@cybozu.co.jp> masanori_matsumoto = masanori_matsumoto <masanori_matsumoto@cybozu.co.jp> yasuharu-sakai = yasuharu-sakai <yasuharu-sakai@cybozu.co.jp> isami_yamada = isami_yamada <isami_yamada@cybozu.co.jp> masaki_oguro = masaki_oguro <masaki_oguro@cybozu.co.jp> jumpei-miyata = jumpei-miyata <jumpei_miyata@cybozu.co.jp> EOF $ mkdir t $ cd t $ svn2git http://svn.dev.cybozu.co.jp/svn/gaia \ --trunk trunk/infra --nobranches --notags --revision 25000 \ --authors $HOME/authors.txt --exclude tbs --exclude dtflib \ --exclude js --exclude ubuntu --verbose (レポジトリを分割するので、不要なものは exclude する) (--revision はここでは今年1月あたり以降の履歴をインポートするように指定しました) $ git log $ git push github:forest/infra master (GitHub に作っておいた空のレポジトリに PUSH する) -a -m 'add xxx.' $ git push -u origin INFRA-1001 |
このコマンドを実行すると、リモートレポジトリにも INFRA-1001
というブランチが作成されます。
すでに INFRA-1001
ブランチがある場合は、差分のみ送信されます。差分はファストフォワードマージできる状態でなければなりません。
ヒント |
---|
二つ以上のリモートレポジトリを持つのはどういう場合でしょうか? 以下のような利用方法が考えられます。
|
チュートリアル
git は利用者が多いのでチュートリアル資料もたくさんあります。以下がおすすめです。
- サルでもわかるGit入門
いろいろ見た中で一番とっつきやすいと思いました。 - こわくない Git
merge と rebase の違いなどを丁寧に解説しています。必読。 - ぎっとぎとにしてやんよ
@teppeis 作の tips 集。必読。 - コミットメッセージの書き方
現在形の英語で書くとか。 - Git Cheat Sheet
レポジトリ、インデックス(ステージングエリア)、ワーキングコピー、スタッシュの関係が図示されています。 - man 7 gitrevisions
revision の指定方法。HEAD~3 や :/text といった便利記法の使い方がわかります。 - ProGit
Official, PDF - Git From the Bottom Up
PDF, 日本語訳(html)
GitHub 概説
git は基本的には個人で使うための機能しかなく、レポジトリを共有管理する機能は充実していません。レポジトリの共有管理をするためには gitolite のようなオープンソースツールもありますが、gitolite プロジェクト自体も GitHub でホスティングされているように、git レポジトリホスティング機能は GitHub がダントツに優れています。
レポジトリ管理
GitHub (Enterprise) ではレポジトリは個々の利用者が自由に作ることができます。共有レポジトリをフォークすることも自由です。
共有レポジトリを管理するために Organization という仕組みがあり、Organization は複数の Owner が共同管理できます。
Organization は複数の Team を持つことができ、チームごと所属するメンバー、レポジトリ、および PUSH, PULL の権限を制御できます。
Organization は誰でも作ることができます。
コミュニケーション
GitHub ではコミットや差分の行単位でコメントをつけることができます。コメントは GitHub の通知機能やメールで通知されます。
メール通知は個人設定で止めることもできます。特定のレポジトリを watch すると、そのレポジトリの変更が通知されます。
ユーザーの顔写真には Gravatar というサービスを利用して表示しています。顔写真がないと誰が操作したのかわかりにくいので、GitHub に登録したら必ず Gravatar を設定しましょう。Gravatar でアバターを指定するメールアドレスは、GitHub で登録されているメールアドレスにしてください(メールアドレスが主キーです)。
あとは "@ユーザー名" と書くとそのユーザーに通知してくれるメンション機能があります。
PULL リクエスト
GitHub で特に有名な機能に PULL リクエストがあります。フォークしたレポジトリ間やブランチ間で、特定の差分を取り込んでもらうように GUI で依頼する機能で、依頼を受けた側はボタン一つでマージできます。差分の行単位でコメントをつけることができるので、レビューツールとしても非常に便利に使えます。
PULL リクエストは担当者を指定できるので、レビューを依頼するユーザーに設定しましょう。
ヒント |
---|
PULL リクエストはフォークしたレポジトリ間でなくとも、ひとつのレポジトリのブランチ間でも投げることができます。 |
情報 |
---|
PULL リクエストは実際には |
Gist
レポジトリ管理とは無関係の、コードスニペットを共有する機能です。
GitHub のおまけ的機能ですが、script タグで他のページに埋め込める等なかなか便利です。
Wiki
GitHub はマークダウン記法でコメントやドキュメントを書く機能があります。
各レポジトリにはこのマークダウン記法でページを作成できる Wiki 機能が付属しています。
Wiki システムは Gollum というものです。詳細はリンク先を読んでください。
簡単な使い方:
ページ間リンクは
[[
で書く書式設定済み [[PageName]] [[Title|PageName]]
- Git レポジトリの中は好きなようにディレクトリを作っていい
ページもどう配置してもいいが、幅優先探索で最初にみつかったものが表示される。 - マークダウン記法の使い方は以下を参照
Issues
レポジトリごとにタスクや不具合を管理する Issues 機能がありますが、非常に簡素なものですので kintone や JIRA の代わりにはなりません。
API
GitHub 本家と同じ API が利用できます。
API を利用すると PULL リクエストをコマンドラインから送るようなことができます。
アーカイブ
情報 |
---|
GitHub Enterprise 11.10.300 でアーカイブダウンロード機能が搭載されました。 |
レポジトリではなく、ファイルだけを取得する git archive
機能は GitHub では提供されていません。クローンしてください。
毎日のビルドにつかうなら、こんな感じ。svn export
よりむしろ高速です。
書式設定済み |
---|
$ git clone repo
(初回のみ)
$ cd repo
$ rm -rf *
$ git fetch origin
$ git reset --hard
(これでまっさらな最新のソースが手に入ります) |
最初にやること
GitHub にログインしてパスワードを変更する
招待メールが届いているはずですので、処理してください
- Gravatar でアバターを登録する
登録メールアドレスは GitHub と同じものにしてください 手元の Ubuntu 12.04 に git を入れる
書式設定済み $ sudo apt-get install git git-doc
ユーザー名とメールアドレスを GitHub と同じになるように設定する
書式設定済み $ git config --global user.name ymmt $ git config --global user.email xxxx@cybozu.co.jp
おまじないをしておく
書式設定済み $ git config --global merge.ff false $ git config --global pull.rebase true
(オプション) GitHub のパスワードを
$HOME/.gitconfig
に保存する
保存しておくと、git hazama review
のときに GitHub パスワードを聞かれずに済みます書式設定済み $ git config --global user.password XXXX $ chmod 600 $HOME/.gitconfig
kintone のユーザー名とパスワードを
$HOME/.gitconfig
に保存する
パスワードはオプションですが、以下略。書式設定済み $ git config --global kintone.user XXXX $ git config --global kintone.password XXXX
GitHub 用の ssh キーを生成して設定する
-C で指定するメールアドレスは GitHub と同じにしてください。書式設定済み $ ssh-keygen -t rsa -C xxxx@cybozu.co.jp -f $HOME/.ssh/github $ vi ~/.ssh/config # add following lines Host github HostName github.localdomain User git IdentityFile ~/.ssh/github
- GitHub に SSH の公開鍵を登録する
$HOME/.ssh/github.pub
の中身を設定画面で登録してください。 hazama/tools
レポジトリをクローンして PATH を設定する書式設定済み $ git clone github:hazama/tools $ echo "export PATH=$(pwd)/tools/bin:\$PATH" >> $HOME/.bashrc $ . $HOME/.bashrc $ git hazama (動作確認)
レポジトリをクローンする
git hazama setup
で適切にリモートレポジトリ(stable)を設定してくれます書式設定済み $ git hazama setup infra $ cd infra $ git remote -v show origin github:hazama/infra (fetch) origin github:hazama/infra (push) stable github:forest/infra (fetch) stable github:forest/infra (push)
これで infra
レポジトリの開発をする準備は完了です。
他のレポジトリも同様ですが、stable リモートは不要なので単にクローンすれば OK です。
git hazama setup
してもいいですが、単にクローンするだけです。
書式設定済み |
---|
$ git clone github:hazama/tbs
$ cd tbs
$ git remote -v show
origin github:hazama/tbs (fetch)
origin github:hazama/tbs (push)
|
練習
いきなり本番の環境を触って壊さないよう、練習用のレポジトリ practice
を用意してあります。
infra
レポジトリと同様の操作ができるので、まずは以下の手順で準備をしてください。
書式設定済み |
---|
$ git hazama setup practice
|
practice
では infra
と同じように下記のワークフローを実行できるので、誰かと一緒に練習してみてください。
forest/practice
は全員に PUSH 権限を与えているので、PULL リクエストを処理できます。
練習の際には kintone に練習用のチケットを登録して、そのチケットで練習してください。
アンカー | ||||
---|---|---|---|---|
|
タスク管理の方法
kintone のタスク管理 アプリを使います。
大まかな流れは以下になります。
- (PG1) タスクを登録する
- (PG1) 開発し、Development Review にする
Development Review にする際に、GitHub のhazama/infra
に PULL リクエストを投げる。
PULLリクエストの担当者にはレビュワーの PG2 を指定する。 - (PG2) リクエスト内容をレビューし、不備があればコメントする(クローズはしない)
- (PG1) レビュワーに差し戻されたら、トピックブランチに修正コミットを追加して PUSH する
- (PG2) レビュー OK なら PULL リクエストをマージし、Testing にする
- (PG1) マージされたのを確認して、開発用データセンターに適用する
- (QA) 試験をし、不具合があれば Reopen する
- (PG1) リオープンされたら修正をトピックブランチに PUSH し、再度 PULL リクエストを投げる
- (PG2) ditto
- (QA) 試験合格したらステータスを Staging にする
- (PG1) Staging になった関連タスクの PULL リクエストを
forest/infra
に投げる。
PULL リクエストを投げたら、タスクは Close する。 - (OP)
forest/infra
にマージする
マージしたら適用手順に従い運用データセンターに適用する。
開発レビューまでの作業
一時ブランチを作る
書式設定済み $ git hazama dev Branch dev set up to track remote branch master from upstream. Switched to a new branch 'dev'
開発する
途中で何度コミットしても構いません。最低1日に1回はコミットしてorigin/master
をマージしましょう。
途中のコミットはあとで捨てるので、コミットコメントは適当で構いません。書式設定済み $ git commit -a -m 'blur blur' $ git fetch origin $ git merge --no-ff origin/master (コンフリクトしたら修正して commit する) (git rebase は間違うと痛いので、使わないこと)
開発が完了したら
git hazama review
コマンドを実行する書式設定済み $ git hazama review dev xx (xx は実際には INFRA-535 なら 535 を指定します) $ git branch -D dev (ブランチ削除は意図的に hazama review でやらないようにしているので、自分で消す)
このコマンドでは以下のようなことが実行されます
- トピックブランチ INFRA-xx を作成
git merge --squash dev
git push origin INFRA-xx
- GitHub API で
hazama/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
- GitHub 上で PULL リクエストを確認する
レビュー担当者を指定できるので、指定しておきましょう レビュワーに PULL リクエストをレビューしてもらう
PULL リクエストは行単位でコメントをつけることができます。
レビュワーは承認したらマージボタンを押してマージしてください。
承認できないときはクローズせず、修正を追加コミットするよう指示します。情報 大幅に改修が必要な場合は、PULLリクエストをマージせずにクローズすることもあります。
その場合は、以下のようなフローになります。- まだorigin/masterにマージされたコミットがない場合
→ git push origin :INFRA-xxでブランチを消してやり直す。 - すでにorigin/masterにマージされたコミットがある場合(試験後に差し戻されたときなど)
→ 「試験で不具合がみつかったときの作業」と同じ
- まだorigin/masterにマージされたコミットがない場合
レビューが却下されたら、INFRA-xx ブランチから dev ブランチを作り開発を続ける
ちょっとした修正なら dev 作らず INFRA-xx で直接作業しても構いません。書式設定済み $ git checkout -b dev INFRA-xx (開発) $ git commit -m 'hoge' $ git checkout INFRA-xx $ git merge --ff --squash dev $ git commit -m 'INFRA-xx: fix a bug.' $ git push origin INFRA-xx $ git branch -D dev
トピックブランチに PUSH すると、以前の PULL リクエストに反映されるので、再度レビューしてもらう。
情報 マスターが更新されたため、レビュー承認後に PULL リクエストのマージが行えない場合があります。
この場合はorigin/master
を手元でマージして PUSH することで、PULL リクエストのマージが行えるようになります。レビューが通ってマージされたら、ローカルブランチを消す
(リモートブランチは消さない)書式設定済み $ git checkout master $ git pull (マージ後のソースに更新される) $ git branch -d INFRA-xx (-D で強制しなくても、マージされていたら消せるはず)
試験で不具合がみつかったときの作業
origin/INFRA-xx
からローカルブランチを作成する書式設定済み $ git checkout -b INFRA-xx origin/INFRA-xx $ git fetch origin $ git merge --no-ff origin/master
修正してコミットする
書式設定済み $ git commit -a -m "INFRA-xx: fix something."
git hazama fix
コマンドを実行する書式設定済み $ git hazama fix xx (xx は実際には INFRA-535 なら 535 を指定します)
このコマンドでは以下のようなことが実行されます
git push origin INFRA-xx
- GitHub API で
hazama/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
マージされたらローカルブランチを消す
(リモートブランチは消さない)書式設定済み $ git checkout master $ git pull $ git branch -d INFRA-xx
forest/infra
へのマージ
hazama/infra
関連のタスクは、試験完了後に forest/infra
にマージする必要があります。
マージしてほしい時期が近付いてきたら、forest に PULL リクエストを投げます。
GitHub の PULL リクエスト機能は投げる先のレポジトリ forest/infra@master
に対して、指定したブランチに存在するコミットをマージするように動作します。すでに作ってある INFRA-xx
トピックブランチは hazama/infra
にある、取り込まれるべきでないコミットも含んでいますので、INFRA-xx
から PULL リクエストを送ってはいけません。以下のように作業する必要があります。
forest/infra@master
からトピックブランチを作成する
こうするとhazama/infra
でまだあててはいけないコミットを含まないことが保証できます- 作成したブランチに
INFRA-xx
作成後に追加されたコミットをgit cherry-pick
で適用する
INFRA-xx
作成後に追加されたコミットを特定するのは、機械的にやるのはなかなか骨です。
c.f. Finding a branch point with Git? - コンフリクトが発生したら、修正をコミットして
git cherry-pick --continue
する - トピックブランチを origin に PUSH して PULL リクエストを
forest/infra
に投げる
以上のことをやってくれる git hazama pick
と git hazama stage
というコマンドがあります。
使い方は以下の通りです。
git hazama pick
で cherry-pick まで実行する
コンフリクトする場合はエラーで止まりますので、指示される通りに解決してください書式設定済み $ git hazama pick xx (xx は INFRA-353 なら 353 を指定) (INFRA-xx-forest トピックブランチを作成して cherry-pick します)
情報 コンフリクトするはずなんてないのにおかしい、といった場合は cherry-pick を中断してください。
書式設定済み $ git cherry-pick --abort $ git checkout master $ git branch -D INFRA-xx-forest
コンフリクトが解決したら、修正してコミットして continue します
書式設定済み $ vi ... $ git add ... $ git cherry-pick --continue
コミットメッセージには'INFRA-xx: fix conflicts.'と入れます。
git hazama stage
でトピックブランチを PUSH して PULL リクエストを投げます書式設定済み $ git hazama stage xx
このコマンドでは以下のようなことが実行されます
git push origin INFRA-xx-forest
- GitHub API で
forest/infra
に PULL リクエストを作成する - kintone に PULL リクエストの URL を追記する
- GitHub 上で PULL リクエストを確認
マージされたらローカルブランチを消す
書式設定済み $ git checkout master $ git fetch stable $ git branch -d INFRA-xx-forest (-D で強制しなくても、マージされていたら消せるはず)
ベストプラクティス
Git 編
- master で作業しない
必ずブランチを作って作業しましょう。 git pull
は基本的に使わないgit fetch
して、適宜 merge しましょう。
作業しない master ブランチはgit pull
で更新して構いません。- 一度 PUSH したブランチは rebase してはいけない
PUSH したあと、PUSH した履歴を書き換えちゃうことになるので、ダメ、絶対。 - むしろ
git rebase
しない
以下参考に。 - トップディレクトリには
.gitignore
を置いておく
こうすれば、他の人と add したくないファイルの設定を共有できます。
GitHub 編
- レポジトリは小分けにする
GitHub では誰でも自由にレポジトリを作れるので、関連性の薄いモジュールをひとつのレポジトリで管理する必要はありません。
小分けにしている方が、フォークやクローンが速くて良いです。 - 共有レポジトリの変更は PULL リクエストで
いきなり master に PUSH するのは止しましょう。
ブランチから PULL リクエストを投げて、レビューを受けるようにしてください。 - むやみに共有レポジトリをフォークしない
リソースがもったいないので、大きなレポジトリはむやみにフォークしてはいけません。
PUSH 権限がない別のチームのレポジトリに PULL リクエストを投げるようなときに、フォークしましょう。
Tips
共有レポジトリの変更(PULLリクエストとか)を追いたい
...
git diff -M COMMIT1...COMMIT2
で COMMIT2 にのみ含まれるコミットが表示されます。
単に差分を確認するだけなら git diff -M ..upsteam
です。
参考:
アップストリームに取り込まれていないコミットを知りたい
...
行の先頭が "+" がまだ取り込まれていないコミット、"-" は同等の変更がすでに取り込まれたコミットです。
fgrep +
にパイプすれば取り込まれていないコミットだけを確認できます。
変更を取り消したい
git commit --amend
直前のコミットを取り消して再コミットします。。
amend 以外指定しないと、コミットメッセージの修正ができます。git reset
--soft
指定されたコミット以降のコミットが消えます。index とワーキングコピーはそのまま。
直前のコミットを取り消すならgit reset --soft HEAD^
です。--mixed
(デフォルト)
指定されたコミット以降のコミットが消えます。
ステージングされた変更(index)を消えるが、ワーキングコピーはそのまま。--hard
指定されたコミット以降のコミットが消えます。index とワーキングコピーも戻ります。
コミットを指定しなければ HEAD になるので、git reset --hard
でsvn revert
相当です。
git rm --cached
git add
でインデックスにステージングされた変更を取り消せます。git reset --mixed
相当。git checkout -- FILE
FILE の変更を破棄して HEAD の状態に戻します。
変更は index にステージングされたままとなるので注意してください。git checkout COMMIT FILE
FILE の変更を破棄して指定したコミット時点に戻します。
参考:http://d.hatena.ne.jp/mrgoofy33/20100910/1284069468
...
書式設定済み |
---|
$ git checkout -b branch origin/master
(適当に編集)
$ git push -u origin branch
(これで作られる)
$ git remote show origin
(PUSH/PULL リモート設定を確認)
|
...
書式設定済み |
---|
$ git config --global core.pager "less -R" |
git の表示をカラフルにしたい
書式設定済み |
---|
$ git config --global color.ui auto |
...
git-hoge
みたいなコマンドを作って PATH の通っているところに置くだけです。
c.f. http://blog.thehippo.de/2012/03/tools-and-software/how-to-create-a-custom-git-command-extension/