![]() | |
![]() GitのWebインターフェース、gitweb | |
開発元 | 濱野純, リーナス・トーバルズ, ほか多数 |
---|---|
初版 | 2005年12月21日 |
最新版 |
2.45.2[1] ![]() |
リポジトリ | |
プログラミング 言語 | C, Bourne Shell, Tcl, Perl |
対応OS | Unix系、Linux、Windows、macOS |
種別 | バージョン管理ソフトウェア |
ライセンス | GNU General Public License バージョン2,GNU Lesser General Public License 2.1 |
公式サイト |
git-scm |
Git(ギット[2][3])は、プログラムのソースコードなどの変更履歴を記録・追跡するための分散型バージョン管理システムである。Linuxカーネルのソースコード管理に用いるためにリーナス・トーバルズによって開発され、それ以降ほかの多くのプロジェクトで採用されている。Linuxカーネルのような巨大プロジェクトにも対応できるように、動作速度に重点が置かれている。現在のメンテナは濱野純 (英語: Junio C Hamano) で、2005年7月から担当している。
Gitでは、各ユーザのワーキングディレクトリに、全履歴を含んだリポジトリの完全な複製が作られる。したがって、ネットワークにアクセスできないなどの理由で中心リポジトリにアクセスできない環境でも、履歴の調査や変更の記録といったほとんどの作業を行うことができる。これが「分散型」と呼ばれる理由である。
Linuxカーネルの開発では、Linux Kernel Mailing List[※ 1] に投稿される多数のパッチをメンテナーたちがソースコードに適用するという形式が採用されている。これらの作業を効率的に行うため、当初はBitKeeperというバージョン管理システムを用いていたが、このソフトウェアは商用ソフトウェアであった(クライアントはバイナリ版のみ無料で、サーバは商用だがBitMover社の厚意で無料で使えていた)。この状況を快く思わない人々がBitKeeperのクローンを実装したことから、この環境が使えなくなってしまい(BitKeeper#ライセンス問題やBitKeeper#価格変更を参照)、その代替として2005年にGitが開発された[4]。
Linuxカーネルの開発では、巨大なソースコードの集合を扱うため、変更点の抽出やリポジトリ操作ができるかぎり高速にできる必要がある。他の様々なバージョン管理システムをあたったが、満足のいくものがなかったため、Gitではこのような問題も出来る限り解決できるよう、いくつかのアイデアが導入されている(この部分は、他のバージョン管理システムにも同様の機能が導入されるようになった)。
Gitは分散型のソースコード管理システムであるため、リモートサーバ等にある中心リポジトリの完全なコピーを手元(ローカル環境)に作成して、そのローカルリポジトリを使って作業を行う。
一般的な開発スタイルでは、大雑把に言えば、以下のようなステップの繰り返しで作業が行なわれる:
リポジトリ間の通信 (clone, pull, push) では以下のプロトコルが使用できる[5]。
Gitの設計はBitKeeperとMonotoneが元になっている[10][11]。元々のGitはローレベルなエンジンとして設計されていたが、これは、他の開発者がCogitoやStGITのようなフロントエンドを容易に開発できるようにすることを目的としていた[12]。現在では、Gitのコア自体もユーザから直接利用できるようになっている[13]。
Gitの設計には、リーナスが大規模プロジェクトのメンテナンスを行った経験や、ファイルシステムのパフォーマンスに関する深い知識、また実用性のあるシステムを短期間に作成しなければならないという差し迫った必要性(BitKeeperを参照)が反映されている。これらの影響は、以下のような形で実装に現れている。
git-gc --prune
コマンドを使用して明示的にガベージコレクションを行うこともできるが、この処理には時間がかかる[19]。Gitの特徴の一つとして、ディレクトリツリーに対するスナップショットを作成する点が挙げられる。初期のバージョン管理システム(SCCSやRCS)では、個々のファイルを処理の対象としており、直近のバージョンに対して差分符号化を行うことでリポジトリのサイズを縮小することに機能の重点が置かれていた。以降のバージョン管理システムでも、この「プロジェクト内の複数バージョンにまたがって一つのファイルを追跡できる」という概念が継承されていた。
一方、Gitではこのコンセプトを使用していない[20]。その結果として、Gitはソースコードツリー中のファイルのリビジョン間の関係性を記録しなくなっている。これにより、Gitは以下のような特徴をもつようになっている。
リポジトリの保存方法については批判もある。
git gc
コマンドを使用することで手動で再パックを行うこともできる。Gitは以下のマージアルゴリズムを実装している。アルゴリズムはマージ時に選択することができる[26]。
リーナス・トーバルズによれば[28]、
「 | 僕は自己中心的な奴だから、自分のプロジェクトには自分にちなんだ名前を付けるようにしているんだ。最初はLinuxで、今度はGitだ。 | 」 |
英語のスラングとして、Gitには「バカ」「間抜け」といった類の意味がある。この自虐ネタはもちろん皮肉で、これはリーナスがLinuxの名前を決める際に自身の名前にちなんだ名前を付けるよう強要されたことから来ている。(Linux#名前の由来を参照)
Gitのオフィシャルサイトのウィキでは、“Git”という名前に対して他にもいくつかの解釈がなされている。例としてはGlobal Information Trackerなどが挙げられる[29]。
Gitの開発は、Linuxカーネルの開発者の多くがBitKeeperのシステムに対するアクセスを禁止されたことに端を発している(BitKeeper#価格変更を参照)。これは、アンドリュー・トリジェル (Andrew Tridgell) がプロプラエタリなソフトウェアであるBitKeeperのプロトコルをリバースエンジニアリングしたことに対し、BitKeeperの著作者であるラリー・マクボイがこれをライセンス違反であるとして、BitKeeperの無料提供を止めたためである。Linux.conf.au 2005のキーノートにおいて、トリジェルはこのリバースエンジニアリングの手順について説明を行ったが、内容はBitKeeperのサーバの適切なポートにtelnetでアクセスし“help”とタイプするだけという単純なものだった[30]。
リーナスはBitKeeperと同じように使える分散型バージョン管理システムを探していたが、無料のシステムで彼の要求(特に速度面での要求)に適合するものは見つからなかった。リーナスが書いたメールによると、2005年4月7日頃に最初のプロトタイプを作成していたようである[31]。
「 |
だけど、僕が見たSCMたちはそれ(bk pull相当のこと)をするのが大変だったんだ。僕がやろうとしていることの1つは(実はこれが一番なんだけど)その過程を十分効率的にすること。もし1つのパッチを適用してその変更の境界を記録するなどするのに30秒かかったとすると(正直、Linux規模のプロジェクトで30秒っていうのは大抵のSCMでは速いほうの見積りだけど)、250通(例えばAndrew[※ 2] と同期するときには決して珍しい量じゃない)のメールパッチを適用するのに2時間かかることになる。 BKはスピード狂ではなくて、(他のSCMと比較するとBKは1桁か2桁くらいは高速だけど)Andrew[※ 2]とマージをする時に1メールにつき約10-15秒かかっていた。だけど、BKではそれは大きな問題にならなかったんだ。BK⇔BK間のマージは簡単だから、僕は他の主要な開発者とは時間がかかるメールでのマージをしたことはなかったから。パッチアプリケーションに基づいたSCMにするなら、"マージ機能" をBKよりも速くしなければならなくなる。それは本当に本当に大変なこと。 だから、僕はいまスクリプトを書いていて、変更をずっと速く追跡できるようにしているんだ。最初の目標はパッチを適用するのと同じくらい高速にそれを行うこと。だけどはっきりいって、今のところできたのは多く見積もってもまだ半分くらいで、思わぬ障害にぶつかったら全然嘘になるかもしれないけど。いずれにせよ、僕がそれをすぐにできる理由は、僕のスクリプトがSCMではないからで、とても特別で "Linuxの状態を記録する" ようなものだからなんだ。それはリニアなパッチを十分効率的な時間でマージできるようになるだろう。 (パッチの適用が3秒でできるなら、大きな1つながりのパッチでも問題にはならない: 途中で失敗しても1分か2分で気がつくなら、それで十分で、手作業で修正することができる。待ち時間が重要な理由はそこにある。-- "オフライン" で効果的にそれができるなら、問題が起きた時に僕は定義どおりそれを修理できずにいるだろう) |
」 |
リーナスは以下のような原則に基づいて設計を行っている。
最初の3つの条件によって、既存のバージョン管理システムはMonotoneを除き全て選に漏れてしまい、4つ目の条件で該当するものがなくなってしまった[33]。そのため、Linuxカーネル2.6.12-rc2のリリース直後に[33]、リーナスは自分で開発を始めた[33]。
Gitの開発は2005年4月3日に開始された[35]。プロジェクトとしてのアナウンスは4月6日に行われ[36]、4月7日にはセルフホスティングされるようになった[35]。4月18日には複数のブランチからのマージが最初に行われた[37]。4月29日にはリーナスの目標としていた処理速度が実現された。Linuxのカーネルツリーにパッチを当てるベンチマークで、初期のGitでは毎秒6.7個のパッチを処理している[38]。6月6日には、GitによるLinuxカーネル2.6.12のリリースが行われた[39]。
BitKeeperからの影響で、リーナスは従来と同じようなアプローチを意図的に避けており、結果としてGitは非常にユニークな設計になっている[40]。技術に長けたユーザがGitを利用できるようになるレベルまではリーナスが開発を行っており、その後、2005年6月26日にはプロジェクトへの主要な貢献者であった濱野純 (Junio C Hamano) にメンテナンスが引き継がれた[41]。濱野は2005年12月21日にバージョン1.0のリリースを行い[42]、2021年5月現在も彼がメンテナンスを行っている。
ソフトウェア開発におけるGitブランチの作成・更新モデルをブランチモデルと呼ぶ。
GitHub flowはブランチモデルの一種である[43]。GitHub flowの方針は「master
ブランチは常にデプロイ可能」である[44]。コードの変更を行う際にはトピックを名称とするブランチをmaster
からforkする。マージ時を含め他者からの意見募集・レビューを行う際にはpull request(merge request)を用いる。pull request時に自動化テスト(c.f. 継続的インテグレーション)をおこなうことでmergeの安全性を確保し、master
が常に正常 = デプロイ可能に保たれる。GitHub flowが有効な分野は継続的デリバリー・継続的デプロイメントが有効な分野、例えばWebサービスが挙げられる。
2011年の提唱時と比較して、GitHub社ではモデルの一部を変更している。オリジナルのGitHub flowでは更新がmaster
へマージされ、そこからデプロイされる。GitHub社ではレビュー後(CI後)のtopic branchが最終テストとしてプロダクション環境へデプロイされる。そこで問題がないと確認されたのちにmaster
へmergeされている[45]。このモデル変更により、CIで判明しなかったバグが発生した場合にmaster
のrevert commitではなくmaster
の再デプロイで対応できる。
Gitはブランチのマージ(merge)に対応している。
マージが行われるとマージコミット(英: merge commit)が生成される。コンフリクトが発生しない場合、git merge
がマージコミットを自動生成する[46]。コンフリクトが発生した場合、まず安全な範囲がマージされインデックスとワーキングツリーが更新される[47]。自動マージできないコンフリクト部は、ワーキングツリーに特定の記法で両方の変更が併記された状態になる[48]。ユーザーによるコンフリクト修正後git add
をおこない、git commit
あるいはgit merge --continue
をおこなってはじめてマージコミットが生成される[49]。
マージコミットの実体は2つ以上のparent属性を持つただのコミットオブジェクトである(特別なGitオブジェクトではない)[50]。通常のコミットオブジェクトと同様に変更後ファイルセットがtreeに記録され、更新の元となっている(複数の)コミットがparentに設定されているだけである。
git-blame
コマンドを使用したソースファイル間のコードの移動の調査について
HEAD
, index, and working tree are updated to it."[git 1]