Gitを使いこなすための20のコマンド

 LinuxカーネルやRuby on Rails、Perlなど、近年多くの大規模プロジェクトで採用されているバージョン管理システムが「Git」だ。Gitには非常に多数のコマンドが用意されているが、日常的に使用するコマンドは20個程度と言われている。本記事では、Gitを使いこなすために覚えるべき20個のGit基本コマンドを紹介する。

 LinuxカーネルやRuby on Rails、Perlなど、近年多くの大規模プロジェクトで採用されているバージョン管理システムが「Git」だ。Gitには非常に多数のコマンドが用意されているが、日常的に使用するコマンドは20個程度と言われている。本記事では、Gitを使いこなすために覚えるべき20個のGit基本コマンドを紹介する。

 なお、Gitの基本的な考え方や使い方については分散バージョン管理システムGit入門でも紹介しているので、そちらも参照してほしい。

リポジトリの作成およびメンテナンスに利用するコマンド

コマンド1:「git init」-リポジトリを作成する

 Gitを利用するには、まずリポジトリの作成が必要だ。リポジトリ作成を行うコマンドは「git init」である。リポジトリを作成したいディレクトリでこのコマンドを実行すると.gitディレクトリが作成され、Gitリポジトリの管理ファイル等がここに作成される。

$ cd <リポジトリを作成するディレクトリ>
$ git init

コラム:Gitが利用する管理ファイル

 Gitの管理ファイルは.gitディレクトリ内に保存される。このディレクトリ内にはさまざまなファイルが格納されるが、通常これらのファイルの存在を意識する必要はない。また、リポジトリの各種設定は.git/configファイル内に記録される。Gitには各種設定を行う「git config」コマンドが用意されているが、このファイルを手動で変更することでも設定変更が可能だ。

コマンド2:「git clone」-既存のリポジトリの複製を作る

 リポジトリの複製を行うには「Git clone」コマンドを利用する。このコマンドは既存のリポジトリからローカルにファイルをコピーして作業用のリポジトリを作成する、といった場合などに利用する。

$ cd <リポジトリを作成するディレクトリ>
$ git clone <複製したいリポジトリのURL>

 リポジトリのURLは表1のような形式で指定する。

表1 Gitで利用できるリポジトリURL
プロトコル 指定方法
rsync rsync://<ホスト名>/<Gitリポジトリのパス>
HTTP http://<ホスト名>[:ポート番号]/<Gitリポジトリのパス>
HTTPS https://<ホスト名>[:ポート番号]/<Gitリポジトリのパス>
git git://<ホスト名>[:ポート番号]/<Gitリポジトリのパス>
SSH ssh://[ユーザー名@]<ホスト名>[:ポート番号]/<Gitリポジトリのパス>
ローカルファイル <Gitリポジトリのパス>もしくはfile://<Gitリポジトリのパス>

 また、作成するディレクトリ名を指定することもできる。

$ git clone <複製したいリポジトリのURL> <作成するディレクトリ>

 git cloneはリポジトリの履歴情報までも含めてリポジトリを複製するため、大規模なプロジェクトの場合は多くのファイルを取得/コピーしなければならないことがある。もし最新のソースファイルを取得する目的のみで使用し、ソースファイルの修正を行わない場合は、「–depth」オプションで取得するリビジョン数を指定するとよい。

 たとえば最新リビジョンだけを取得したい場合、「–depth 1」と指定する。

$ git clone --depth 1 <複製したいリポジトリのURL>
コマンド3:「git fsck」-リポジトリの正当性チェックを行う

 リポジトリがもし破損した可能性がある場合、「git fsck」で破損している個所を検出できる。

$ git fsck

 また、完全なチェックを行うには「–full」オプションを付けてgit fsckを実行する。

$ git fsck --full

コラム:Gitの「danglingオブジェクト」

 「git fsck」では、「danglingオブジェクト」と呼ばれるテンポラリオブジェクトも検出される。danglingオブジェクトはリポジトリに変更を加える際に作成される中間ファイルのようなもので、たとえば「git add」で追加したファイルに別の変更を加えてコミットした場合などに残されるものだ。このファイルはストレージ容量を消費するものの、残っていても大きな害はないため、無視して構わない。また、後述の「git gc」コマンドを実行することで、一定期間(デフォルトでは2週間)よりも前に作成されたdanglingオブジェクトを破棄することができる。

