BETA

Gitのブランチ操作をマスターする

投稿日:2019-11-26
最終更新:2019-11-26

ブランチに関してかなりやったのでまとめ。
ただ、やっぱり図がないとかなり分かりにくい・・。

下のサイトで視覚的に理解しながらGitの操作ができるので、おすすめ。
Learn Git Branching

ブランチとHEAD

ブランチとは?

最新コミットの別名。
つまり、ブランチ≒最新コミット。
$ git branch ブランチ名でブランチをHEADの位置に作る。
$ git branch foo masterでmasterブランチからfooブランチを作成することもできる。

HEADとは?

現在の作業地点のコミット。
またHEADは通常は他のブランチにくっつくように隠れているが、$ checkout <コミットハッシュ>でHEADだけを分離できる。
分離した時に$ git merge masterなどを行うと、HEADがある地点のコミットにマージされる。

ブランチとHEADの移動

ブランチは$ git branch -f <ブランチ名> <参照値>で移動できる(参照値はブランチ名、相対指定、コミットハッシュのどれか)
ex) $ git branch -f master foo^でmasterブランチをfooブランチの一つ前のコミットに移動させる。

一方でHEADはcheckoutコマンドで他のコミットに移動できる。
つまり作業地点のコミットを切り替えられる。
ex) $ git checkout topic~2でtopicブランチの2つ前のコミットにHEADを移動。

移動位置の相対的な指定方法

記号 意味
^ 一つ前のコミット
~数値 数値分前のコミット
^数値 何番目の親かを指定

merge後、mergeされた側のブランチが1番目の親、mergeした側のブランチが2番目の親となる。
記号は連鎖して使える。
ex) $ git checkout HEAD~^2~2で現在のHEADの位置から一つ前のコミットに移動、そこから2番目の親のコミットに移動、そこからさらに2つ前のコミットに移動できる。(HEADの位置を)

mergerebaseの違い

mergeは二つのブランチを一つに統合するイメージ。
rebaseは分岐地点からちぎって指定したブランチにくっつけるイメージ。

2種類のマージ

Fast-ForwardとNon Fast-Forwardがある。

Fast-Forward(早送り)は分岐してないなら、同じ最新コミットまで進める。
デメリットはマージした記録が残りづらい、取り消しづらい。

一方でNon Fast-Forward(普通のマージ)は二つの内容を統合したコミットを作る。

基本$ git merge topicで今のブランチにtopicブランチを統合したコミットを作る。

rebaseの注意点

rebaseはコミットの流れが一本化して綺麗になるというメリットがある。
だが、rebaseで作られたコミットは元のコミットと内容は同じだが、別のコミットとなる(AコミットはA'コミットになるイメージ)。
そのため、pushされているブランチをrebaseするとpushできなくなる。
共有のブランチではrebaseしてはいけない。

$ git rebase masterで現在のブランチをmasterブランチにrebaseする。
$ git rebase master fooでfooブランチをmasterブランチにrebaseすることもできる。

戻す系のresetrevert

$ git reset C1で C1コミットまで巻き戻す。
コミットをなかったことにする。

一方は$ git revert C1でC1をなかったことにするコミットを新たに作成する。
なかったことにするコミットを作るので、以前のコミットは残る。

reset前のコミットはORIG_HEADという名前で参照することができる。
ので、取り消したい操作は$ git reset --hard ORIG_HEADで取り消せる。

ただし、ORIG_HEADはrebaseコマンドの直前を指しているため、rebaseのあとでさらにコミットすると使えなくなってしまう。
そんな時は$ git reflogを使う。
$ git reflogで操作歴を見て、戻したいポイントを見つけたら$ git reset --hard [コミットハッシュ]で何でも戻せる。

コミットを自由に並び替えるcherry-pickrebase -i

$ git cherry-pick C1 C2 C3 …でHEADコミットにC1,C2,C3...のコミットをとってきてくっつけることができる。

$ git rebase -i C1でC1以降のコミットを並べ替えたり、削除できたりする。

履歴をざっと確認

$ git describe <タグorブランチorコミットハッシュ>を使うと、<タグ>_<コミット数>_g<ハッシュ>のような情報が見れる。
<タグ>には履歴の一番最新のタグ名が、<コミット数>にはそのタグから幾つのコミットがあったか、<ハッシュ>はそのコミットのハッシュがそれぞれ入る。
これで指定したコミットまでのコミット履歴がざっくり分かる。

リモートブランチ(pushfetch)

リモートブランチはリモートと最後に同期した時点での状態を保持している。
$ git fetchでリモートブランチを更新する、リモートと同期する。
$ git checkout origin/masterするとHEADが分離する。
つまりローカルではHEADをリモートブランチに追従させることができない。

fetchコマンドはローカルの状態は変更しない。
変更するにはcherry-pickrebasemergeでリモートブランチにローカルブランチのコミットをくっつける。

pullfetch + merge
$ git pull --rebaseとすると、fetchした後にリモートブランチにrebaseする。

pushでローカルの変更をリモートに反映、リモートブランチも同期される。現在のブランチが追従しているリモートブランチを更新。

開発者はmasterブランチにいるときは基本pushとpullしかしない。
masterは常にリモート(origin/master)に追従した状態のままにする。
ex) git pull --rebase; git pushでリモートをローカルに反映させてからプッシュ、リベースでやる。

リモートトラッキング

ローカルブランチにそれぞれどのリモートブランチを追跡するか設定できる。
$ git checkout -b foo origin/master; git push;でfooという新しいブランチにチェックアウトし、プッシュ先はリモートのmasterブランチ。
git branch -u origin/master fooでも設定できる。

pushfetch先の変更

$ git push origin masterでローカルのmasterブランチをリモートのoriginリポジトリのmasterブランチにプッシュできる。
現在のチェックアウト先は無視される。

$ git push origin foo^:masterでローカルのfooブランチの一つ前のコミットをリモートのoriginリポジトリのmasterブランチにプッシュ。

fetchも同様に指定できる。pushの逆がfetch。
git fetch origin foo
git fetch origin foo~1:bar

奇妙なpushとfetch

$ git push origin :foo
リモートに何も送らないとローカルとリモートのfooブランチが両方削除される。

$ git fetch origin :foo
ローカルに何も送られてこないとローカルにfooブランチが作られる。

なぜこうなるかよくわからないが、とりあえずこうなる。

参考にしたサイト等

Learn Git Branching
こわくないgit

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

BЯunoの技術ブログ。日々学んだことを記録していくよ。

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう