日本語 ▾ トピック ▾ 最新バージョン ▾ gittutorial は 2.46.1 で最終更新されました

名前

gittutorial - Git入門チュートリアル

概要

git *

説明

このチュートリアルでは、新しいプロジェクトをGitにインポートし、変更を加え、他の開発者と変更を共有する方法を説明します。

代わりに、例えば最新バージョンをテストするためにGitを使ってプロジェクトをフェッチすることに主に興味がある場合は、Gitユーザーマニュアルの最初の2つの章から始めることをお勧めします。

まず、git log --graphのようなコマンドのドキュメントは、

$ man git-log

または

$ git help log

後者の方法では、任意のマニュアルビューアを使用できます。詳細については、git-help[1]を参照してください。

いずれかの操作を行う前に、名前と公開メールアドレスをGitに登録しておくことをお勧めします。最も簡単な方法は次のとおりです。

$ git config --global user.name "Your Name Comes Here"
$ git config --global user.email you@yourdomain.example.com

新しいプロジェクトのインポート

最初の作業としてproject.tar.gzというtarballがあると仮定します。これをGitのバージョン管理下に置くには、次のようにします。

$ tar xzf project.tar.gz
$ cd project
$ git init

Gitは次のように応答します。

Initialized empty Git repository in .git/

これで作業ディレクトリが初期化されました。.gitという新しいディレクトリが作成されていることに気づくでしょう。

次に、git addを使って現在のディレクトリ内の全てのファイルの内容のスナップショットをGitに取得させます(.に注意)。

$ git add .

このスナップショットは現在、Gitが「インデックス」と呼ぶ一時的なステージングエリアに保存されています。インデックスの内容をリポジトリに永続的に保存するには、git commitを使用します。

$ git commit

これによりコミットメッセージの入力を求められます。これでプロジェクトの最初のバージョンがGitに保存されました。

変更を行う

いくつかのファイルを変更し、その更新された内容をインデックスに追加します。

$ git add file1 file2 file3

これでコミットの準備ができました。コミットされる内容を見るには、--cachedオプションを付けてgit diffを使用します。

$ git diff --cached

--cachedなしでは、git diffはあなたが変更したがまだインデックスに追加していない内容を表示します。)また、git statusで状況の簡単な概要を得ることができます。

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

	modified:   file1
	modified:   file2
	modified:   file3

さらに調整が必要な場合は、今すぐ行い、新しく変更された内容をインデックスに追加します。最後に、変更をコミットします。

$ git commit

これにより、再び変更を記述するメッセージの入力を求められ、プロジェクトの新しいバージョンが記録されます。

あるいは、事前にgit addを実行する代わりに、次を使用できます。

$ git commit -a

これは、変更された(ただし新規ではない)ファイルを自動的に検出し、それらをインデックスに追加し、コミットするという全ての操作を一度に行います。

コミットメッセージに関する注意: 必須ではありませんが、コミットメッセージは、変更を要約した短い(50文字以内)一行で始め、その後に空白行を挟み、さらに詳細な説明を続けるのが良い習慣です。コミットメッセージの最初の空白行までのテキストはコミットタイトルとして扱われ、そのタイトルはGit全体で使われます。例えば、git-format-patch[1]はコミットをメールに変換する際に、タイトルを件名に、残りのコミットを本文に使用します。

Gitはファイルを追跡せず内容を追跡する

多くのバージョン管理システムには、新しいファイルの変更追跡を開始するようシステムに指示するaddコマンドが用意されています。Gitのaddコマンドは、よりシンプルで強力なことを行います。git addは新規ファイルと変更されたファイルの両方に使用され、どちらの場合も指定されたファイルのスナップショットを取り、その内容をインデックスにステージングし、次のコミットに含める準備をします。

プロジェクト履歴の表示

いつでも、次のコマンドを使って変更履歴を見ることができます。

$ git log

各ステップでの完全な差分も表示したい場合は、次を使用します。

$ git log -p

各ステップの概要は、全体像を把握するのに役立つことがよくあります。

$ git log --stat --summary

ブランチの管理

1つのGitリポジトリは、複数の開発ブランチを管理できます。experimentalという新しいブランチを作成するには、次を使用します。

$ git branch experimental

ここで実行すると、

$ git branch

既存のすべてのブランチのリストが表示されます。

  experimental
* master

experimentalブランチはあなたが今作成したもので、masterブランチは自動的に作成されたデフォルトブランチです。アスタリスクは現在いるブランチを示します。次のように入力します。

$ git switch experimental