コマンド4:「git gc」-リポジトリ内の不要なオブジェクトを削除し、最適化を行う

 「git gc」コマンドは、リポジトリ内のオブジェクトの圧縮(pack)や不要なオブジェクトの破棄などを行うものだ。これによってリポジトリが使用するストレージ容量を減らせるだけでなく、パフォーマンスの向上も期待できる。頻繁に実行する必要はないが、大量のコミットやマージを行った場合などには実行するとよいだろう。

$ git gc

作業ツリーやブランチを操作・管理するコマンド

コマンド5:「git status」-変更が加えられたファイルを表示する
コマンド6:「git diff」-ファイルに加えられた変更点をdiff形式で表示する
コマンド7:「git add」-コミットするファイルを指定する
コマンド8:「git commit」-変更点をコミットする

 リポジトリに新たにファイルを追加したり、変更を加えたファイルを指定するのに利用するコマンドが「git add」だ。どのファイルが追加/変更されたのかは、「git status」で確認できる。git statusを実行すると、次の例のように追加/変更されたファイルの情報が表示される。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#       modified:   HBPreferencesTransFormer.h
#       modified:   HBPreferencesTransFormer.m
#
no changes added to commit (use "git add" and/or "git commit -a")

 特定のファイルにどのような変更が加えられたかは「git diff」コマンドで確認できる。

$ git diff <変更を確認したいファイル>

 変更点を保存するには、git addコマンドで対象とするファイルを指定したのちに「git commit」コマンドを実行する。

$ git add <追加/変更したファイル1> <追加/変更したファイル2> ...
$ git commit

 また、git commitを「-a」オプションを付けて実行すると変更が加えられたファイルを自動検出してコミットできる。ただし、この場合新規に作成されたファイルはコミット対象にはならない。

$ git commit -a

 通常、git commitコマンドを実行するとエディタが起動してコメントメッセージの入力が求められる。エディタを起動したくない場合は「-m」オプションでメッセージを指定すればよい。

$ git commit -m "<コミットメッセージ>"
コマンド9:「git log」-コミットログを閲覧する

 「git log」でリポジトリのコミットログを閲覧できる。コミットログは新しいものから順に表示され、次の実行例のようにそれぞれのコミットについてそのコミットを表すハッシュ値とコミット者、タイムスタンプ、コメントが表示される。

$ git log
commit 0b70750bdf9b02597741301c695ff46bc75036d4
Author: hoge <hoge@users.sourceforge.jp>
Date:   Thu Mar 12 19:47:31 2009 +0900

    Cleaning codes and convert TAB to space.

commit 769735fbce0a0a23a2b7547003d43518b4ec96f3
Author: hoge <hoge@users.sourceforge.jp>
Date:   Thu Mar 12 19:43:09 2009 +0900

    Cleaning code, and add comments
 :
 :

コラム:Gitのコミットはリビジョンでなくハッシュで管理される

 CVSやSubversionではコミットを「リビジョン」という数値で管理するが、Gitの場合コミットをハッシュ文字列で管理している。たとえば特定のファイルをその過去のバージョンと比較する、といった場合、どのバージョンのファイルと比較するかはハッシュ文字列で指定する。なお、ハッシュ文字列でコミットを指定する場合、必ずしもすべてを入力する必要はなく、そのコミットを一意に特定できる先頭数桁を入力すれば良い。

 また、コミットの指定はハッシュだけでなく後述の「ショートネーム」と呼ばれるエイリアスのようなもので指定することも可能だ。

コマンド10:「git reset」-直前のコミットを取り消す

 コミット後に小さなミスなどに気付いた場合などに便利なのが「git reset」だ。たとえばコミット後に「git reset –soft HEAD^」と実行すると、直前に行ったコミットを取り消すことができる。

$ git reset --soft HEAD^

 この場合、作業ツリーの内容はコミット時のままで「コミットした」ということだけが取り消される。もし作業ツリーに加えた変更点までも取り消したい場合は、「–soft」の代わりに「–hard」を指定すればよい、

 また、コミットされていた内容は「ORIG_HEAD」という名前で参照できる。これを利用して、次のように実行することで現在の状態とコミットされていた状態の差分を表示できる。

$ git diff ORIG_HEAD

 修正後に再度コミットを行うには、下記のようにする。これを実行すると、先に入力したコミットメッセージを再編集してコミットが行える。

$ git commit -a -c ORIG_HEAD

 なお、git commitに「–amend」オプションを付けて実行することで、直前に行っていたコミットを訂正することができる。

$ git commit
(コミット後にミスに気付き、ミスを修正)
$ git commit --amend    (先に行ったコミットが、ミスを修正したものに置き換えられる)

 上記の操作は、次のような操作とほぼ同一の働きをする。

