Git 基礎最速マスター

id:repeatedly から無言の圧力を受けたので書きました。
タイトルは釣り。そもそも自分が Git マスターしてないし。突っ込み歓迎。超歓迎。
一応、このエントリだけで一つの Git リポジトリをそれなりに操れるようになることを目指してます。なので、コマンド一つ一つに対する説明じゃなくて、やりたいこと一つ一つに対する説明が中心です。え?それ最速マスターじゃない?きーこーえーなーいー。
あと、他のバージョン管理システム、例えば SubversionMercurial が使えることを前提としています。誰か「バージョン管理システム基礎最速マスター」とか書かないの?

インストール

Windows と Debian しか分かりませんので、自分のシステムに読み替えて行ってください。あと誰か Mac ください。
インストールも設定も終ってるよ!って方はリポジトリの作成までひとっ飛び

Windows

Windows では msysgit か Cygwin 版の Git のどちらかを入れることになります。
ちょっと試してみたい、って方は、msysgit でいいでしょう。
もし、Subversion と連携させたいとか、ファイル名に日本語を使って、更に Windows 以外の環境ともやりとりしたいなら、Cygwin 版を選択してください。
ここでは msysgit を前提に話をします。


まずは msysgit のページの右の「Featured downloads」の中からインストーラをダウンロードしてください。
現時点では 3 つ選択肢がありますが、with-cheetah 版は Vista や 7 では上手く動かなかったので、Vista や 7 を使っている方は一番上を使うのが無難です。
一番上の with-cheetah が付いていないものは、フォルダの何もない部分を右クリックしたときに Git のメニューが出ないのですが、with-cheetah 版では Git のメニューが出るようになっています。
なので、XP の方は with-cheetah を使うのもいいでしょう。
ただし、with-cheetah 版はコンテキストメニューの拡張をレジストリを弄るだけで実現していませんので、git bash here で開くアプリケーションを入れ替える際に、この方法が使えなくなります。


ダウンロードしたら、ダウンロードしたインストーラを実行します。
とりあえず使うことを目的としているので、何も考えずにデフォルト設定のままインストールしてしまいましょう。


次に、他に必要なアプリケーションをインストールします。
まずは nkf ですが、「nkf Windows インストール」で検索すると色々と出てくるので省略します。nkf.exe をパスの通った場所に置いてください。
また、LaTeX 等をインストールしている場合、nkf もインストールされている可能性がありますので、コマンドプロンプトnkf --version を実行してみて、実行できるようならそれで OK です。


Git ではコミットログが必須なので、エディタもダウンロードしておきましょう。
設定により Shift_JIS でログを保存することもできるのですが、後々を考えるとデフォルトの UTF-8 で保存しておくのが無難でしょう。
なので、エディタもデフォルトで UTF-8 で保存できるように設定可能なエディタを選んでおくのが楽です。
また、簡単に終了できるエディタだと更にいい感じなので、個人的には gvim をお勧めします。他にも Unicode 版のサクラエディタでも設定によりデフォルトで UTF-8 で保存するようにできます。


gvim を使う場合は、香り屋版を使うといいでしょう。
香り屋版の vim には verifyenc.vim というプラグインが入っており、これが空のファイルの fenc を cp932 に置き換えてしまうので、無効化しておきましょう*1
vimrc もしくは gvimrc に、

let g:plugin_verifyenc_disable = 1

と、

set fenc=utf-8

を記述しておけば utf-8 で保存してくれます。


Unicode 版のサクラエディタを使う場合は、とりあえずパッケージ版をインストールしてから、Unicode 版で上書きしてください。Unicode 版は sakuraW.exe と sakuraW.exe.manifest となっていますが、それぞれ sakura.exe と sakura.exe.manifest としてしまうのが楽です。
正規表現による検索が使いたい場合は、更にUnicode 対応の bregonig.dll も sakura.exe と同じ場所に解凍しておいてください。
デフォルトの保存エンコーディング方式を変更するには、Ctrl + 4 でタイプ別設定一覧を開き、「基本」を選択して設定変更ボタンをクリックしてください。
支援タブにデフォルト文字コードとあるので、これを UTF-8 にすれば OK です。

