2017年07月30日

git チェックアウトをもっと便利に使う

ブランチを切り替えるときに使う git checkout コマンド。
ブランチのチェックアウト操作を行うことで、作業ツリーの状態をそのブランチの最新状態に切り替えることができる。

が、チェックアウトできるのは、ブランチだけではない。
他の使い方もあるので、知っていればより便利に git checkout が使える。


まず "HEAD" の状態を確認しておく。".git/HEAD" というファイルが実体。
git_checkout01.png
$ cat .git/HEAD
ref: refs/heads/master

"refs/heads/master" を参照していることを示している。
では、"refs/heads/" にどのようなファイルがあるのか確認してみる。
└ refs
├ heads
├ master
└ new_branch
"master" ブランチと "new_branch" ブランチのファイルがある。では、肝心の "refs/heads/master" には何が書いてあるのか。
$ cat .git/refs/heads/master
b94d4058ea3ef1537213e35212debb2214507a05
"master" ブランチの最新のコミットIDが書かれている。
この実体は ".git/objects/" にあり、コミットIDをもとに探すことができる。
今、参照するコミットIDが "b94d405" なので ".git/objects/b9/4d4058ea3ef1537213e35212debb2214507a05" が "HEAD" が参照するものとなる。
"HEAD"

.git/HEAD

.git/refs/heads/master

.git/objects/b9/4d4058ea3ef1537213e35212debb2214507a05






ファイルの過去のリビジョンをチェックアウトする


「全体としては今の雰囲気が良いいけど、この部分については前の内容のほうがバランスが取れているよね」的なことを言われたり、「落ち着いて考えたらやっぱりこの内容は無し」と思うこともある。
そういう場合は、git reset で作業ツリーを元に戻すことができる。
しかし git reset は作業ツリー上のすべてのファイルを指定状態に戻す。もし、特定のファイルだけ巻き戻したいという場合には、git checkout が使える。

"HEAD" 状態に戻したい場合は以下のようにする。

git checkout HEAD <対象ファイル>

"HEAD" が参照するコミットIDから対象ファイルをロードしてきて、作業ツリー上のファイルを上書きする。
git_checkout02.png

ファイルを戻すのは、"HEAD" だけではなく、コミットIDを指定すれば過去のコミットから特定ファイルをロードすることができる。

git checkout <コミットID> <対象ファイル>

このときの "HEAD" の状態も確認してみる。
$ git checkout b60971b a.txt
$ cat .git/HEAD
ref: refs/heads/master
"HEAD" の状態に変化はなく、"master" ブランチを参照している。

ステータスを見てみる。
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)

modified: a.txt
チェックアウトしたファイルは、ロードするだけではなく、ステージされている。このような動きになることを知っておくとよい。

また、コミットIDだけではなく、タグを指定することもできる。

$ git checkout <タグ> <対象ファイル>



ファイルの変更を元に戻すためだけではなく、過去の内容をちょっと確認したい場合にも使える。コミットIDだけではなく、タグを指定することもできるので、過去のリリースバージョン当時のファイルを確認したいときになどに、その当時のファイルをチェックアウトし、確認が終われば、"HEAD"を指定して戻せば良い。




過去のリビジョンを一時的に取り出す


特定のファイルではなく、特定のコミットを指定すれば、作業ツリーがすべてその当時の状態になるのでは?
と思って、特定のコミットだけ指定してチェックアウトしてみる。

$ git checkout b60971b

Note: checking out 'b60971b'.

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

HEAD is now at b60971b... Add new file : b.txt
何かメッセージが出て警告を受けた気がする。

メッセージ内容はこんな感じ。
"detached HEAD" 状態です。この時点のファイルを見て回ったり、実験的な変更を加えてコミットすることができる。別のブランチをチェックアウトすれば、その他のブランチに影響を与えることなく、ここでの変更を破棄することができる。
もし作成したコミットを残しておくために新しいブランチを作りたいなら、-b を使って再度チェックアウトをすればいい。
例:git checkout -b <new-branch-name>
"HEAD" は、今、 b60971b... Add new file : b.txt

git_checkout03.png

このときの "HEAD" の状態を確認してみる。
$ cat .git/HEAD
b60971b05d47cb17ce3f4ad01be89e3c1d9c8e29
今までと違い、コミットの実体を直接指定している。
HEAD

.git/objects/b6/0971b05d47cb17ce3f4ad01be89e3c1d9c8e29


間違って "detached HEAD" したのであれば、再度ブランチをチェックアウトして、きちんと "detached" では無い状態にする。


意図的に "detached HEAD" にしたのであれば問題無いが、もしgitがせっかく教えてくれたメッセージを無視してブランチをチェックアウトしたものだと勘違いしたまま作業してコミットまでしてしまったとする。
git_checkout04.png
この状態でブランチを切り替えてみる。
$ git checkout new_branch
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

2c8dbd4 detached HEAD

If you want to keep it by creating a new branch, this may be a good time
to do so with:

git branch 2c8dbd4

Switched to branch 'new_branch'

またメッセージが出た。この内容はこんな感じ。
どのブランチにも繋がっていないコミットが1個残っている。

2c8dbd4 detached HEAD

これを新しいブランチを作ることで残したいのであれば、今がいいタイミングです。
以下のようにすればいい。

git branch <new-branch-name> 2c8dbd4

git_checkout05.png
"detached HEAD" になっていることに気づかずにコミットした状態で、他のブランチにチェックアウトすると、"detached HEAD" 状態でコミットした内容は見えなくなってしまうが、無くなったわけではない。どこからも参照されないだけで記録は残っている。

これを復活させるためには、gitが教えてくれた通りに実行すればいい。
一時的なブランチを作ればいい。

$ git checkout tmp


これで参照できるようにつながったので、後はこのブランチをマージするなりして対応すればいい。作業した内容を無事に復旧できれば、一時的なブランチなので削除すれば終了。






まとめ


git checkout でファイルの変更を無かったことにしたり、巻き戻したりできるので知っておくと、いざというときにさっと作業できるので便利。ただし、コミットIDでチェックアウトし、"detached HEAD" にしてしまうと、この状態を知っていると知らないでは、このあとの作業の内容が違ってくる。間違ったまま作業していくと、コミット内容が見える範囲から消えてしまうことになりかねない。
gitがきちんとメッセージで教えてくれているので、慣れた作業であってもメッセージを読み飛ばさないように注意したほうがいい。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする
この記事へのコメント
コメントを書く
コチラをクリックしてください