$ git commit
$ git reset --soft HEAD^    (コミット後にミスに気付き、コミットを取り消し)
(ミスを修正)
$ git commit -c ORIG_HEAD
コマンド11:「git revert」-作業ツリーを指定したコミット時点の状態にまで戻す

 「git revert」は作業ツリーを指定したコミット時点の状態にまで戻し、コミットを行うコマンドである。引数にはコミットを指定するハッシュ文字列もしくはタグ名などを指定する。

$ git revert <コミット名>

 git revertはgit resetと似ているが、作業ツリーを差し戻したという情報が作業履歴に残るのが異なる点だ。

ブランチを作成/管理するコマンド

コマンド12:「git branch」-ブランチ情報の表示およびブランチの作成
コマンド13:「git checkout」-ブランチの切り替え
コマンド14:「git show-branch」-ブランチの作成/変更/マージ履歴を表示

 現在のソースツリーを元に新たなブランチを作成するには、「git branch」を使用する。また、操作対象とするブランチを切り替えるには、「git checkout」を使用する。

 たとえば、新たに「temp01」というブランチを作成し、以後このブランチで作業を行うには次のようにする。

$ git branch temp01
$ git branch
* master
  temp01
$ git checkout temp01
Switched to branch "temp01"
$ git branch
  master
* temp01

 なお、git checkoutに「-b」オプションを付けて実行すると、新たにブランチを作成してそのブランチに切り替える、という作業が一発で行える。たとえば、「git checkout -b temp01」は、次の2つのコマンドを順に実行した場合と同じ結果になる。

$ git branch temp01
$ git checkout temp01

 どのブランチがどのブランチを元に作られたか、という情報は「git show-branch」で確認できる。git show-branchでは次の例のような出力を行うが、前半の「—」までがブランチ履歴、「—」から後半が最近のコミット履歴を表している。

$ git show-branch
! [master] add script merging google anal.'s log and OTP's log.
 ! [temp01] Cleaning codes and convert TAB to space.
  * [temp02] Cleaning codes and convert TAB to space.
---
 +* [temp01] Cleaning codes and convert TAB to space.
 +* [temp01^] Cleaning code, and add comments
++* [master] add script merging google anal.'s log and OTP's log.

 前半部分ではブランチが階層構造で表示されており、「*」が付いている行が現在の作業ブランチになる。また、[]内の文字列はそれぞれのコミット単位を表すショートネームだ。この例では、「master」から「temp01」ブランチが作成され、さらに「temp01」から「temp02」ブランチが作成されたことが分かる。

コマンド15:「git merge」-ローカルブランチのマージを行う

 「git merge」は、現在の作業ブランチに別のブランチで行われた変更点を取り込むコマンドだ。

$ git merge <変更点の取り込み元ブランチ>

 マージが成功した場合はそのままコミットも行われる。いっぽう、競合が発生したファイルには下記のような形式で競合している個所にマーカーが埋め込まれる。

<<<<<<< <ブランチ名>:<ファイル名>
<作業中ブランチの内容>
=======
<変更点の取り込み元(マージ元)ブランチの内容>
>>>>>>> <ブランチ名>:<ファイル名>

 たとえば、下記は「markup.pl」というファイルに対してマージを行い、競合が発生した例である。「<<<<<<< HEAD:markup.pl」から「=======」までが作業ブランチ内のmarkup.plに記述されていたもので、「=======」から「>>>>>>> e74597cbfdb9995e540ca9e8c8a6e79705e2889c:markup.pl」までがマージ元ブランチ内のmarkup.plに記述されていたものとなる。