Debian

Debian では残念ながら Git のバージョンが古いので、ソースからビルドしてインストールします。
一度簡単にインストール出来る Git をインストールし、最新の Git のリポジトリを取得してそのソースコードをビルドしています。
ソースを wget で拾ってきてもいいのですが、せっかくなのでリポジトリも落としておきましょう、ということで。

$ sudo aptitude -y install git-core
$ git clone git://git.kernel.org/pub/scm/git/git.git
$ sudo aptitude -y remove git-core
$ sudo aptitude -y build-dep git-core
$ sudo aptitude install libssl-dev
$ cd git
$ make prefix=/usr/local all
# sudo make prefix=/usr/local install
$ GITURL='http://www.kernel.org/pub/software/scm/git'
$ wget $GITURL/git-manpages-1.7.0.1.tar.gz $GITURL/git-htmldocs-1.7.0.1
$ su
# mkdir -p /usr/local/share/doc/git-doc /usr/local/share/man
# cd /usr/local/share/doc/git-doc && tar xf /home/bleis/git-htmldocs-1.7.0.1.tar.gz
# cd /usr/local/share/man && tar xf /home/bleis/git-manpages-1.7.0.1.tar.gz
# cp /home/bleis/git/contrib/completion/git-completion.bash /etc/bash_completion.d/git

シェルに bash を使っている場合、.bashrc に以下の記述を入れておくと便利です。

# コメントアウトされている場合はコメントを外し、
# そもそも記述がない場合は追加する
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi

# この記述を追加
# msysgitのGitインストールフォルダ\etc\profileを参考にした
PS1='\[\033[32m\]\u@\h \[\033[33m\w$(__git_ps1)\033[0m\]
$ '

こうすることで、Git のリポジトリにいるときに現在チェックアウトしているブランチが常に表示されるようになります。

設定

msysgit 固有の設定

Windows で msysgit を選んだ場合はここの設定を行ってください。


まず、Git のインストールフォルダ以下の etc\profile の最後に

# git logなどで文字化けしないための設定
export GIT_PAGER="nkf -s | LESSCHARSET=utf-8 less"
# コミットメッセージ入力用エディタの設定
export GIT_EDITOR="'C:\Program Files\vim72-kaoriya-w64j\gvim.exe'"

と追記します。エディタはお好きなものをどうぞ。
次に、Git のインストールフォルダ以下の etc\inputrc の

# disable/enable 8bit input

から空白行までを、

set convert-meta off
set meta-flag on
set output-meta on
set kanji-code utf-8

に書き換えます。

共通の設定

Windows でも Debian でも必要な設定です。


Windows の場合、スタートメニューにある Git から Git Bash を選択してシェルを開きます。Debian は X-Window 入れてないのでそのままです。GUI を入れてる方は各々好きな方法でシェルを開いてください。
開いたら、

$ git config --global user.name bleis-tift
$ git config --global user.email hey_c_est_la_vie(at)hotmail.co.jp
$ git config --global color.ui auto

と、ユーザ名、メールアドレスを設定してください。ユーザ名に空白を含む場合、ダブルクォーテーションで囲むなどしてください。これらの情報は、コミット時に Git がログに含めますので、必ず設定する必要があります。
3 行目は git status コマンドを実行した際に色が付いて見やすいため、実行しておくことをお勧めします。


これで Git を使う準備が整いました。

リポジトリの作成

まず最初に、リポジトリを作らなければいけません。
Git でリポジトリを作る方法は、大きく分けて 2 つあります。

  1. 空のリポジトリを作る
  2. 他のリポジトリのクローンを作る
空のリポジトリを作る

新規プロジェクトを作るような場合に空のリポジトリを作ります。
コマンドは簡単で、

$ git init

