Gitとは
バージョン管理システム。ファイルやフォルダに加えられた変更を追跡するためのツール。
一人で作業する場合には、例えばファイルに特定の変更が加えられた理由を確認できたり、複数の作業を互いに影響しない形で行ったりすることができて便利。複数人で作業する場合には、互いの更新が確認できたり、任意の修正の作業者を特定できたり、同時に作業ができたりなどの利点がある。
バージョン管理システムは他にもいろいろあるが、Gitがデファクトスタンダードになっている。Gitのコマンドは一見複雑だけど、使いこなせると便利だし、データモデルを理解していればコマンドライン操作も比較的容易に習得できるはず。
初期設定
環境構築を参考にインストールが完了したら、以下のコマンドを実行して初期設定をする。
名前とメールアドレスの設定
git config --global user.name "[ユーザー名]"
git config --global user.email "[メールアドレス]"
Warning
公開リポジトリではこの情報も公開されるので要注意。
デフォルトブランチ名の設定
git config --global init.defaultBranch main
Info
--global
をつけて設定した情報はホームディレクトリの.gitconfig
というファイルに保存される。
参考資料
とても分かりやすい講義ノートがありました。以下の説明に加えて、こちらも参考にしてみてください。
データモデル
スナップショット
標準的なディレクトリとして、以下のようなものを考える。
<root> (tree)
|
+- foo (tree)
| |
| + bar.txt (blob, content: "hello, world")
|
+- baz.txt (blob, content: "hello, git")
Gitではディレクトリをtree、ファイルをblobと呼ぶ。treeは、それ以下のtreeやblobに対するリンクであり、blobはバイト列である。最上位のtree(ここでは<root>
)に含まれるtreeやblob状態を、Gitはスナップショットとして保存していく。
スナップショットの履歴
個々のスナップショットを関連づけるために、Gitでは有向非巡回グラフ(Directed Acyclic Graph; DAG)を使用している。これはすなわち、個々のスナップショットが先行するスナップショット(parent)のセットを参照しているということである。参照しているparentは一つではなく、複数の場合もある(並行で開発されているブランチを統合する時など)。
Gitでは、このようなスナップショットをcommitと呼ぶ。
o <-- o <-- o <-- o
^
\
--- o <-- o
o <-- o <-- o <-- o <---- o
^ /
\ v
--- o <-- o
データモデルの擬似コード
// ファイルは大量のバイト列
type blob = array<byte>
// ディレクトリはファイルとディレクトリを内包している
type tree = map<string, tree | blob>
// コミットはparent、メタデータ、最上位階層のtreeを保持している
type commit = struct {
parents: array<commit>
author: string
message: string
snapshot: tree
}
objectと内容のアドレス
Gitでは、blob、tree、commitの全てをobjectとして扱う。
type object = blob | tree | commit
Gitは全てのobjectに対してSHA-1 hashを実行し、その内容のアドレスを保持している。
objects = map<string, object>
def store(object):
id = sha1(object)
objects[id] = object
def load(id):
return objects[id]
そのため、全てのobjectが40字の16進数SHA-1ハッシュを持っている。
reference(参照)
commitをSHA-1ハッシュで区別することができるが、不便なので、名前をつけることができる。 この、commitにつける名前のことをreferenceと呼ぶ。
references = map<string, string>
def update_reference(name, id):
references[name] = id
def read_reference(name):
return references[name]
def load_reference(name_or_id):
if name_or_id in references:
return load(references[name_or_id])
else:
return load(name_or_id)
慣習的に、「main」というreferenceはメインの開発ブランチ(これは後述)における最新のcommitを指す。また、Gitでは「HEAD」という特別なreferenceを使って「現在の作業場所」を指定する。
repository(レポジトリ)
Gitレポジトリとは、データのobjectとreferenceである。Gitのデータモデルが持っているのは、objectとreferenceのみであり、Gitの操作とはつまり、commitのDAGに対して、objectの追加およびreferenceの追加と更新を行うことである。
ステージング
とはいえ、Gitではスナップショットを作成するためのコマンドが2段階に分かれる。具体的には、ステージングという概念を導入し、(1) スナップショットに含めるべき変更を指定した上で(git add
)、スナップショットをとる(git commit
)できるようにしている。
コマンドラインインタフェース
基本的なもの
git help <command>
: Gitコマンドについての情報を得るgit init
:.git
ディレクトリ内に保存されたデータとともに、新しいGitレポを作成するgit status
: 現在のレポジトリの状態を確認するgit add <filename>
: ステージングエリアにファイルを追加するgit commit
: 新しいコミットを作成する- コミットメッセージは何を目的にどのような変更を加えたか、具体的に書く習慣をつけましょう
git log
: フラットな履歴のログを示すgit log --all --graph --decorate
: 有向非巡回グラフ(DAG)として履歴を可視化するgit diff <filename>
: ステージングエリアでの変更を表示するgit diff <revision> <filename>
: スナップショット間のファイル内の差異を表示するgit checkout <revision>
: HEADと現在のブランチを更新する
ブランチング(branching)とマージング(merging)
git branch
: ブランチを表示するgit branch <name>
: ブランチを作るgit checkout -b <name>
: ブランチを作り、そのブランチに切り替えるgit branch <name>; git checkout <name>
と同様
git merge <revision>
: 現在のブランチにマージするgit mergetool
: マージコンフリクト(結合衝突)を解決するためのツールを使用するgit rebase
: パッチのセットを新しいベース(土台)の上にリベース(作業が完了したブランチを分岐元のブランチにくっつける)する
リモート
git remote
: リモートをリスト表示するgit remote add <name> <url>
: リモートを追加するgit push <remote> <local branch>:<remote branch>
: リモートにオブジェクトを送信し、リモートのリファレンスを更新するgit branch --set-upstream-to=<remote>/<remote branch>
: ローカルブランチとリモートブランチ間の通信を設定するgit fetch
: リモートからオブジェクトとリファレンスを回収するgit pull
:git fetch; git merge
と同様git clone
: リモートからリポジトリをダウンロード(クローン)する
取り消し(Undo)
git commit --amend
: コミットの内容やメッセージを編集するgit reset HEAD <file>
: ファイルのステージングを解除するgit checkout -- <file>
: 変更を破棄する
Git上級者向けコマンド
git config
: Gitをカスタマイズするgit clone --depth=1
: バージョン履歴全体は持ってこない、浅いクローン(ダウンロード)git add -p
: 対話的なステージングgit rebase -i
: 対話的なリベースgit blame
: どの行を誰が最後に編集したのかを表示するgit stash
: 作業ディレクトリへの変更を一時的に削除するgit bisect
: 履歴のバイナリサーチ(二分探索)を行う(回帰など).gitignore
: 意図的に追跡されていないファイルを、無視するために特定する
GitHubとは
Gitのリモートレポジトリホスティングサービスで、Gitとは別物。プロジェクトのバックアップをとる時や他の人と共有する時に便利。GitHubの他にも、BitbucketやGitLabなどがある。