experimentalブランチに切り替えます。次にファイルを編集し、変更をコミットして、masterブランチに戻ります。

(edit file)
$ git commit -a
$ git switch master

行った変更がもう表示されないことを確認してください。それはexperimentalブランチで行われたもので、現在はmasterブランチに戻っているからです。

masterブランチで別の変更を行うことができます。

(edit file)
$ git commit -a

この時点で、2つのブランチは分岐しており、それぞれ異なる変更が加えられています。experimentalで行われた変更をmasterにマージするには、次を実行します。

$ git merge experimental

変更が競合しない場合、完了です。競合がある場合、問題のあるファイルに競合を示すマーカーが残されます。

$ git diff

これが表示されます。競合を解決するためにファイルを編集したら、

$ git commit -a

マージの結果をコミットします。最後に、

$ gitk

結果の履歴を美しいグラフィカルな表示で示します。

この時点で、experimentalブランチを削除することができます。

$ git branch -d experimental

このコマンドは、experimentalブランチの変更がすでに現在のブランチにあることを確認します。

もしcrazy-ideaというブランチで開発を進めて後悔した場合、いつでもそのブランチを削除することができます。

$ git branch -D crazy-idea

ブランチは手軽で簡単なので、何かを試す良い方法です。

Gitを共同作業に使う

Aliceが/home/alice/projectにGitリポジトリを持つ新しいプロジェクトを始めたとします。そして、同じマシンにホームディレクトリを持つBobが貢献したいと考えています。

Bobは次から始めます。

bob$ git clone /home/alice/project myrepo

これにより、Aliceのリポジトリのクローンを含む新しいディレクトリmyrepoが作成されます。このクローンは元のプロジェクトと同等であり、元のプロジェクトの履歴の独自のコピーを持っています。

Bobはその後、いくつかの変更を行い、それらをコミットします。

(edit files)
bob$ git commit -a
(repeat as necessary)

準備ができたら、彼はAliceに/home/bob/myrepoのリポジトリから変更をプルするように伝えます。彼女はこれを次のように行います。

alice$ cd /home/alice/project
alice$ git pull /home/bob/myrepo master

これはBobのmasterブランチからの変更をAliceの現在のブランチにマージします。Aliceがその間に独自の変更を行っていた場合、手動で競合を解決する必要があるかもしれません。

したがって、pullコマンドは2つの操作を実行します。リモートブランチから変更をフェッチし、それらを現在のブランチにマージします。

一般的に、Aliceはこのpullを開始する前に、自身のローカルでの変更をコミットしておきたいと考えるでしょう。もしBobの作業が、履歴が分岐してからのAliceの作業と競合する場合、Aliceは自身のワーキングツリーとインデックスを使って競合を解決しますが、既存のローカルでの変更が競合解決プロセスを妨げる可能性があります(Gitはフェッチは実行しますがマージを拒否します。この場合、Aliceは何らかの方法でローカルの変更を取り除き、再度プルを行う必要があります)。

Aliceは、まずマージせずにfetchコマンドを使ってBobが何をしたか覗き見ることができます。これにより、特別なシンボルFETCH_HEADを使ってBobがプルする価値のあるものを持っているかどうかを確認できます。このように行います。

alice$ git fetch /home/bob/myrepo master
alice$ git log -p HEAD..FETCH_HEAD

この操作は、Aliceが未コミットのローカルでの変更を持っていても安全です。レンジ表記HEAD..FETCH_HEADは、「FETCH_HEADから到達可能なもの全てを表示するが、HEADから到達可能なものは除く」という意味です。Aliceは自身の現在の状態(HEAD)につながる全てを既に知っており、このコマンドでまだ見ていないBobの状態(FETCH_HEAD)の内容を確認します。

Aliceが、彼らの履歴が分岐して以来Bobが何をしたかを視覚化したい場合、以下のコマンドを発行できます。

$ gitk HEAD..FETCH_HEAD

これは、以前git logで見た2ドットのレンジ表記と同じです。

Aliceは、彼らが分岐して以来、両者が何をしたかを確認したい場合があります。彼女は2ドット形式の代わりに3ドット形式を使用できます。

$ gitk HEAD...FETCH_HEAD

これは「どちらか一方から到達可能なものすべてを表示するが、両方から到達可能なものは除く」という意味です。

これらのレンジ表記は、gitkgit logの両方で使用できることに注意してください。

