Git checkout と switch / restore

ブランチを切り替えるときに必ず使う git checkout。リセットっぽい機能もあったりしてちょっととっつきにくい。

そんなcheckout、いずれ使わなくなるかも??

2019年8月(バージョン2.23)、checkout の機能を2つに分けた switchrestore が実験的なコマンドとして追加された。2020年8月18日の時点でも ”THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.” と記載されており、今後振る舞いが変更される可能性があることには注意が必要だ。

checkout

公式ドキュメントは次のようになっている。

git-checkout - Switch branches or restore working tree files
Git - git-checkout Documentation

git-checkout - ブランチを切り替える、または作業ツリーのファイルを復元する。

ブランチの切り替え

$ git checkout -b develop 
Switched to a new branch ‘develop’
      
$ git branch              
* develop                                  
  master
         
$ git checkout master     
Switched to branch ‘master'                

checkout ブランチ名 で、ブランチの切り替え。 -b オプションをつけると、新しくブランチを作ってそのブランチに切り替える。

作業ツリーのファイルを復元

$ ls
hello.txt
                 
$ rm hello.txt
$ ls

$ git checkout -- hello.txt
$ ls                        
 hello.txt                                   

git checkout -- ファイル名 で、誤って削除した hello.txt を、インデックス(ステージ)から復元できた。

checkout コマンドが担ってきた (1) ブランチの切り替え、(2) 作業ツリーのファイル復元 について、それぞれ新しいコマンドが用意された。

switch

公式ドキュメントは次のようになっている。

git-switch - Switch branches
Git - git-switch Documentation

git-switch - ブランチを切り替える。

$ git switch master   
Switched to branch ‘master'
        
$ git switch -c topic 
Switched to a new branch ‘topic'
     
$ git branch          
  develop                              
  master
* topic

git switch ブランチ名 で、ブランチの切り替え。

checkout -bの、新しいブランチを作って切り替えるのは、switch -c になる。

restore

公式ドキュメントは次のようになっている。

git-restore - Restore working tree files
Git - git-restore Documentation

git-restore - 作業ツリーのファイルを復元する。

$ ls                       
hello.txt
                          
$ rm hello.txt       
$ ls

$ git restore hello.txt    
$ ls                       
hello.txt                                   

git restore ファイル名 で、ファイルをインデックスから復元。デフォルトでは作業ツリーのみが復元される。

--staged オプションをつけるとHEADからインデックスに復元。--staged --worktree オプションでインデックスと作業ツリーを復元。--source オプションで HEAD 以外のコミット指定が可能。

git status の比較

新コマンドに合わせて、git status の表示も変更されている。比較してみるとわかりやすい。

ファイル変更後、インデックス前

v2.27.0(新)

$ git status                                           
On branch topic                                                         
Changes not staged for commit:                                          
  (use "git add <file>..." to update what will be committed)            
  (use "git restore <file>..." to discard changes in working directory) 
     modified:   hello.txt                                                              
                                                                                        
no changes added to commit (use "git add" and/or "git commit -a”)

v2.21.0(旧)

$ git status                                                             
On branch topic                                                             
Changes not staged for commit:                                                    
  (use "git add <file>..." to update what will be committed)      
  (use "git checkout -- <file>..." to discard changes in working  
 directory)                                                        
                                                                                
     modified:   hello.txt                                                  
                                                                                
no changes added to commit (use "git add" and/or "git commit -a”) 

(use "git restore <file>..." to discard changes in working directory) と、checkout が restore に変更されている。ファイル名との間の -- は不要となった。

インデックス後、コミット前

v2.27.0(新)

$ git add .                        
$ git status                       
On branch topic                                     
Changes to be committed:                                    
  (use "git restore --staged <file>..." to unstage) 
    modified:   hello.txt                                   

v2.21.0(旧)

$ git add .                                
$ git status                               
On branch topic                               
Changes to be committed:                      
  (use "git reset HEAD <file>..." to unstage) 

    modified:   hello.txt                     

インデックスしたファイルを解除するときは、従来 reset が使われてきたが、(use "git restore --staged <file>..." to unstage)に変更されている。

感想

switch で「ブランチ切り替え」、restore で「ファイル復元」の方が断然わかりやすい。正式リリースが待ち遠しい。