🐡

gitのcheckoutはブランチ移動だけじゃなかったという話

2022/12/20に公開

gitのコマンドを勉強する際、git checkout "ブランチ名"というコマンドを始めのころに学ぶ人は多いと思います。そしてこのコマンドはブランチ切り替えのためのものなので、「checkout = gitでブランチ切り替えのための呪文」みたいなイメージを持つ人も多分そこそこいると思います。
その理解自体が完全に間違っているわけでなく、むしろそのままでもなんとかなるケースも多いです。が、そのイメージのままだと次のようなコマンド見ると困惑することになります。

$ git checkout .

「私の知っているcheckoutじゃない!」というのが私の初見の感想でした(というか、ここまでの流れすべて実体験です)。

そんなこんなで勉強して備忘録としてまとめたのがこの記事です。以下、checkoutの挙動について紹介していくのですが、見習いエンジニアが書いてるものなので、変なところなどがあったら指摘してもらえると嬉しいです。

現在の作業場所の変更

こいつはよく使うgit checkout "ブランチ名"みたいなやつですね。ブランチ移動というイメージが強いかもしれませんが、細かいことを言うとブランチを切り替えているのではなく、そのブランチでの最新コミットの状態にしている、というのがより正確の認識らしいです。
そのため、下のコマンドのように、ブランチではなくコミットを指定して特定のコミットの状態にすることも可能です。

$ git checkout <指定したいコミットのID>

一部のファイルのみ別コミットの状態にする

上でコミットの状態にすることができると紹介しましたが、

$ git checkout <指定したいコミットのID> <指定したいファイル名>

とすることで一部のファイルのみ別コミットの状態にすることができます。

パット見、わざわざ項目分けるほどの違いに見えないかもしれませんが、この一部ファイルのみの変更はコンフリクト対処で活躍します。マージやstashを利用してコンフリクトが発生した際に、

$ git checkout -ours <指定したいファイル名>

とすることで、自分が今いるブランチを優先することができます。ちなみに、-theirsを指定することでマージ相手を優先することもできます。

過去のファイルの復元

今までの紹介で
コミットIDのみ → 指定されたコミットの状態にする
コミットIDとファイル名 → 指定されたファイルのみ、指定されたコミットの状態にする
となっていたわけですが次は、じゃあファイル名のみだとどうなるの、という話です。
具体的には、

$ git checkout  <指定したいファイル名>

というコマンドですね。

このコマンドでは、最新コミット(自分が作業場所として移動していたコミット)を参照します。つまり、指定したファイルに関して最新コミットに加えた変更を戻すことができる、というわけです。
ただし注意が必要でして、git checkout "ファイル名"ではステージしていない変更(git addしていない変更)しか戻すことができません。一度addした変更を戻すためにはgit restoreを利用してください。

ちなみに、このファイルの復元が一番最初で紹介したコマンドの正体です。ファイル名の代わりに.(ドット)を指定すると、現在のディレクトリにあるすべてのファイルに対して復元が行われます。

結局"checkout"ってなんなのか

上の3つでコマンドの紹介は終わりですが、そもそもcheckoutってどんな意味だっけ、という話です。
私は「チェックアウト」という響きからは最初ホテルの手続きしか浮かばなかったんですが、IT用語として「バージョン管理システムから履歴を取り出す」という意味があるらしいです。
つまりgitでいうと、コミットという作業履歴を取り出す、という意味になります。確かに上で紹介した3つはすべてコミットを参照していましたね。ファイルの復元や作業場所の変更のようにgit checkoutの役割は一見するとまとまりのないように見えますが、「コミットを取り出す」という意味を意識すればつながりが見えて扱いやすくなるかもしれません。

以上、自分用のまとめを兼ねた記事でしたが、誰かの役に立てば幸いです。
以下、勉強する際に利用させてもらった記事です。
https://zenn.dev/tekihei2317/articles/bbdaf8173f21c9
https://prograshi.com/general/git/how-to-undo-modifications/

Discussion