だけです。
Subversion では、これに対応する操作は

$ svnadmin create ~/name
$ svn checkout file:///home/bleis/name

です。
Subversion ではリポジトリと作業ディレクトリは別の場所にありますが、Git では Subversion で言うところの作業ディレクトリ (Git では作業ツリーと呼びます) の一番上のレベルにリポジトリが存在します。
そのため、上のようにリポジトリのみを作ればよく、作業ツリーはリポジトリを作った場所をルートにそれ以下すべて、と言うことになります。


また、git init ではリポジトリのみを作るため、すでにファイルが存在するような場所でも問題なく実行できます。
Subversion の場合は・・・checkout する前に import して、ディレクトリ内のデータをいったんすべて削除してから checkout、です。面倒ですね。それにリポジトリに登録したくないファイル群はどこか別の場所に退避させると言ったことも必要です。面倒です。

他のリポジトリのクローンを作る

すでに開発が進んでいるプロジェクトに参加したり、そのプロジェクトからフォークした新しいプロジェクトをはじめる場合には、他のリポジトリをクローンします。
これもコマンドは簡単で、

$ git clone リポジトリのパス

です。リポジトリの名前を自分で付けたい場合、

$ mkdir myproj && cd myproj
$ git clone リポジトリのパス .

のようにします。
Subversion でこれに対応する操作は、上で紹介した checkout になります。

状態の確認

状態の確認は、

$ git status

とします。Subversion など他のバージョン管理システムでもよくありますね。

インデックスの編集

Git では、リポジトリと作業ツリーの間にインデックスという領域を設けています。
このインデックス上で次のコミットを練り上げてからリポジトリにコミットします。
そのため、Subversion よりも一手間かかってしまうように見えるのですが、これにより Git の柔軟性につながっています。
が、一応最速マスターということもあるので、インデックスはほぼ無視して話を進めます。Better C ならぬ Better Subversion としての Git、ということです。

Git にまだ登録していないファイルを登録する

順番から行けばまずはまだ Git に登録していないファイルの登録方法からでしょう。

$ git add ファイル名

です。Subversion でも

$ svn add ファイル名

ですが、Git では add はそれ以外にも使いますので、そのことを頭の片隅にでも置いておいてください。
ちなみに、現在のディレクトリのすべてを add するとき、Git と Subversion では微妙に方法が違います。
Git では、

$ git add .

を使うのに対して、Subversion では

$ svn add *

を使います。Git でも * を使えるのですが、* はシェルの機能なので、. の方をよく使います。

間違えて add してしまったものを取り消す

間違えて add して閉まった場合、Git では

$ git rm --cached ファイル名

とします。Subversion では、

$ svn revert ファイル名

とします。ここは Git がちょっと面倒ですね。
また、Git にも revert というコマンドがあるのですが、これは Subversion のものとままったく違う機能ですので、とりあえず Git で revert コマンドは実行しないようにしましょう。

コミット

指定ファイルをコミット

あるファイルをコミットする場合、

$ git add ファイル名
$ git commit

としてコミットします。また、Git ではコミットメッセージが必須なので、エディタが起動します。コミットメッセージを入力して保存し、エディタを終了したらコミットは終了です。
Subversion では、

$ svn commit ファイル名

とするところです。Git では commit コマンドにファイル名を渡すことができません。その代わりに add コマンドを使って次に commit するファイルを登録していきます。
次のコミットに含めたいファイルがすでに Git に登録されているものばかりの場合、次のショートカットが使えます。

$ git commit -a

また、m オプションによりコミットメッセージを直接指定することも可能です。

$ git commit -am "commit summary

detail message"
コミットメッセージの形式

Git ではコミットメッセージの1 行目にそのコミットの概要を書き、2 行目を空行に、3 行目以降に詳細を記述するという形式が推奨されています。
この形式を前提としたコマンドもありますので、この形式を使っておくと何かと便利です。

作業ツリーにした編集を戻す

