git reset & git checkout 使い分けまとめ
こんにちは、CX事業本部の若槻です。
Gitコマンドのgit reset
とgit checkout
は、いずれも「インデックス(ステージ)」や「作業ツリー」や「HEAD」などを指定の状態に戻すことができるコマンドです。今回はこのgit reset
とgit checkout
をどんなときにどう使えばよいか?を整理してみました。
git helpを見てみる
まず、各コマンドのgit helpを見てみます。
git resetについて
$ git reset --help NAME git-reset - Reset current HEAD to the specified state SYNOPSIS git reset [-q] [<tree-ish>] [--] <paths>... git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>] DESCRIPTION In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The <tree-ish>/<commit> defaults to HEAD in all forms.
要約するとgit reset
は主に以下の操作ができるようです。
- 現在のブランチのHEADからステージへエントリーをコピーし、オプションで作業ツリーへエントリーをコピーする。
- 現在のブランチのHEADを指定のコミットに移動し、オプションで移動先のコミットからステージと作業ツリーへエントリーをコピーする。
git checkoutについて
$ git checkout --help NAME git-checkout - Switch branches or restore working tree files SYNOPSIS git checkout [-q] [-f] [-m] [<branch>] git checkout [-q] [-f] [-m] --detach [<branch>] git checkout [-q] [-f] [-m] [--detach] <commit> git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... git checkout [<tree-ish>] [--] <pathspec>... git checkout (-p|--patch) [<tree-ish>] [--] [<paths>...] DESCRIPTION Updates files in the working tree to match the version in the index or the specified tree. If no paths are given, git checkout will also update HEAD to set the specified branch as the current branch.
要約するとgit checkout
は主に以下の操作ができるようです。
- 作業ツリーのファイルをステージまたは指定されたツリーのバージョンと一致させる。pathspecが指定されていない場合、HEADを指定されたブランチに設定する。
どんなときにどのコマンドを使えば良いか整理してみた
どんなとき(何を何の状態で戻したいとき)にどのコマンドを使えば良いか、大きく以下の二通りに分けて整理してみました。
- HEADまたはステージから戻す場合
- 過去のコミットから戻す場合
HEADまたはステージから戻す場合
1. ステージから作業ツリーに特定のファイルを戻す
この場合はgit checkout -- <ファイル>
コマンドを利用します。
利用例
ファイルaaa.txt
とbbb.txt
がステージに追加され、さらに作業ツリーで変更されています。
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: aaa.txt new file: bbb.txt 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: aaa.txt modified: bbb.txt
git checkout -- aaa.txt
を実行します。
$ git checkout -- aaa.txt
ステージから作業ツリーにファイルaaa.txt
のみ戻りました。(aaa.txt
のステージ未追加の変更が消された)
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: aaa.txt new file: bbb.txt 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: bbb.txt
ちなみにステージにないファイルをチェックアウトしようとするとエラーとなります。
$ git checkout -- ddd.txt error: pathspec 'ddd.txt' did not match any file(s) known to git.
2. ステージから作業ツリーにすべてのファイルを戻す
この場合はgit checkout .
コマンドを利用します。
利用例
ファイルaaa.txt
とbbb.txt
の変更がステージに追加され、さらに作業ツリーで変更されています。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: aaa.txt new file: ccc.txt 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: aaa.txt modified: ccc.txt
git checkout .
を実行します。
$ git checkout .
ステージから作業ツリーにすべてのファイル(aaa.txt
、ccc.txt
)が戻りました。(ステージ未追加の変更が消された)
戻りました。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: aaa.txt new file: ccc.txt
3. HEADからインデックスと作業ツリーに特定のファイルを戻す
この場合はgit checkout HEAD -- <ファイル>
コマンドを利用します。
利用例
ファイルaaa.txt
とbbb.txt
の変更がステージに追加され、さらに作業ツリーで変更されています。
$ git status On branch master Your branch is up-to-date with 'origin/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: aaa.txt new file: bbb.txt 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: aaa.txt modified: bbb.txt
git checkout HEAD -- aaa.txt
を実行します。
$ git checkout HEAD -- aaa.txt
HEADからステージと作業ツリーにファイルaaa.txt
のみ戻りました。(aaa.txt
の未コミットの変更が消された)
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: bbb.txt 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: bbb.txt
ちなみにHEADにないファイルをチェックアウトしようとするとエラーとなります。
$ git checkout HEAD -- ddd.txt error: pathspec 'ddd.txt' did not match any file(s) known to git.
4. HEADからステージにすべてのファイルを戻す
この場合はgit reset HEAD
コマンドを利用します。
利用例
ファイルの変更がステージに追加され、さらに作業ツリーで変更されています。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: bbb.txt 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: bbb.txt
git reset HEAD
を実行します。
$ git reset HEAD
HEADからステージにすべてのファイルが戻りました。(HEADの状態でステージの内容が上書きされた。)
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) 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: bbb.txt no changes added to commit (use "git add" and/or "git commit -a")
5. HEADからステージと作業ツリーにすべてのファイルを戻す
この場合はgit reset --hard HEAD
コマンドを利用します。(HEAD
は省略可能)
ファイルの変更がステージに追加され、さらに作業ツリーで変更されています。
利用例
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: aaa.txt 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: bbb.txt Untracked files: (use "git add <file>..." to include in what will be committed) ccc.txt
git reset --hard HEAD
を実行します。
$ git reset --hard HEAD
Untracked filesを除き、HEADからステージと作業ツリーにすべてのファイルが戻りました。(HEADの状態でステージと作業ツリーの内容が上書きされた。)
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Untracked files: (use "git add <file>..." to include in what will be committed) ccc.txt nothing added to commit but untracked files present (use "git add" to track)
過去のコミットから戻す場合
1. 過去のコミットからステージと作業ツリーに特定のファイルを戻す
この場合はgit checkout <コミット> -- <ファイル>
コマンドを利用します。
利用例
HEADから1つ前のコミット391ab85
からファイルaaa.txt
を取り出したいとします。
$ git log --oneline a80ef38 (HEAD -> master) なんかコミット3 391ab85 なんかコミット2 26d97d8 なんかコミット
ステージと作業ツリーはクリーンです。
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
git checkout 391ab85 -- aaa.txt
を実行します。
$ git checkout 391ab85 -- aaa.txt
HEADから1つ前のコミットからステージと作業ツリーにファイルaaa.txt
のみが取り出せました。
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: aaa.txt
2. HEADを過去のコミットに移動する
この場合はgit reset --soft <コミット>
コマンドを利用します。
利用例
HEADから1つ前のコミット391ab85
にHEAD位置を移動したいとします。
$ git log --oneline a80ef38 (HEAD -> master) なんかコミット3 391ab85 なんかコミット2 26d97d8 なんかコミット
ステージと作業ツリーはクリーンです。
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
git reset --soft 391ab85
を実行します。
$ git reset --soft 391ab85
HEADが過去のコミット391ab85
に移動しました。
$ git log --oneline -3 391ab85 (HEAD -> master) なんかコミット2 26d97d8 なんかコミット e17fe0e さらに前のコミット3
ステージの内容は変更されないので、移動後のHEADとの差分がステージでは表示されています。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: aaa.txt new file: ccc.txt
3. HEADを過去のコミットに移動し、ステージの内容を移動先のコミットの状態に戻す
この場合はgit reset --mixed <コミット>
コマンドを利用します。(--mixed
は省略可能)
利用例
HEADから1つ前のコミット391ab85
にHEAD位置を移動し、ステージの内容を移動先のコミットの状態に戻したいとします。
$ git log --oneline -3 8b911dc (HEAD -> master) こみっと 391ab85 なんかコミット2 26d97d8 なんかコミット1
ステージと作業ツリーはクリーンです。
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
git reset --mixed 391ab85
を実行します。
$ git reset --mixed 391ab85
HEADが過去のコミット391ab85
に移動しました。
$ git log --oneline -3 391ab85 (HEAD -> master) なんかコミット2 26d97d8 なんかコミット1 e17fe0e さらに前のコミット
作業ツリーの内容は変更されないので、移動後のHEAD(=ステージ)との差分が作業ツリーでは表示されています。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) 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: aaa.txt Untracked files: (use "git add <file>..." to include in what will be committed) ccc.txt no changes added to commit (use "git add" and/or "git commit -a")
4. HEADを過去のコミットに移動し、ステージと作業ツリーの内容を移動先のコミットの状態に戻す
この場合はgit reset --hard <コミット>
コマンドを利用します。
利用例
HEADから1つ前のコミット391ab85
にHEAD位置を移動し、ステージと作業ツリーの内容を移動先のコミットの状態に戻したいとします。
$ git log --oneline -3 51e4398 (HEAD -> master) とりあえずこみっと 391ab85 なんかコミット2 26d97d8 なんかコミット
ステージと作業ツリーはクリーンです。
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean
git reset --hard 391ab85
を実行します。
$ git reset --hard 391ab85
HEADが過去のコミット391ab85
に移動しました。
$ git log --oneline -3 391ab85 (HEAD -> master) なんかコミット2 26d97d8 なんかコミット e17fe0e その前のこみっと
移動後のHEADとステージと作業ツリーの内容が同じとなるので、ステージと作業ツリーはクリーンとなります。
$ git status On branch master Your branch is ahead of 'origin/master' by 1 commit. (use "git push" to publish your local commits) nothing to commit, working tree clean
まとめ
- HEADまたはインデックスから戻す場合
- ステージから作業ツリーに特定のファイルを戻す:
git checkout -- <ファイル>
- ステージから作業ツリーにすべてのファイルを戻す:
git checkout .
- HEADからインデックスと作業ツリーに特定のファイルを戻す:
git checkout HEAD -- <ファイル>
- HEADからステージにすべてのファイルを戻す:
git reset HEAD
- HEADからステージと作業ツリーにすべてのファイルを戻す:
git reset --hard HEAD
- ステージから作業ツリーに特定のファイルを戻す:
- 過去のコミットから戻したい場合
- 過去のコミットからステージと作業ツリーに特定のファイルを戻す:
git checkout <コミット>
- HEADを過去のコミットに移動する:
git reset --soft <コミット>
- HEADを過去のコミットに移動し、ステージの内容を移動先のコミットの状態に戻す:
git reset --mixed <コミット>
- HEADを過去のコミットに移動し、ステージと作業ツリーの内容を移動先のコミットの状態に戻す:
git reset --hard <コミット>
- 過去のコミットからステージと作業ツリーに特定のファイルを戻す:
※git reset
やgit checkout
でHEADや過去のコミットから作業ツリーに内容を戻すときの変更は必ずステージを経由することを覚えておくと、上記のコマンド実行のイメージ画像は見やすいかと思います。
おわりに
以上、git reset
とgit checkout
をどんなときにどう使えばよいか?を整理してたという記事でした。
両コマンドの使い分けがいまいち曖昧だったので整理できて良かったです。
あと、参考に記載の書籍はGit解説本としてすごく分かりやすいのでおすすめです!
参考
以上