Gitの考え方

今の会社ではGitを使ってソースを管理している。
個人で使ったことは多少はあるにしろ、本格的な使用は始めてで戸惑ったけど失敗して迷惑を掛けながらも理解できてきたのでメモっておく。


ネット上にはGitの解説をしているサイトはある。けれどほとんどはコマンドの説明だ。
Gitはコマンドが多くUIがあまりよろしくないので戸惑うこともしばしばだけど、ここさえ抑えておけばコマンドは後で調べても何とかなるはず。
とは言っても、自分が手探りで触って理解した内容だから正確じゃあないかも。

addとかpushとかのイメージ

これは図解Gitが分かりやすい。
ここさえ読んでおけば多分理解できるはず。

Gitはハッシュ(SHA-1)を追う

基本だけど、やっぱり重要。branchやsubmoduleなど色々関係してくる。


たとえば、submoduleが分かりやすい。
masterとそれに付随するsubmoduleがあるとする。
masterが覚えているのはsubmoduleのハッシュだけ。


説明のためにsubというsubmodueがあるとしよう。ハッシュは適当に書いている。
まずはgit logでsubを見てみると、534c...というハッシュがある。

$ git log sub
commit 534c...
Author: hogehoge
〜


ではこの修正内容を見てみると、

$ git show 534c
 -- a/sub
 ++ a/sub
 @@ -1 +1 @@
 -Subproject commit 6e39...
 +Subproject commit 990a...

となっている。このハッシュはsubの修正内容になっているはずだ。
cd subしてからgit logしてみると良い。6e39...も990aもあるはずだ。


branchも同じだろう。
git自体は全体のハッシュを持っているが、ブランチはどのハッシュが関係するかを管理しているだけ。
だから、branchの生成コストが低い。どうせプログラム的にはハッシュのリストを作ってそれに名前を作るだけで済むし(実際にどうしているかは知らないけどね)。
Lisp風に書くと、

(define master (2345...) (2adf...) (6423...) ...)

という感じ。


新しいbranchを作るには現在のブランチのコピーを作れば良い。

(list-copy master new-branch)

簡単だ。
特定のハッシュを取り出すのも簡単になるし、特定のハッシュからブランチを作成するのも簡単。

branchはpopのできないスタックのようなもの

あくまでも自分のイメージだけど。
上ではリストに例えたけど、動きのイメージとしてはスタックの方が分かりやすい。


例えば、file_aというファイルがあり、このファイルを複数人で修正するとしよう。


現在の状態は(master (234c...))だ。


Aさんが修正をする。

$ vi file_a
$ git add file_a
$ git commit "changed"
$ git push

これでpush先の現在の状態は(master (234c...) (54ab...))だ。


さて、Bさんがいる。Bさんは(master (234c...))に別の修正を行った。
(master (234c...) (389c...))となった。


このとき(234c...)の次の状態AさんとBさんで異なる。
当然Bさんがpushしようとするとrejectされる。pullするとコンフリクトするかもしれない。
もちろん修正内容次第ではコンフリクトしないかもしれない。コンフリクトするかどうかになって始めてGitは修正内容(つまりファイル内容)を見る。
ここで、Aさんの修正とBさんの修正部分がかぶっていなければコンフリクトはしない。しかし運が悪く修正部分が重なっていればコンフリクトする。


Gitは(master (234c...) (54ab...) (389c...))のようになる事を期待している。
だからこそpushしたときに、rejectされてpullするとコンフリクトすることになる。
mergeをするときにコンフリクトするのも同じ理由だ。
Gitをpopできないスタックといったのは、過去の修正は基本的に残るから、スタックにpushするしか出来ないという意味だ。
運悪くコンフリクトしたらGitのスタックに矛盾が生じないように修正さえすればgit pushできるはず。



これさえ抑えておけば、あとはネットや本で調べてコマンドを打ち込めば良いはず。
昨日も問題が発生した。自分もgitの使い方でミスもしてきた。
けど、これは問題を起こした本人が悪いわけではなくGitのUIが良くないから発生したんだと思う。
人間は誰でもミスをするんだし、そのためにバージョン管理ソフトを使うのだから。でもUIが悪くてツールの動作まで把握しないと使いこなせないのは辛いなぁ。機能は素晴らしいのに。