これは cybozu.com のインフラ開発チームが社内で使用しているマニュアルを一部修正したものです。 文中の GitHub はほとんどの場合、サイボウズ社内で利用している GitHub Enterprise のことを指しています。 |
Git は分散バージョン管理システムと呼ばれるものの一つです。Subversion と比較すると、高機能だが複雑で難しいと言えます。「分散」とついているのは Subversion のように中央レポジトリがあるのではなく、各個人が手元に所有する分散したレポジトリを同期して使うモデルを採用しているためです。とはいえ、現実的にはほとんどのチームで GitHub でホストする共有の中央レポジトリを持つことになるでしょう。こうした場合 git の最大の特徴は後述するブランチとマージの管理が優れていることです。例えば、特定の不具合の修正を他のブランチに取り込むといったことが簡単にできます。
Subversion のことは忘れましょう。利用できる機能は表面上似ているものも多いのですが、それを実現している内部の方式がまったく異なるため、たとえばマージで行われていることは Subversion の知識で理解しようとしてもうまくいきません。マージやチェックアウトやブランチという言葉は共通で使われていますが、Subversion の動作から理解しようとしても無理です。
まずは以下の資料を読んでおきましょう。
以下の用語が理解できたと思います。
あとはリモートレポジトリの取り扱い方法を学んでおきましょう。
Git は分散したレポジトリを同期することで、共同作業をできるようにします。同期するにはまず手元にリモートレポジトリを取り寄せます。取り寄せ方は二通りあります。
リモートレポジトリのクローンを手元に作成する方法
$ git 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 origin stable |
git clone
は origin
という名前でリモートレポジトリを手元に取り寄せます。実際には以下のような操作と同等のことをしています。
git remote add origin
URLorigin
という名前で登録して、 git fetch origin
origin
のコミットグラフを取り寄せる二つ以上のリモートレポジトリを取り寄せるのは、この git remote add
以降の操作を繰り返しているだけです。
取り寄せた後は、なにかを、いじって、リモートに反映したいですね。まずなにをいじるのでしょう?
答えはリモートブランチです。どんなブランチがあるか git branch -r
で確認してみましょう。
$ git branch -r origin/HEAD -> origin/master origin/INFRA-1000 origin/master stable/master |
origin に master
, INFRA-1000
と stable に master
ブランチがあることがわかります。origin/master
に対してなにかフィーチャーを実装することにしたとしましょう。次にやることは、ローカルブランチを origin/master
から分岐して作ることです。
$ git checkout -b INFRA-1001 origin/master $ git branch * INFRA-1001 master $ git remote show origin * remote origin Fetch URL: github:hazama/infra Push URL: github:hazama/infra HEAD branch: master Remote branches: INFRA-1000 tracked master tracked Local branches configured for 'git pull': INFRA-1001 merges with remote master master merges with remote master Local refs configured for 'git push': master pushes to master |
INFRA-1001
というローカルブランチが作成され、origin/master
を追跡しているのがわかります。
この INFRA-1001
ブランチで作業し、コミットすると、そのコミットはローカルレポジトリに保存されます。
ローカルレポジトリに保存したコミットグラフをリモートに反映するには git push
を使います。
$ git commit -a -m 'add xxx.' $ git push -u origin INFRA-1001 |
このコマンドを実行すると、リモートレポジトリにも INFRA-1001
というブランチが作成されます。
すでに INFRA-1001
ブランチがある場合は、差分のみ送信されます。差分はファストフォワードマージできる状態でなければなりません。
二つ以上のリモートレポジトリを持つのはどういう場合でしょうか? 以下のような利用方法が考えられます。
|
git は利用者が多いのでチュートリアル資料もたくさんあります。以下がおすすめです。
git は基本的には個人で使うための機能しかなく、レポジトリを共有管理する機能は充実していません。レポジトリの共有管理をするためには gitolite のようなオープンソースツールもありますが、gitolite プロジェクト自体も GitHub でホスティングされているように、git レポジトリホスティング機能は GitHub がダントツに優れています。
GitHub (Enterprise) ではレポジトリは個々の利用者が自由に作ることができます。共有レポジトリをフォークすることも自由です。
共有レポジトリを管理するために Organization という仕組みがあり、Organization は複数の Owner が共同管理できます。
Organization は複数の Team を持つことができ、チームごと所属するメンバー、レポジトリ、および PUSH, PULL の権限を制御できます。
Organization は誰でも作ることができます。
GitHub ではコミットや差分の行単位でコメントをつけることができます。コメントは GitHub の通知機能やメールで通知されます。
メール通知は個人設定で止めることもできます。特定のレポジトリを watch すると、そのレポジトリの変更が通知されます。
ユーザーの顔写真には Gravatar というサービスを利用して表示しています。顔写真がないと誰が操作したのかわかりにくいので、GitHub に登録したら必ず Gravatar を設定しましょう。Gravatar でアバターを指定するメールアドレスは、GitHub で登録されているメールアドレスにしてください(メールアドレスが主キーです)。
あとは "@ユーザー名" と書くとそのユーザーに通知してくれるメンション機能があります。
GitHub で特に有名な機能に PULL リクエストがあります。フォークしたレポジトリ間やブランチ間で、特定の差分を取り込んでもらうように GUI で依頼する機能で、依頼を受けた側はボタン一つでマージできます。差分の行単位でコメントをつけることができるので、レビューツールとしても非常に便利に使えます。
PULL リクエストは担当者を指定できるので、レビューを依頼するユーザーに設定しましょう。
PULL リクエストはフォークしたレポジトリ間でなくとも、ひとつのレポジトリのブランチ間でも投げることができます。 |
PULL リクエストは実際には |
レポジトリ管理とは無関係の、コードスニペットを共有する機能です。
GitHub のおまけ的機能ですが、script タグで他のページに埋め込める等なかなか便利です。
GitHub はマークダウン記法でコメントやドキュメントを書く機能があります。
各レポジトリにはこのマークダウン記法でページを作成できる Wiki 機能が付属しています。
Wiki システムは Gollum というものです。詳細はリンク先を読んでください。
簡単な使い方:
ページ間リンクは [[
で書く
[[PageName]] [[Title|PageName]] |
レポジトリごとにタスクや不具合を管理する Issues 機能がありますが、非常に簡素なものですので kintone や JIRA の代わりにはなりません。
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 にログインしてパスワードを変更する
招待メールが届いているはずですので、処理してください
手元の 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 |
$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 のタスク管理 アプリを使います。
大まかな流れは以下になります。
hazama/infra
に PULL リクエストを投げる。forest/infra
に投げる。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 でやらないようにしているので、自分で消す) |
このコマンドでは以下のようなことが実行されます
git merge --squash dev
git push origin INFRA-xx
hazama/infra
に PULL リクエストを作成するレビュワーに PULL リクエストをレビューしてもらう
PULL リクエストは行単位でコメントをつけることができます。
レビュワーは承認したらマージボタンを押してマージしてください。
承認できないときはクローズせず、修正を追加コミットするよう指示します。
大幅に改修が必要な場合は、PULLリクエストをマージせずにクローズすることもあります。
|
レビューが却下されたら、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 リクエストのマージが行えない場合があります。 |
レビューが通ってマージされたら、ローカルブランチを消す
(リモートブランチは消さない)
$ 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
hazama/infra
に PULL リクエストを作成するマージされたらローカルブランチを消す
(リモートブランチは消さない)
$ 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
作成後に追加されたコミットを特定するのは、機械的にやるのはなかなか骨です。git cherry-pick --continue
する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 を中断してください。
|
コンフリクトが解決したら、修正してコミットして 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
forest/infra
に PULL リクエストを作成するマージされたらローカルブランチを消す
$ git checkout master $ git fetch stable $ git branch -d INFRA-xx-forest (-D で強制しなくても、マージされていたら消せるはず) |
git pull
は基本的に使わないgit fetch
して、適宜 merge しましょう。git pull
で更新して構いません。git rebase
しない.gitignore
を置いておくWatch しましょう。すると、ログイン後の News Feed にアクティビティが出てきます。
通知を受け取りたければ、News Feed の RSS (トップページ右上あたり)を購読しましょう。
社内サーバーの RSS なので、社内で使える RSS リーダーが必要です。Chrome を使っていれば Slick RSS 辺りが便利です。
.bashrc の PS1 設定を以下のように変更しましょう。
git_branch() { echo $(git branch 2>/dev/null | sed -rn "s/^\* (.*)$/\1/p") } if [ "$color_prompt" = yes ]; then PS1='\[\033[32m\]\h\[\033[00m\]:\[\033[01;34m\]$(git_branch)\[\033[00m\]:\w\$ ' else PS1='\h:$(git_branch):\w\$ ' fi |
git diff -M
や git log -M -p
のように -M
を指定します。
さもないと、ファイルの削除と新規追加というようにばらばらに表示されてしまい、わかりにくいです。
$ git fetch upstream $ git diff -M ...upstream |
git diff -M COMMIT1...COMMIT2
で COMMIT2 にのみ含まれるコミットが表示されます。
単に差分を確認するだけなら git diff -M ..upsteam
です。
参考:
たとえば forest/infra
にまだ取り込まれていない hazama/infra
のコミットを知るには、以下のように git cherry
を使います。
$ git fetch testing $ git fetch stable $ git checkout testing/master $ git cherry -v stable/master + f10efc4e51b54251fe17968c3585b73718e04ff7 INFRA-398 + 968576c93041f79d570e229f183aae0ebb1d2d21 INFRA-502 + 7d441aff55a641be7a6c48b45af5ba3f6b396d93 INFRA-553 - 7e4723cf1597b9ba8a4095c5fc70290912303d62 INFRA-555 - 390504e8496a6ac5ad4b0d4b5b557e2d07fddc0b INFRA-564 |
行の先頭が "+" がまだ取り込まれていないコミット、"-" は同等の変更がすでに取り込まれたコミットです。
fgrep +
にパイプすれば取り込まれていないコミットだけを確認できます。
git commit --amend
git reset
--soft
git reset --soft HEAD^
です。--mixed
(デフォルト)--hard
git reset --hard
で svn revert
相当です。git rm --cached
git add
でインデックスにステージングされた変更を取り消せます。git reset --mixed
相当。git checkout -- FILE
git checkout COMMIT FILE
参考:http://d.hatena.ne.jp/mrgoofy33/20100910/1284069468
未コミットの修正をまだコミットしたくない時に別のブランチで作業をしたくなることは良くあります。git stash
を使うのも手ではありますが、結構面倒です。
以下のように git new-workdir
を使えるようにしておくととても便利。
$ sudo cp /usr/share/doc/git/contrib/workdir/git-new-workdir /usr/local/bin $ sudo chmod a+x /usr/local/bin/git-new-workdir |
参考:http://subtech.g.hatena.ne.jp/secondlife/20121207/1354854068
$ git show HEAD^:<filename> |
リモートブランチはローカルブランチを PUSH することで作成できます。
$ git checkout -b branch origin/master (適当に編集) $ git push -u origin branch (これで作られる) $ git remote show origin (PUSH/PULL リモート設定を確認) |
リモートブランチの削除も PUSH することで行います。
$ git push origin :branch |
巻き戻したいコミットの SHA1 サムを特定して、
$ git push origin +SHA1SUM:branch |
とするとリモートブランチが SHA1SUM まで巻き戻ります。SHA1SUM 自体は残ります。
git push origin branch
は実は git push origin branch:branch
の省略記法です。
なので、以下のようにするとリモートの別の名前のブランチに PUSH できます。
$ git push origin local_branch:remote_branch |
こちらを参考に。
git whatchanged --oneline
で一覧できます。
特定のコミットのみ調べたいなら、git show --name-only --oneline COMMIT
です。
git status
を読みやすくしたい$ git status -s M hoge ?? fuga |
ローカルで作って git push --tags
します。
$ git tag v1.1.0 $ git push --tags origin |
$HOME/.gitconfig に [alias] セクションを追加することで作成できます。
以下、記載例です。git l
あたりは便利なのでおすすめ。
[alias] st = status -sb co = checkout ci = commit del = !git checkout master && git branch -D p = push -u br = branch up = fetch --verbose --prune mg = merge --squash so = remote show origin df = diff --find-renames dfc = diff --cached --find-renames dfs = diff --staged --find-renames pick = cherry-pick changed = whatchanged l = log --pretty=format:\"%ci %C(yellow)%H%Creset [%cn] %Cgreen%s %C(cyan)%d%Creset\" -10 lg = log --graph --all --color --pretty='%x09%h %cn%x09%s %Cred%d%Creset' |
エスケープシーケンスで色を付けていますが、うまくできない人は以下を試してください。
$ git config --global core.pager "less -R" |
$ git config --global color.ui auto |
git stash
を使うと、変更を一時領域に保存して、あとで取り出すことができます。
$ git branch * master $ git stash $ git checkout -b dev testing/master $ git stash pop $ git diff |
git-hoge
みたいなコマンドを作って PATH の通っているところに置くだけです。
c.f. http://blog.thehippo.de/2012/03/tools-and-software/how-to-create-a-custom-git-command-extension/