git checkout について、動作仕様とオプションについてまとめました。またリモートブランチへの切り替えにおけるよくある誤解と、その解決方法について記載しました。
目次
git checkout の概要
「git checkout」は下記の2つの機能を持ったコマンドです。
git checkout の機能
- 作業ブランチを切り替える
- 指定したコミット(もしくはインデックス)の状態を、現在の作業ツリーに展開する
もしパラメータに「ブランチ名」を指定すれば、[1]の動作、ファイルパスやファイル名を指定すれば、[2]の動作となります。この2つは異なる機能ですので、注意が必要です。
1作業ブランチを切り替える
git checkout コマンドに、パラメータでブランチ名を指定すれば、そのブランチに切り替える事ができます。
// masterブランチに切り替える
git checkout master
なお、ブランチ切り替え時に、作業ツリーやインデックスに変更内容が残っており、かつチェックアウト先のファイルとの間で、残っている変更内容がコンフリクトするのであれば、エラーとなりブランチ切り替えを中止します。
逆に、コンフリクトが発生しないのであれば、変更を作業ツリーや、インデックス上にそのまま維持できます
2指定したコミットにおける任意のファイルを作業ツリーに反映する
git checkout のパラメータに、コミットとパス(ファイル名)を指定すれば、作業ツリーにファイルを展開するコマンドとして動作します。パラメータの違いで、[1]とは少し異なる動作をしますので、それぞれの機能を混同しないように注意して下さい。
さて、引数にはコミット識別子を直接指定しても構いませんし、例えば「HEAD」のような参照でももちろんOKです。
// 例1:コミット「6f87gs1」の index.php を、作業ツリーに展開するコマンド
git checkout 6f87gs1 index.php
// 例2:HEAD の index.php を、作業ツリーに展開するコマンド
git checkout HEAD index.php
もしコミット指定を省略して、パス(ファイル名)のみを指定すれば、代わりにインデックス上のファイルを作業ツリーに展開します。
// インデックスの index.php で、作業ツリーに展開するコマンド
git checkout index.php
git checkout におけるファイルパスの指定方法
git checkout コマンドのファイルパスの指定では、コミットとファイルパスの間に「–」を含めても構いません。例えば・・・
// 現在のブランチの先頭の index.php を、作業ツリーに展開する
git checkout HEAD -- index.php
この記述は、めんどうですので省略する事がほとんどです。
ただ万が一、「インデックスの masterというファイルを作業ツリーに展開したい」のであれば下記のように書く事でmasterブランチでなくファイル名のmaster であることをGitに伝える事ができます。
// インデックスの master を作業ツリーに展開する
git checkout -- master
でも、これが必要となる状況と遭遇することは、まず発生しないでしょう・・・。
git checkout のオプション
git checkout の主要なオプションの紹介です。いくつかのオプションは、ブランチを新規生成する機能がふくまれており、そのため、git branch コマンドと共通のオプションも存在します。
新規ブランチをチェックアウト「git checkout -b」
新規ブランチを作成する、同時にチェックアウトする「-b」オプションは、git checkout で最も利用頻度の高いオプションです。
これは「git branch <ブランチ名>」と「git checkout <ブランチ名> 」のショートハンドとして動作します。また、git branch コマンドのように、ブランチ作成の起点を第二パラメータで指定できます。
// 例)現在のブランチの先頭から、new-feature ブランチを作成してチェックアウト
git checkout -b new-feature
// 例)master を起点に、favorite-feature ブランチを作成してチェックアウト
git checkout -b favorite-feature master
もし、すでに存在するローカルブランチ名であれば、新規ブランチとしては作成できませんが、大文字の「-B」オプションで、強制的に新規ブランチとして再生成し、そこに切り替えることができます。
// dev ブランチがすでに存在しても、強制的に master に合わせて、チェックアウトする
git checkout -B dev master
強制的にチェックアウト「git checkout -f 」
ブランチ切り替え時に、作業ツリーやインデックスに変更が残っていれば、エラーにより、ブランチ切り替えは中断します。一方で、そのような変更をすべて破棄してもよければ、「-f」オプションにより強制的にチェックアウトできます。
// インデックスと作業ツリーの変更を破棄して、強制的にチェックアウトする
git checkout -f master
【参考】リモートブランチは checkoutできるの?
リモートブランチを更新したいとき、ついローカルブランチのようにチェックアウトして編集したくなってしまうかもしれません。ですが、git の仕様上、作業ブランチをリモートブランチに切り替えて、直接更新することはできません。
ローカル環境からリモートブランチを更新する唯一の手段は「ローカルブランチの履歴を、リモートブランチに push する」のみとなります。通常リモートの更新には、下記のような手順を操作を行います。
リモートブランチを更新する手順
- リモートブランチに対応する「リモート追跡ブランチ」をローカルに作成
- 作成したローカルブランチを作成してチェックアウト
- 対応するリモートブランチにPush
1リモートブランチに対応する「リモート追跡ブランチ」を作成する
例えば、リモート「origin」にある「cool-feature」というブランチを更新する場合、git fetch コマンドを使って対応するリモート追跡ブランチを作成します。
// リモートの cool-feature ブランチに対応する追跡ブランチを作成
git fetch origin cool-feature
この時点で、まだ作業用のブランチは作られておらず、リモート追跡ブランチ「origin/cool-feature」が存在するのみです。
2作業用ローカルブランチを作成し、チェックアウトする
[1]を終えた状態で、、下記のように git checkoutコマンドを使えば、自動的に同名のリモート追跡ブランチを起点にして、ローカルブランチを新規生成し、チェックアウトできます。
// リモートのcool-featureブランチをフェッチする git checkout cool-feature
cool-feature は、まだ存在しないブランチ名は「-b」オプションなしにはチェックアウトできないはずですが、指定した「cool-feature」が「origin/cool-feature」とローカルに見つかりますので、この場合、自動的にそのリモート追跡ブランチを起点にして、新しいローカルブランチが作られてくれます。git の親切設計です。
さらに、この方法を使うと、同時に cool-feature ブランチの上流ブランチ(upstream branch と言います)として「origin/cool-feature」が設定されます。これは「git checkout -b <branch> --track <remote>/<branch>」と明示した時と同じ動作となります。
ご参考まで、「上流ブランチ」の概念に関してはこちらをご一読下さい。
3ローカルブランチの変更内容をPushする
あとはPushすればOKです。[2]ですでに上流ブランチが設定されていますので、git push のパラメータは省略できます。
// cool-featureの状態を、対応する上流ブランチにPUSHする
git push
git push origin cool-feature // 同義
試しにリモートブランチをチェックアウトしてみる...
改めて、抑えておく必要があるのは「リモートにあるブランチをチェックアウトする」はできないですし、「リモート追跡ブランチをチェックアウトしてそこで作業する」もできない、という点です。
でも、好奇心で、試しにリモート追跡ブランチをcheckoutしてみたらどうなるでしょうか。
$ git checkout origin/cool-feature
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 91f6913... iUpdate the style.
「Detached HEAD状態」になってしまいました。これは、いわば「匿名ブランチにいる状態」という所で、つまるところ、origin/cool-featureをチェックアウトしてそのブランチで作業できていない(匿名ブランチに乗っている)ということですね。もし、新しいブランチで作業したければ、ちゃんと-bでローカルブランチ作ってね、というただし書きまであります。
ただ「一時的にリモートの状態をローカルで動作させたい」などのテスト目的であれば、あえてこのように匿名ブランチで作業するもの選択肢かもしれませんね。匿名ブランチ上で行った変更はすべてブランチを切り替えなおすと同時に破棄されます。
参考情報
git checkout に関する、Gitの公式ドキュメントです。