Git

Git（ギット）は、プログラムのソースコードなどの変更履歴を記録・追跡するための分散型バージョン管理システムである。Linuxカーネルのソースコード管理に用いるためにリーナス・トーバルズによって開発され、それ以降ほかの多くのプロジェクトで採用されている。Linuxカーネルのような巨大プロジェクトにも対応できるように、動作速度に重点が置かれている。現在のメンテナは濱野純 () で、2005年7月から担当している。
Gitでは、各ユーザのワーキングディレクトリに、全履歴を含んだリポジトリの完全な複製が作られる。したがって、ネットワークにアクセスできないなどの理由で中心リポジトリにアクセスできない環境でも、履歴の調査や変更の記録といったほとんどの作業を行うことができる。これが「分散型」と呼ばれる理由である。
背景および概要.
Linuxカーネルの開発では、Linux Kernel Mailing List に投稿される多数のパッチをメンテナーたちがソースコードに適用するという形式が採用されている。これらの作業を効率的に行うため、当初はBitKeeperというバージョン管理システムを用いていたが、このソフトウェアは商用ソフトウェアであった（クライアントはバイナリ版のみ無料で、サーバは商用だがBitMover社の厚意で無料で使えていた）。この状況を快く思わない人々がBitKeeperのクローンを実装したことから、この環境が使えなくなってしまい（BitKeeper#ライセンス問題やBitKeeper#価格変更を参照）、その代替として2005年にGitが開発された。
Linuxカーネルの開発では、巨大なソースコードの集合を扱うため、変更点の抽出やリポジトリ操作ができるかぎり高速にできる必要がある。他の様々なバージョン管理システムをあたったが、満足のいくものがなかったため、Gitではこのような問題も出来る限り解決できるよう、いくつかのアイデアが導入されている（この部分は、他のバージョン管理システムにも同様の機能が導入されるようになった）。
作業の流れ.
Gitは分散型のソースコード管理システムであるため、リモートサーバ等にある中心リポジトリの完全なコピーを手元（ローカル環境）に作成して、そのローカルリポジトリを使って作業を行う。
一般的な開発スタイルでは、大雑把に言えば、以下のようなステップの繰り返しで作業が行なわれる：
リポジトリ間の通信 (clone, pull, push) では以下のプロトコルが使用できる。
以前はrsyncも使用できたが、2.8.0で廃止された。
設計.
Gitの設計はBitKeeperとMonotoneが元になっている。元々のGitはローレベルなエンジンとして設計されていたが、これは、他の開発者がCogitoやStGITのようなフロントエンドを容易に開発できるようにすることを目的としていた。現在では、Gitのコア自体もユーザから直接利用できるようになっている。
Gitの設計には、リーナスが大規模プロジェクトのメンテナンスを行った経験や、ファイルシステムのパフォーマンスに関する深い知識、また実用性のあるシステムを短期間に作成しなければならないという差し迫った必要性（BitKeeperを参照）が反映されている。これらの影響は、以下のような形で実装に現れている。
Gitの特徴の一つとして、ディレクトリツリーに対するスナップショットを作成する点が挙げられる。初期のバージョン管理システム（SCCSやRCS）では、個々のファイルを処理の対象としており、直近のバージョンに対して差分符号化を行うことでリポジトリのサイズを縮小することに機能の重点が置かれていた。以降のバージョン管理システムでも、この「プロジェクト内の複数バージョンにまたがって一つのファイルを追跡できる」という概念が継承されていた。
一方、Gitではこのコンセプトを使用していない。その結果として、Gitはソースコードツリー中のファイルのリビジョン間の関係性を記録しなくなっている。これにより、Gitは以下のような特徴をもつようになっている。
リポジトリの保存方法については批判もある。
Gitは以下のマージアルゴリズムを実装している。アルゴリズムはマージ時に選択することができる。
歴史.
名前の由来.
リーナス・トーバルズによれば、
英語のスラングとして、Gitには「バカ」「間抜け」といった類の意味がある。この自虐ネタはもちろん皮肉で、これはリーナスがLinuxの名前を決める際に自身の名前にちなんだ名前を付けるよう強要されたことから来ている。(Linux#名前の由来を参照)
Gitのオフィシャルサイトのウィキでは、“Git”という名前に対して他にもいくつかの解釈がなされている。例としては"Global Information Tracker"などが挙げられる。
開発初期の歴史.
Gitの開発は、Linuxカーネルの開発者の多くがBitKeeperのシステムに対するアクセスを禁止されたことに端を発している（BitKeeper#価格変更を参照）。これは、アンドリュー・トリジェル (Andrew Tridgell) がプロプラエタリなソフトウェアであるBitKeeperのプロトコルをリバースエンジニアリングしたことに対し、BitKeeperの著作者であるラリー・マクボイがこれをライセンス違反であるとして、BitKeeperの無料提供を止めたためである。Linux.conf.au 2005のキーノートにおいて、トリジェルはこのリバースエンジニアリングの手順について説明を行ったが、内容はBitKeeperのサーバの適切なポートにtelnetでアクセスし“help”とタイプするだけという単純なものだった。
リーナスはBitKeeperと同じように使える分散型バージョン管理システムを探していたが、無料のシステムで彼の要求（特に速度面での要求）に適合するものは見つからなかった。リーナスが書いたメールによると、2005年4月7日頃に最初のプロトタイプを作成していたようである。
リーナスは以下のような原則に基づいて設計を行っている。
最初の3つの条件によって、既存のバージョン管理システムはMonotoneを除き全て選に漏れてしまい、4つ目の条件で該当するものがなくなってしまった。そのため、Linuxカーネル2.6.12-rc2のリリース直後に、リーナスは自分で開発を始めた。
Gitの開発は2005年4月3日に開始された。プロジェクトとしてのアナウンスは4月6日に行われ、4月7日にはセルフホスティングされるようになった。4月18日には複数のブランチからのマージが最初に行われた。4月29日にはリーナスの目標としていた処理速度が実現された。Linuxのカーネルツリーにパッチを当てるベンチマークで、初期のGitでは毎秒6.7個のパッチを処理している。6月6日には、GitによるLinuxカーネル2.6.12のリリースが行われた。
BitKeeperからの影響で、リーナスは従来と同じようなアプローチを意図的に避けており、結果としてGitは非常にユニークな設計になっている。技術に長けたユーザがGitを利用できるようになるレベルまではリーナスが開発を行っており、その後、2005年6月26日にはプロジェクトへの主要な貢献者であった濱野純 (Junio C Hamano) にメンテナンスが引き継がれた。濱野は2005年12月21日にバージョン1.0のリリースを行い、2021年5月現在も彼がメンテナンスを行っている。
ブランチモデル.
ソフトウェア開発におけるGitブランチの作成・更新モデルをブランチモデルと呼ぶ。
GitHub flow.
GitHub flowはブランチモデルの一種である。GitHub flowの方針は「codice_3ブランチは常にデプロイ可能」である。コードの変更を行う際にはトピックを名称とするブランチをcodice_3からforkする。マージ時を含め他者からの意見募集・レビューを行う際にはpull request（merge request）を用いる。pull request時に自動化テスト（c.f. 継続的インテグレーション）をおこなうことでmergeの安全性を確保し、codice_3が常に正常 = デプロイ可能に保たれる。GitHub flowが有効な分野は継続的デリバリー・継続的デプロイメントが有効な分野、例えばWebサービスが挙げられる。
2011年の提唱時と比較して、GitHub社ではモデルの一部を変更している。オリジナルのGitHub flowでは更新がcodice_3へマージされ、そこからデプロイされる。GitHub社ではレビュー後（CI後）のtopic branchが最終テストとしてプロダクション環境へデプロイされる。そこで問題がないと確認されたのちにcodice_3へmergeされている。このモデル変更により、CIで判明しなかったバグが発生した場合にcodice_3のrevert commitではなくcodice_3の再デプロイで対応できる。
マージ.
Gitはブランチのマージ（merge）に対応している。
マージが行われるとマージコミット（英: merge commit）が生成される。コンフリクトが発生しない場合、codice_10がマージコミットを自動生成する。コンフリクトが発生した場合、まず安全な範囲がマージされインデックスとワーキングツリーが更新される。自動マージできないコンフリクト部は、ワーキングツリーに特定の記法で両方の変更が併記された状態になる。ユーザーによるコンフリクト修正後codice_11をおこない、codice_12あるいはcodice_13をおこなってはじめてマージコミットが生成される。
マージコミットの実体は2つ以上のparent属性を持つただのコミットオブジェクトである（特別なGitオブジェクトではない）。通常のコミットオブジェクトと同様に変更後ファイルセットがtreeに記録され、更新の元となっている（複数の）コミットがparentに設定されているだけである。