Subversion では間違って add してしまったものを戻すのも、作業ディレクトリにした編集を戻すのも、revert コマンドで行いますが、Git では違うコマンドを使用します。
間違って add してしまったものを戻すためには、上で説明したとおり rm コマンドを使用しますが、作業ディレクトリにした編集をリポジトリの状態まで戻すためには

$ git reset --hard ファイル名

とします。
ここで、ファイル名を省略すると作業ディレクトリの状態がリポジトリの状態と同じになります。つまり、まだ Git に登録されていないファイルはすべて削除されますので、注意してください。

一つ前のコミットを修正する

「あ、コミットメッセージに typo があった・・・」とか、「あ、あのファイル add するの忘れてた・・・」など、コミットしてから間違いに気付くことはたまにあるかと思います。いや、よくあります。
Git では、一つ前のコミットは簡単に修正可能です。

コミットメッセージを修正する

コミットメッセージを修正したい場合、

$ git commit --amend

とするだけです。エディタが立ち上がり、コミットメッセージを修正して保存し、エディタを終了するだけでコミットメッセージの修正が完了します。

add し忘れを修正する

add し忘れた場合、

$ git add addし忘れたファイル
$ git commit --amend

です。

編集間違いを修正する

例えば、Hoge.cs というファイルに間違った編集を加えてしまった場合にそれを修正するには、まず Hoge.cs を正しい状態に編集してから、

$ git add Hoge.cs
$ git commit --amend

です。


このように、一つ前のコミットのちょっとしたミスは簡単に修正可能です。他にも、add してはいけなかったファイルを add したまま commit してしまったこともやり直せます。基本的に、どんな種類のやり直しも可能です。
Subversion では、コミットメッセージの修正くらいは可能ですが、それ以外は難しい上、危険です。

ログを見る

コミットの概要のみ見る

コミットの概要、つまりコミットメッセージの 1 行目だけ見たい場合、

$ git shortlog

とします。これを実行すると、ユーザ毎にコミットメッセージの 1 行目が表示されます。
表示するログを少なくしたい場合、「-」に続けて表示するログの数を指定します。
例えば、-10 と指定すると一番新しいものから 10 個のコミットに対するコミットメッセージの 1 行目が出力されます。

もう少し詳しく見る

もう少し詳しい情報が見たい場合、

$ git log

とします。
これにより、コミットに対して一意に定まるハッシュ値、Author、日付、コミットメッセージが確認できます。
shortlog で説明したような、コミットメッセージの個数の制限も可能です。

フィルタリング

Git のログはフィルタリング機能が豊富です。

作者でフィルタリング
--author=作者
日付でフィルタリング
--since=日付, --until=日付
正規表現でフィルタリング
--grep=正規表現

などなど、様々なフィルタリングが可能です。

ブランチ

Git のブランチは Subversion のものと比べ、すべてにおいて高速です (仕組みが全く違います)。特に、branch の切り替えがすぐに終るので、複数のブランチを渡り歩くなんてことも苦になりません。
また、Git のブランチはデフォルトではそのリポジトリのみに作られる「ローカルブランチ」なので、他人を気にせずに色々なことが可能です。

ブランチを作るタイミング・作り方

Git では、作業ごとにブランチを作ると良いでしょう。
何かの作業を始める前に、その作業を行う専用のブランチを作るのです。このとき、ブランチの名前は深く考えず、自分が分かれば何でもいいでしょう。自分のリポジトリのみのブランチなので、好き勝手にやって良いのです。

$ git checkout -b ブランチ名

これでブランチを作成し、そのブランチに切り替えます。
このエントリどおりにインストールした場合、

bleis@debian ~/hoge (master)
$

から、

bleis@debian ~/hoge (ブランチ名)
$

のようになったはずです。この括弧の中が今いるブランチを表しています。
このエントリとは違う方法でインストールした場合、もし git-completion がインストールされ有効にした場合は上のようになりますが、そうでない場合はそもそも master という名前はどこにもないはずです。
そう言う場合に今のブランチを確認するためには、