sub ulist {
    if( $l =~ m/^☆(リスト.*)$/ ) {
      $cap = $1;
    }

<<<<<<< HEAD:markup.pl
    print "<ul>\n";
    while( $l =~ m/^・/ ) {
      $l =~ s/^・(.*)$/<li>$1<\/li>/;
      print "foo:$l\n";
      $l = <>;
=======
    print "<p><b>$cap</b></p>\n";
    print list_start( $cap );
    while( $l = <> ) {
>>>>>>> e74597cbfdb9995e540ca9e8c8a6e79705e2889c:markup.pl
      chomp $l;
      $l =~ s/&/&amp;/g;
      $l =~ s/</&lt;/g;
      $l =~ s/>/&gt;/g;
}

 なお競合が発生した場合、このマーカーを取り除いて競合を解消するか、もしくはマージを取り消すまでコミットが行えないので注意してほしい。

コマンド16:「git tag」-コミットにタグを付ける

 Gitではコミットをハッシュ文字列で管理しているため、ユーザー側から見るとどの文字列がどのコミットを表しているのか分かりにくい。「git tag」は、直前のコミットに対して分かりやすい別名(タグ)を付けるコマンドだ。

$ git tag <タグ名>

 タグ名を指定せずにgit tagを実行すると、現在のリポジトリ内にあるタグを確認できる。

$ git tag rev1    (「rev1」というタグを付ける)
$ git tag         (タグを確認する)
rev1
コマンド17:「git stash」-現在の作業ツリーの状態を一時的に保管する

 現在の作業中の状態をコミットせずに、一時的にほかのブランチに対して作業を行いたい、という場合に役立つのが、「git stash」コマンドだ。このコマンドでは、現在の作業ツリーの状態を一時的に保存しておくことができる。

$ git stash <保存名もしくはコメントなど>

 git stashの実行後は、git checkoutなどで作業したいブランチをチェックアウトすればよい。作業の完了後作業中だった作業ツリーを再度呼び出すには、元のブランチをチェックアウトしてから「git stash pop」コマンドを実行する。また、「git stash list」を実行すると、一時保存されている作業ツリーが一覧表示される。

$ git stash list
$ git stash pop
コマンド18:「git rebase」-ブランチの派生元(上流)を変更する

 「git rebase」は、「ブランチの派生元を変更する」という、CVSやSubversionにはなかったユニークな機能である。git rebaseがどのような処理を行うかは次の図1を参照してほしいが、簡単に言えばあるブランチに対して行った変更点を、派生元のより新しいリビジョンのものに適用するものだ。

図1 「git rebase」のイメージ
図1 「git rebase」のイメージ

 図1の例の場合、ブランチAから派生したブランチBに対して、「変更α」と「変更β」、「変更γ」という3回のコミットを行っている。また、ブランチBを作成したのち、ブランチAには複数のコミットが行われている。このような状態でブランチBに対し「get rebase ブランチA」を実行すると、ブランチAの最新版に対して、ブランチBを作成してからブランチBの最新版までの間に加えられた変更(この場合変更αと変更β、変更γ)が適用され、それがブランチBの最新版となる。

 git rebaseを利用するには、作業を行いたいブランチで次のように実行すればよい。

$ git rebase <派生元ブランチ>

 このとき、もし競合が発生すればgit mergeの場合と同様に競合点がマーカーとともにファイルに記載される。また、「git rebase –abort」でrebaseを取り消すこともできる。

ほかのリポジトリとの連携を行うコマンド

コマンド19:「git pull」-ほかのリポジトリの変更点をローカルリポジトリにマージする

 ほかのリポジトリで加えられた変更点を現在のブランチにマージするには、「git pull」コマンドを利用する。

$ git pull <変更点の取り込み元リポジトリ>

 変更点の取り込み元リポジトリは、git cloneの場合と同様にURLで指定する(表1)。また、git cloneコマンドで作成したリポジトリの場合、.git/config内の「remote」項目などに複製元リポジトリのURLが自動的に記録されるため、複製元リポジトリからpullを行う場合は下記のように取り込み元リポジトリを指定しなくとも実行できる。

$ git pull
コマンド20:「git push」-公開リポジトリに自分のリポジトリの内容を送信する

 git pullはほかのリポジトリの内容を自分のリポジトリに取り込むものだったが、逆に自分のリポジトリの内容をほかのリポジトリ(一般的には公開リポジトリ)に送信して取り込ませるコマンドが「git push」である。

 git pushの引数には、送信先のリポジトリURLと送信するブランチ、送信先ブランチを指定する。

$ git push <送信先リポジトリ> <送信するブランチ>:<送信先ブランチ>

 送信先ブランチを指定しなかった場合は、送信するブランチと同じブランチを指定したものとみなされる。また、送信先ブランチが送信先リポジトリに存在しない場合はそのブランチが作成される。

コラム:公開リポジトリと通常のリポジトリとbareリポジトリ

 Gitの公開リポジトリは通常、管理ファイルのみを持つ「bareリポジトリ」として作成される。通常bareリポジトリでは作業ツリーの変更やコミットといった操作は行わず、ファイルのやりとりにのみ使用する。また、慣例としてbareリポジトリとして使用するディレクトリには「.git」という拡張子が付けられる。

 bareリポジトリは、「–bare」オプションを付けてでgit initを実行することで作成できる。