Gitの話
VCSの特徴
歴代のVCS(Version Control System: バージョン管理システム)の特徴
名称 | 環境 | 管理単位 | リポジトリ |
RCS | スタンドアロン | 単一のファイル | 単一のファイルをlock/unlock |
CVS Subversion | ネットワーク | ファイルツリー | ネット上で単一のリポジトリを共有 |
Git | 複数のリポジトリがネット上に共存 |
リポジトリの内部構造
Gitではコミットする度にリポジトリ内部にひとまとまりのデータ構造が作成される。
- 作成されるデータ構造の内訳
- コミットオブジェクト
一回のコミットそのものを表すデータオブジェクト。
- コミットオブジェクトを起点として、そのコミット時点の全ての情報を参照できる(図では、丸印から下に伸びる実線)。
- コミットオブジェクトにはその内容から算出されるSHA1のダイジェスト値が識別子として割り当てられる。これをコミットIDと呼ぶ。
- コミットオブジェクトはその直前のコミットオブジェクトを指し示している。これを手繰ってゆくことでコミットの履歴を新しい方から古い方へ参照することができる(図では、丸印から左に伸びる点線矢印)。
- ツリーオブジェクト
コミットオブジェクト毎に、管理しているファイルの階層関係を表すオブジェクト
- ツリーオブジェクトはおおざっぱに言うとファイルの階層関係を記録しているだけ。
OSが管理するファイルシステムそのものを記録しているわけではない。ファイル属性は通常ファイルのパーミッションなどは記録されているが、ディレクトリのパーミッション、ファイル・ディレクトリ共オーナやグループは記録されていない。
- BLOB (Binary Large OBject)
ファイルの内容を保持するオブジェクト。
- ファイルオブジェクトにもファイル内容のSHA1のダイジェスト値がIDとして割り当てられる。
Gitでは、BLOBのオブジェクトIDが同じであれば、実ファイルシステム上で異なるファイルであっても、あるいは全く関係ない別のリポジトリのファイルであっても、すべて「同一のもの」として扱われる。
- コミット
Gitでは、「コミット」という言葉は2つの意味を持つ。
一つは、リポジトリ内でコミットオブジェクトと、それが指し示すツリーオブジェクトとBLOBの全体を称して名詞的に使う。
例えば「コミットを取り出す」とか「2つのコミットの差分を調べる」というように使う。
もう一つは、他のVCSでも用いられる「ファイルをリポジトリに登録する=コミットする」という動詞的な意味。
この2つの違いを意識するとGitの理解が進む(と思う)。
- ブランチ
「ブランチ」という言葉も、他のVCSとは違う使われ方をする場合がある。
- 「ブランチ」は「現在の最新のコミットを指し示すポインタ(のようなもの)」につけた名前。
あるブランチに対しコミットが追加されると、そのブランチは新たに追加されたコミットを指すようになる。
- Gitのリポジトリを作成すると、「master」というブランチが作成される。これは他のVCSでのMain Trunkのような役割を果たす。
- 「HEAD」というブランチは、「現在作業対象となっているブランチ(カレントブランチ)」を表している。
- コミットの操作
コミット操作(コミットの再試行、取り消し、変更)関連のコマンドは種類が多く、マニュアルの説明では動作の違いがわかりにくいものもある。初学者が混乱しやすい部分。
- git reset
- git checkout
- git commit --amend
- git revert
- git rebase
- git cherry-pick ...など...
これらはそれぞれのコマンドを実行することによってコミットオブジェクトがどのように変化するかを比較してみると、それぞれのコマンドの意味が理解しやすい(と思う)。
分散リポジトリ
Gitでは複数のリポジトリを設置し、リポジトリ間でコミットを送受信することができる。
Gitの仕組み的には、全てのリポジトリは対等。
通常は、基点となるリポジトリを設け、そのリポジトリから複製した別のリポジトリ上で作業を行い、その作業結果を基点となるリポジトリに集約する「中央リポジトリ方式」がよく使われる。
複製(クローン)したリポジトリ内には、複製元のリポジトリの状態を記録するための特殊なブランチが存在し、これを「追跡ブランチ」と呼ぶ。
- リモートリポジトリに手元の追跡ブランチを同期させる操作をフェッチ(fetch)と呼ぶ。
- プル = フェッチ+マージ
- ローカルブランチの内容をリモートリポジトリに送りつける操作をプッシュと呼ぶ
リモートリポジトリを操作するには、
- ローカルリポジトリに存在するブランチ
- ローカルリポジトリ内の追跡ブランチ
- リモートリポジトリ内に存在するブランチ
を明確に区別して指定する必要がある。このための記法をrefspec (参照仕様)と呼ぶ。
参照仕様の理解もGitを使う上でのポイントの一つ(と思う)。
#img(): File not found:
おすすめドキュメント
ネット上、書籍共に数多くありますが…。
- Git入門:Git初学習者のための効率的な学習方法を考えてみた
- The entire Pro Git book (日本語版)
ツールとか
- リポジトリ管理
リモートリポジトリをウェブベースで管理するツール。GitHub.comのインターフェースを参考に作成されている。
リポジトリだけでなく、ユーザアカウント管理、イシュートラッカー、Wikiといったプロジェクト管理機能も同時に実装されている。
- GitLab
コミュニティ版、エンタープライズ版、SaaS版、ホスティングサービスが提供されている。
単一のリポジトリ内で、コード提出→レビュー→承認といったフローを想定していため、承認要請は「プルリクエスト」ではなく「マージリクエスト」である。
Ruby on Railsで記述されている。
- GitBucket
個人(竹添直樹氏)によるもの。Scala言語で記述されている。
「Github Enterpriseは高いしOSSではない、GitLabはインストールやバージョンアップがめんどくさい、という隙間を狙ったプロダクト」とのこと。
開発フロー
作業用ブランチ(トピックブランチ)の作成やマージといった作業フローの運用については、様々な議論があるようだ。
例えば、
など。
雑感
- VCSは時代を反映する
今回Gitを使うようになって感じたことの一つ
- RCS ... IPネットワーク以前。一台のマシンに全員がTSSでログインして作業するイメージ。
→一つのファイルはある時点では一人しかいじれない。
- CVS, svn ... IPネットワーク普及後。リポジトリはネットワーク経由でどこからでもアクセス出来るようになった。
→ファイルを複数人で並行していじれようになった 。
- Git ... 大容量のストレージが個人レベルで入手可能に。ネットワークも高速な回線が常時使用可能なのがあたりまえ。
→リポジトリは全員が持てばいい。コミットも差分などは取らずそのまま保存。
…どんどん富豪的に
- 黒い画面怖い
Gitについて色々調べている過程で時として目にしたフレーズ。
Gitは今ではメジャーなソフトなので、インフラ寄りはないエンジニアやウェブのデザイン系の人達も使う機会が多いようだ。彼らはCLIに馴染みがないためこのようなフレーズが発せられる模様。
概ね以下のような事柄が原因ではないか。
- GUIでカバーしていないニッチな機能を使う必要が生じた場合、CLIを使うことになる
- SSHのようなGitを使う上で必要となる周辺技術があり、これらもCLIベースでの操作となる
- VCSには他のソフトにはない独自の概念が多くあり、それらが可視化されていないCLIではやりたいことと実際の操作の関連がわかりにくい
- ほんこれ
ロブ・パイクは「Programming in C」の中で、以下のように述べている;
Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self evident. Data structures, not algorithms, are central to programming.
データがソフトウェアの主役である。データ構造を正しく選び、それらを適切に構成すればアルゴリズムは自ずと明らかなものになる。アルゴリズムではなくデータ構造がプログラミングの根幹である。
今回Git習得の過程でこのことを実感した。
Gitは優れてデータ構造主導のソフトウェアである。初期のGitはCで記述された少数のコマンドとシェルスクリプトとで構成されていたというのも頷ける話である。