Bobの作業を検査した後、緊急のものがなければ、AliceはBobからプルせずに作業を続けることを決めるかもしれません。もしBobの履歴にAliceがすぐに必要とするものがある場合、Aliceはまず作業中の変更を一時退避(stash)させ、pullを実行し、最終的に結果の履歴の上に作業中の変更を元に戻す(unstash)ことを選択するかもしれません。

小規模で密接なグループで作業している場合、同じリポジトリと何度もやり取りすることは珍しくありません。リモートリポジトリのショートハンドを定義することで、これを容易にすることができます。

alice$ git remote add bob /home/bob/myrepo

これにより、Aliceは、自身のブランチとマージせずに、git fetchコマンドを使ってpull操作の最初の部分を単独で実行できます。

alice$ git fetch bob

長い形式とは異なり、Aliceがgit remoteで設定されたリモートリポジトリのショートハンドを使ってBobからフェッチすると、フェッチされたものはリモート追跡ブランチ、この場合はbob/masterに保存されます。したがって、この後、

alice$ git log -p master..bob/master

AliceのmasterブランチからBobが分岐して以来行った全ての変更のリストが表示されます。

これらの変更を調べた後、Aliceは変更を自身のmasterブランチにマージできます。

alice$ git merge bob/master

このmergeは、自身のリモート追跡ブランチからプルすることでも行うことができます。このように。

alice$ git pull . remotes/bob/master

git pullは、コマンドラインで他に何が指定されていても、常に現在のブランチにマージされることに注意してください。

後で、BobはAliceの最新の変更を自身のレポに次のように更新できます。

bob$ git pull

Aliceのリポジトリへのパスを指定する必要がないことに注意してください。BobがAliceのリポジトリをクローンしたとき、Gitは彼女のリポジトリの場所をリポジトリ設定に保存しており、その場所はプルに使用されます。

bob$ git config --get remote.origin.url
/home/alice/project

git cloneによって作成された完全な設定は、git config -lを使って確認でき、git-config[1]のmanページには各オプションの意味が説明されています。)

Gitはまた、Aliceのmasterブランチの元のコピーをorigin/masterという名前で保持しています。

bob$ git branch -r
  origin/master

Bobが後で別のホストから作業することにした場合でも、sshプロトコルを使用してクローンとプルを実行できます。

bob$ git clone alice.org:/home/alice/project myrepo

あるいは、Gitにはネイティブプロトコルがあり、httpも使用できます。詳細については、git-pull[1]を参照してください。

GitはCVSのようなモードでも使用できます。これは、様々なユーザーが変更をプッシュする中央リポジトリを持つものです。詳細はgit-push[1]gitcvs-migration[7]を参照してください。

履歴の調査

Gitの履歴は相互に関連する一連のコミットとして表現されます。git logコマンドがそれらのコミットをリスト表示できることはすでに見てきました。各git logエントリの最初の行がコミットの名前も示していることに注意してください。

$ git log
commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
Author: Junio C Hamano <junkio@cox.net>
Date:   Tue May 16 17:18:22 2006 -0700

    merge-base: Clarify the comments on post processing.

この名前をgit showに渡すと、このコミットの詳細を見ることができます。

$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7

しかし、コミットを参照する方法は他にもあります。コミットを一意に識別するのに十分な長さの名前の最初の部分を使用できます。

$ git show c82a22c39c	# the first few characters of the name are
			# usually enough
$ git show HEAD		# the tip of the current branch
$ git show experimental	# the tip of the "experimental" branch

各コミットは通常、プロジェクトの以前の状態を指す1つの「親」コミットを持ちます。

$ git show HEAD^  # to see the parent of HEAD
$ git show HEAD^^ # to see the grandparent of HEAD
$ git show HEAD~4 # to see the great-great grandparent of HEAD

マージコミットは複数の親を持つ場合があることに注意してください。

$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
$ git show HEAD^2 # show the second parent of HEAD

コミットに独自の命名をすることもできます。実行後、

$ git tag v2.5 1b2e1d63ff

1b2e1d63ffv2.5という名前で参照できます。この名前を他の人と共有する(例えば、リリースバージョンを識別するため)つもりなら、「タグ」オブジェクトを作成し、場合によっては署名するべきです。詳細についてはgit-tag[1]を参照してください。

コミットを知る必要があるGitコマンドは、これらの名前のいずれかを受け取ることができます。例えば、

$ git diff v2.5 HEAD	 # compare the current HEAD to v2.5
$ git branch stable v2.5 # start a new branch named "stable" based
			 # at v2.5
$ git reset --hard HEAD^ # reset your current branch and working
			 # directory to its state at HEAD^

