なんとなくGitを使っていました。
基本的にはgit add/commit/push/pull/cloneができれば、最低限は開発できたので、困るまでそれでいいかななんて思っていたのですが、
ブランチ操作でローカルレポジトリがよくわからないことになったので、ちゃんと勉強するか〜と思って勉強しました。
概要
Gitのブランチ操作は、HEADの位置をズラしているだけ。
別ディレクトリを切り出しているわけではない。
ブランチ操作のときに起きた問題
ブランチを3つ作って、
- リモートレポジトリ同様のブランチ(develop)
- 実験ブランチ
- 必須要件ブランチ
という役割分担で運営してました。
ローカルのdevelopから、実験ブランチ→必須要件ブランチという順番にブランチを切っていきました。
必須要件ブランチをリモートリポジトリにpushすっぞ、となったときに、リモートのバージョンが結構進んでいたので、pullして新しい差分をとりこむことにしました。
結構ガチャガチャやったら、なぜか実験ブランチの修正内容が消えていました。
原因はっきりわかっていないのですが、未commitのまま、ブランチを切り替えたので、
ワークディレクトリの内容が消えてしまったのだと思われます。
(消える危険があるときはcheckoutできないと思っていたのですが、できる場合もある?)
ブランチ運用を雰囲気でやっていたツケでした。
幸い実験ブランチはコード自体は微修正だったので、結局「git reset」で最終commit時まで戻して、コード内容だけをコピーして、
ブランチ自体を消してしまって、きれいにつくりなおすという原始的な手段を使いました。
ただリモートレポジトリに更新あるたびに、実験中のブランチめちゃくちゃになったら怖いです。
ブランチを切ったときに本当に起きていること
ブランチを切る操作は、下記のコマンドをうちますね?
git branch b1
git checkout b1
僕はこっちでやる派ですが、1つのコマンドでもできます。
(オプションを覚えられないんですよね……)
git checkout -b b1
僕は今まで、この操作で別ディレクトリができているイメージでいました。
これは完全に間違い。
他のバージョン管理システムだと、ブランチを切る作業=作業ディレクトリの丸コピーというものもあるみたいです。
Gitはlinus torvalds(Linux作ったフィンランド人)が、それまでのバージョン管理システム(VCS)にムカついて作ったものです。
僕自身はSubversionなどのバージョン管理システム使ったことなくて、いきなりgitだったので、branch操作が高速! という感覚もなく、
それを当たり前として受け入れてしまいましたが、違うみたいです。
Git のブランチモデルは、Git の機能の中でもっともすばらしいものだという人もいるほどです。
そしてこの機能こそが Git を他の VCS とは一線を画すものとしています。
何がそんなにすばらしいのでしょう?
Git のブランチ機能は圧倒的に軽量です。
ブランチの作成はほぼ一瞬で完了しますし、ブランチの切り替えも高速に行えます。
その他大勢の VCS とは異なり、Git では頻繁にブランチ作成とマージを繰り返すワークフローを推奨しています。
一日に複数のブランチを切ることさえ珍しくありません。
この機能を理解して身につけることで、あなたはパワフルで他に類を見ないツールを手に入れることになります。
これは、あなたの開発手法を文字通り一変させてくれるでしょう。
でも作業ディレクトリコピーしないとしたら、どうやってGitはブランチ変更してるのか? を説明します。
Gitのバージョン管理は、commitした時点のスナップショットによって行われます。
現在自分がどのスナップショットにいるのかを把握するために、「HEAD」というポインタを持っています。
commitを取り消したいときに
git reset --hard HEAD
というコマンドはうったことがありましたが、実はHEADが何かわかっていませんでした。
HEADは「レポジトリの中で現在どのコミット位置にいるか」を指すポインタなんですね。
commitだけではなく、branchもこのHEADを活用しています。
git branch testing
branchを切ったとき、ここではmaster→testingと切ったとしましょう。
その場合、見ているスナップショットの位置は一緒です。
更にHEADはmasterを指しています。
checkoutしてみましょう。
git checkout testing
checkoutによって、HEADはtestingを指すようになります。
ただこの時点では、両branchともにスナップショットの中身が一緒なので、結局は同じバージョンを指しています。
このあとtestingで開発を進めて、commitすると、branch内容が分岐します。
これ以降は、両ブランチは互いに分岐したものとして、それぞれの変更は、互いに影響しません。
実験ブランチであれば、作ってそのままにしておけばいいですし、本流に組み込みたければ、mergeを使います。
修正内容がかち合ったらconflictが発生するので、そこだけ修正すれば容易にmergeできるはずです。
リモート追跡ブランチについて
これも書きたかったんですが、長くなったので、また別記事にします。
参考
3.1 Git のブランチ機能 - ブランチとは
記事中に出てくる画像もこちらからです。