$ git branch
* ブランチ名
  master

のように、branch コマンドを使用します。現在のブランチには先頭に「*」が付きますので、これで確認できます。
この機能はブランチを多用する Git では非常に重宝しますので、シェルが bash なら是非有効にしてください。zsh などを使っている場合でも、似たような機能は簡単に実現可能ですし、Web 上にも情報が色々ありますので、是非使いましょう。


ちなみに、master ブランチはデフォルトで作られるブランチで、Subversion での trunk と同じようなものと思っておけばいいでしょう。
そして、作業用に作ったブランチで作業を終えた後は master ブランチにその作業を反映することになります。

作ったブランチでの作業を master に反映する

ブランチでの作業を master に反映するには、

$ git rebase master
$ git checkout master
$ git merge ブランチ名

とします。
2 番目のコマンドはブランチを切り替えるコマンドで、master ブランチに切り替えています。
ここで他のブランチ名を指定すると、当たり前ですがそのブランチに切り替わります。


ブランチを他のブランチに反映しているわけですから、競合する可能性があります。
競合は、1 番目のコマンド実行中に発生する可能性があります。3 番目ではありません。1 番目です。
競合が発生した場合、処理が中断し、

bleis@debian ~/hoge (ブランチ名|REBASE)
$

のような表示になります。
git status でどのファイルが競合しているかを確認してください。
競合を解決し、ファイルを保存したら、

$ git add .
$ git rebase --continue

とします。
もしその競合がその場で解決できないようなものの場合、処理を中断する必要があります。

$ git rebase --abort

として、処理を中断しましょう。

不要になったブランチの削除

master ブランチへの反映が完了したブランチは、もう用済みなので削除してしまいましょう。

$ git branch -d ブランチ名

このように、Git では比較的短命なブランチを多用します。
比較的短命な上、ローカル環境のみで有効なブランチなので、上の方で名前は自分が分かればいい、としたのです。
もし BTS/ITS を使っている場合はチケット番号を振っておけばいいでしょう。


Git と Subversion とではブランチの仕組みが全然違うので、単純に比較することはできないのですが、Subversion のブランチの作成や切り替え・元のブランチへの反映は動作が重い上にコマンドも長く面倒です。
それに対して Git ではとても単純な方法でこれらが可能な上、動作も高速なので、どんどんブランチを活用していきましょう。

タグ

Subversion ではブランチをタグとして使う、というものでしたが、Git ではタグとブランチは別物です。
そのため、Subversion のようにタグなのにタグを打った時点から内容が変更される、ということはありません。
また、タグもブランチと同様、基本的にはそのリポジトリのみで有効です。

タグを作る

タグを作るには、

$ git tag タグの名前

とします。
タグは分類のために「/」で区切ります。ブランチでも可能なのですが、Git ではブランチは比較的短命な場合が多いため、あまり分類しても意味がありません。
それに対してタグは作ったら基本的に消しませんので、分類しておくことは良い習慣です。
例えば、

  • バグ対応のタグは「bug/」に続けてチケット番号を付ける
    • バグ対応が複数コミットに渡った場合、対応を開始したコミットは「bug/チケット番号/open」というタグを付け、対応を完了したコミットには「bug/チケット番号/close」というタグを付ける
  • 機能追加のタグは「issue/チケット番号/open」と「issue/チケット番号/close」とする
  • リリースを行ったコミットを表すために「release/リリースバージョン」というタグを付ける

のようにします。

その先へ

Git と言えば分散型のバージョン管理システムです。
ここまででローカルの作業はそれなりにできるようになったと思いますが、それだけじゃつまらないですよね。
と言うことで、その先への案内です。


・・・と言いつつ、まずはこちら。
チュートリアルやユーザーマニュアルが訳されています。ありがたや。

また、日本語で読める素敵な本が 3 冊もあります。

