[git reset (--hard/--soft)]ワーキングツリー、インデックス、HEADを使いこなす方法

  • 439
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

1. gitの基礎(言葉の意味)

  • ワーキングツリー[working tree]:最新のファイルの状態
  • インデックス[index](ステージ[stage]):コミットするためのファイルの状態
  • ローカルリポジトリ[local repository]:ファイルの変更履歴を記録(手元で管理)
    • ヘッド[HEAD]:最新のコミットの状態
  • リモートリポジトリ[remote repository]:ファイルの変更履歴を記録(みんなで共有)

2015_0307commit図_2.jpg

  • add:「ワーキングツリー → インデックス」への反映
  • commit:「インデックス → ローカルリポジトリ」への反映
  • push:「ローカルリポジトリ → リモートリポジトリ」への反映

2. git resetを使いこなす

git resetには--hard--mixed--softの3つのオプションがある。

※厳密にはもっとあります。詳しくは`git reset -h`を叩くなどして見てください。

それぞれのオプションにおいて、修正の及ぶ範囲は下記。

  • --hard:「HEADの位置・インデックス・ワーキングツリー」全て
  • --mixed(or オプション無し):「HEADの位置・インデックス」
  • --soft:「HEADの位置」のみ

現在のファイルの状態をYとする。
2015_0307git_reset_1_.jpg

  • ファイルを変更したらワーキングツリーが変更
  • addしたらインデックスが変更
  • commitしたらHEAD( = 最新のコミットのハッシュ値のエイリアス)が1つ前に進む

2015_0307git_reset_2_.jpg
変更をコミットしてファイルの状態がZに移ったとする。
2015_0307git_reset_3_.jpg

  • reset --hard:全部Yに戻す。
  • reset --mixedcommitaddの取り消し。
  • reset --softcommitのみ取り消し。

2015_0307git_reset_4_.jpg

★主な利用シーン★

① 直前のコミットを取り消したい(コミットのみ取り消し)

git reset --soft HEAD^
  • HEAD^:直前のコミットを意味する。
    • @^HEAD~も同じ意味。
    • HEAD~{n} :n個前のコミットを意味する。
    • HEAD^HEAD~{n}の代わりにコミットのハッシュ値を書いても良い。
    • gitのv1.8.5からは、「HEAD」のエイリアスとして「」が用意されている。
    • HEAD^^^HEAD~3HEAD~~~HEAD~{3}@^^^は同じ意味。
  • --softなので、インデックス・ワーキングツリーはそのまま。
  • 上書きコミットしたいなら、git commit --amendを使うとラク!

② 直前のコミットを取り消したい(マルっと消したい)

git reset --hard HEAD^
  • --hardなので、「インデックス・ワーキングツリー」も1つ前のコミットの状態に戻る。

③ コミット後の変更を全部消したい

git reset --hard HEAD
  • --hardなので、「HEADの位置・インデックス・ワーキングツリー」を全てHEADの位置に動かす。
    • HEADの位置はそのまま。
    • 「インデックス・ワーキングツリー」の変更が消せる。

④ addを取り消したい

git reset --mixed HEAD

または、

git reset HEAD
  • --mixed(or オプション無し)なので、「HEADの位置・インデックス」をHEADの位置に動かす。
    • HEADの位置はそのまま。
    • 従って、インデックスの変更(addした内容)のみ元に戻す。

⑤ すごい昔の状態で動作を確認したい

git reset --hard 昔のコミットのハッシュ値
  • これをやる前に、pushして置くことを強くオススメします!
  • reset --hardは基本的にすべて消えるので慎重に。
    • 一応復活させる術はなくはない。
  • remoteに最新の状態を記録しておけば、ローカルは好きな所に移動しても安心。
  • コミットのハッシュ値はgit logで確認すればOK!

動作確認後、最新の状態に戻るには、また、

git reset --hard ORIG_HEAD

をすれば良い。

  • git reset --hard ORIG_HEAD:直前のresetをなかったことにするおまじない!
  • git resetは未来の状態にも行ける。
  • git reset --hard 最新のコミットのハッシュ値でも良い。
  • git rebase origin/masterでも良い。
  • reset --hardrebaseする時は、こまめにソースツリーの状態を確認しておくといいと思います。

3. 間違えてgit resetしちゃったら・・・

直前のリセットを取り消したいなら、

git reset --hard ORIG_HEAD

をすればOK!

reset後色々いじってしまっていたら、慌てずに、git reflogコマンドを叩きましょう。

  • git log:コミットの履歴を見る
  • git reflog:これまでHEADが辿ってきた履歴を見る

git reflogで戻したい状態を見つけ出し、

git reset [(必要なら)オプション] [ハッシュ値]

をすれば良い。
resetで困ったときは「resetreflog」と覚えておこう!

(注) reflogは万能ではない

git reflogは、「これまでHEADが辿ってきた履歴」を保持しているものです。
addしただけでcommitしてないものがある時に、reset --hardをしてしまったら、addした内容は復元不可能です。
addすらしてないものももちろん消えます。

  • git resetを使うときはくれぐれも慎重に!

4. おまけ(gitを使いやすくする)

① ローカルの変更内容を一時的に退避させる。

git stash

退避させた内容を元に戻すには、下記を叩けばOK!

git stash pop

② aliasを作成

gitのaliasは~/.gitconfigに書き込むことが可能。

vim ~/.gitconfig
~/.gitconfig
[alias]
    ad = add
    br = branch
    ci = commit
    co = checkout
    ft = fetch
    pl = pull
    ps = push
    sh = show
    st = status

ただ、個人的にはgitを打つのも面倒なので~/.bashrcにgit系のaliasも書いている。

vim ~/.bashrc
~/.bashrc
# git
alias g='git'
alias gb='git branch'
alias gs='git status'
alias gd='git diff'
alias gds='git diff --staged'
alias ga.='git add .'
alias gcm='git commit -m'
alias gcam='git commit -am'
alias gpod='git push origin develop'
alias gp='git push'
alias gfo='git fetch origin'
alias grod='git rebase origin/develop'
alias gsp='git stash pop'
alias gsu='git submodule update --init --recursive'
alias gcd='git checkout develop'
alias gmnf='git merge --no-ff'

masterを直接いじることをせずdevelopブランチ切ることが多いため、上のようなaliasにしている。
あと、運用方法の好みとして、pullせずrebaseする風潮が自分のまわりであるので、gppushの意味も持たせてしまっている。

③ その他

▼git rebase 失敗した時の対処法
http://qiita.com/shuntaro_tamura/items/c505b76c1021a35ca9ff

▼Gitで補完機能を有効にする方法
http://qiita.com/shuntaro_tamura/items/9ed9321e64dc208fe95a

▼ファイルの変更履歴を行単位(orコミット単位)で調べる方法
http://qiita.com/shuntaro_tamura/items/b8b99a9b4987144581e9

▼コミットの取り消し、打ち消し、上書き
http://qiita.com/shuntaro_tamura/items/06281261d893acf049ed

▼ブランチ切って更新してマージするまでの流れ
http://qiita.com/shuntaro_tamura/items/6c8bf792087fe5dc5103

▼初心者のためのgitコマンド
http://qiita.com/shuntaro_tamura/items/5228a29082a844d4875c

▼【Gitおすすめサイト1】サルでもわかるGit入門
http://www.backlog.jp/git-guide/

▼【Gitおすすめサイト2】Git公式ドキュメント
http://git-scm.com/docs/