その最後のコマンドには注意してください。ワーキングディレクトリ内の変更を失うだけでなく、このブランチからそれ以降の全てのコミットも削除されます。もしこのブランチがそれらのコミットを含む唯一のブランチである場合、それらは失われます。また、他の開発者がプルするような公開ブランチではgit resetを使用しないでください。履歴を整理するために他の開発者に不必要なマージを強制することになります。プッシュした変更を元に戻す必要がある場合は、代わりにgit revertを使用してください。

git grepコマンドは、プロジェクトの任意のバージョンで文字列を検索できるため、

$ git grep "hello" v2.5

v2.5内の"hello"の全ての出現箇所を検索します。

コミット名を省略すると、git grepは現在のディレクトリで管理しているファイルの中から検索します。したがって、

$ git grep "hello"

Gitによって追跡されているファイルのみを検索する簡単な方法です。

多くのGitコマンドはコミットのセットも受け取り、それらはいくつかの方法で指定できます。git logのいくつかの例を以下に示します。

$ git log v2.5..v2.6            # commits between v2.5 and v2.6
$ git log v2.5..                # commits since v2.5
$ git log --since="2 weeks ago" # commits from the last 2 weeks
$ git log v2.5.. Makefile       # commits since v2.5 which modify
				# Makefile

また、git logに「レンジ」でコミットを指定することもできます。この場合、最初のコミットが必ずしも2番目のコミットの祖先である必要はありません。例えば、stablemasterのブランチの先端が以前共通のコミットから分岐していた場合、

$ git log stable..master

masterブランチで行われたがstableブランチでは行われていないコミットをリスト表示します。一方、

$ git log master..stable

stableブランチで行われたがmasterブランチでは行われていないコミットのリストを表示します。

git logコマンドには弱点があります。コミットをリスト形式で表示しなければならないことです。履歴に分岐し、その後再びマージされた開発ラインがある場合、git logがそれらのコミットを表示する順序は無意味です。

複数の貢献者がいるほとんどのプロジェクト(LinuxカーネルやGit自体など)では頻繁にマージが行われ、gitkはその履歴をより良く視覚化します。例えば、

$ gitk --since="2 weeks ago" drivers/

driversディレクトリ以下のファイルを変更した、過去2週間分のコミットを閲覧できます。(注:gitkのフォントは、Controlキーを押しながら「-」または「+」を押すことで調整できます。)

最後に、ファイル名を受け取るほとんどのコマンドは、オプションで任意のファイル名の前にコミットを指定することで、ファイルの特定のバージョンを指定することができます。

$ git diff v2.5:Makefile HEAD:Makefile.in

また、git showを使ってそのようなファイルを見ることもできます。

$ git show v2.5:Makefile

次のステップ

このチュートリアルは、プロジェクトの基本的な分散バージョン管理を行うには十分なはずです。しかし、Gitの深さとパワーを完全に理解するには、Gitが基づいている2つのシンプルな概念を理解する必要があります。

  • オブジェクトデータベースは、ファイル、ディレクトリ、コミットといったプロジェクトの履歴を保存するために使用される、非常に洗練されたシステムです。

  • インデックスファイルは、ディレクトリツリーの状態のキャッシュであり、コミットを作成したり、ワーキングディレクトリをチェックアウトしたり、マージに関わる様々なツリーを保持するために使用されます。

このチュートリアルのパート2では、オブジェクトデータベース、インデックスファイル、およびGitを最大限に活用するために必要なその他のいくつかの事柄について説明します。gittutorial-2[7]でそれを見つけることができます。

もしすぐにそれを続けたくなければ、この時点で興味深いかもしれないその他のいくつかの余談は次のとおりです。

  • git-format-patch[1], git-am[1]: これらは、Gitコミットのシリーズを電子メールパッチに変換し、またその逆を行うもので、電子メールパッチに大きく依存するLinuxカーネルのようなプロジェクトで役立ちます。

  • git-bisect[1]: プロジェクトにリグレッションがある場合、バグを追跡する1つの方法は、履歴を検索して、責任がある正確なコミットを見つけることです。git bisectはそのコミットのバイナリ検索を実行するのに役立ちます。多くのマージされたブランチを持つ複雑な非線形履歴の場合でも、ほぼ最適な検索を実行できるほど賢いです。

  • gitworkflows[7]: 推奨されるワークフローの概要を提供します。

  • giteveryday[7]: 約20のコマンドで日常的なGit。

  • gitcvs-migration[7]: CVSユーザー向けのGit。

GIT

git[1] スイートの一部

scroll-to-top