実用 Git が出るまでは、入門 Git 読んで入門 git 読むのがいいかな、って感じだったんですが・・・
ぶっちゃけ、入門 git はもう読む必要ないんじゃないでしょうか?
入門 Git 読んで、実用 Git 読むのがいいと思います。
入門 Git が最初から Git 内部のことに少し触れるので、そこでつまずく場合は入門 git を読むようにするといいです。


さらにさらに、Web 上で Pro Git が読めます。
ブランチの説明がとても分かりやすかったので、是非どうぞ!


このブログでも何回か Git を取り上げていますので、よかったらそちらもどうぞ。


あー、誰か Git 基礎最速マスターリモートリポジトリ編とか GitHub 基礎最速マスターとか書いてくれないかなぁ・・・

Mercurial

id:Akineko (秋猫さん) が Mercurial の最速マスターを書いてくれました!やったね!
Mercurial基礎最速マスター -初期設定・基本編- - Akinekoの日記

*1:もしくはプラグインを改造して utf-8 になるようにしてしまうか。自分はこちらの方法を使っています。

コマンドの数

Git はコマンドが多すぎてどれから手を付けて良いか分からない!って理由で Mercurial や他の DVCS に流れてしまう人はある程度いるんじゃないかと思います。
実際、そういうエントリをいくつか見たことがあります。
確かに、git help -a とすると、楽勝で 100 個を越えるコマンドが表示されます。確か 138 個だったと思います。
でも、git help と打ってみてください。最新版の 1.7.0.1 でも 21 個しか出てきません。Git を普通に使う分にはその程度のコマンドを理解していればいいのです。
このように、オプションを付けなければ Git 開発者がよく使うコマンドと判断した 21 個が分かるのです。とりあえずはこの 21 個からはじめればいい、という指針になります。


では、他のバージョン管理システムはどうなのか?というのが気になって調べてみました。

VCS help で表示されるコマンド数
Git 21
Mercurial 87
Bazaar 14 だけど実質 12
Monotone 13 だけど実質 33
Darcs 33
Subversion 33
CVS 32

Bazaar が実質の個数が少ないのは、bzr help の説明が 3 つに分かれているからで、
Monotone が実質の個数が多いのは、コマンドの前にオプションについての説明も入っているからです。
コマンドの実質の個数を並び替えると、

Bazaar < Git < CVS < Darcs/Subversion < Monotone < Mercurial

となります。ヘルプという点では Bazaar が非常に優秀です。短くまとめられているだけでなく、グループ化も行われており、非常に分かりやすいです*1
それに対して Mercurial は、すべてのコマンドを表示してしまっており、どれからはじめればいいのかここからは全然分かりません。
Mercurial ユーザからすると、「最初に見るのはそこじゃない!」という反論があるかもしれませんが、それだったら Git だって「コマンド数全体じゃなくて最初にこの 21 個のコマンドをやればいい!」となりますよね。


なので、Git がコマンド数が多いことを理由に避けられるというのは非常に悲しいものがあります。
これからはこの 21 と言う数字を押し出していけば、こういう事態が避けられるような気がします。


また、コマンドが多いことは問題になるかというと、むしろ便利なことの方が多いと感じています。
例えば、あるコミットでの変更のみを他のブランチにも適用したい場合に、Git では cherry-pick というコマンドが使用できます。

$ git cherry-pick bug/123

とするだけで、bug/123 での修正を現在のブランチに対して適用することができるのです。
これを例えば Subversion でやろうと思ったら、

$ svn merge -c 2137 file:///path/to/trunk
特定のリビジョンだけマージ(Cherry Picking)

このようになります。
さて、どちらが分かりやすいでしょうか?
Subversion との比較で言えば、ブランチの作成や切り替えでも同じようなことが言えます。
コマンドが多いことは、慣れてしまえばむしろ武器になりうるのです。

*1:ただし、pull や push と言った DVCS の特徴であるコマンドが一覧にありませんが・・・まぁ、Bazaar は DVCS としても集中管理型としても使えるので、こういう判断もアリだと思います