MarkdownとBullet Journal

いわゆるプログラマーのつぶやき

【Git】reset , checkout , 「 . 」有無の比較表

間違えやすい操作を表で整理

以前にgit checkoutとgit resetをまとめたが、各コマンド後のステージング(staging, index)と作業ディレクトリのファイルの変化を比較表で整理し直した。特に全file選択を意味する末尾の「.」の有無で、

  • git checkout "指定commit"  指定commitに移動するコマンド
  • git checkout "指定commit" .  指定commitから指定fileを作業ディレクトリとstagingに戻すコマンド
  • git reset "指定commit"    指定commitをHEADに更新するコマンド
  • git reset "指定commit" .    指定commitからfileをstagingに戻すコマンド

と全く異なる動作になる点を明確にする。詳細な説明は前の記事に譲り、視覚的に差を分かりやすくまとめた。

以前の記事:

programmingforever.hatenablog.com

機能整理表とファイルの動き比較表

以上各コマンドの機能整理と各ファイルの動きがわかる比較表をまとめる。最初にcommit指定時の表を記載し、次に最新commitまたはcommit未指定時の表を記載する。最後に各コマンド毎にfile移動の詳細説明を行う。

⒈ commit指定時の各コマンドの機能整理表

f:id:ProgrammingForEver:20210905090833j:plain

例:10個前のcommitを指定した時のHEADとfileの動き

f:id:ProgrammingForEver:20210908090453p:plain f:id:ProgrammingForEver:20210908093550p:plain

前の記事でまとめた各コマンドの利用目的と照らし合わせると理解しやすいと思う。

file指定がないコマンドの利用目的:
  • git reset --soft "指定commit" は、commitを無かったことにしたい時
  • git reset "指定commit" は、整理されたcommitに改変したい時
  • git reset --hard "指定commit" は、一からやり直したい時
  • git checkout "指定commit" は、以前のVer.確認やブランチを切りたい時
file指定があるコマンドの利用目的:
  • git checkout "指定commit" files:作業ディレクトリ内の指定fileは不要で、指定commitから指定fileを戻したい時
  • git reset "指定commit" files:作業ディレクトリ内の指定fileは必要で、指定commitから指定fileを戻して利用したい時

共にHEADは動かず、git chechoutはstagingと作業ディレクトリに指定fileを戻す動作、git resetはstagingだけに戻す指定fileを戻す動作なので上記目的に適する。

2. 最新commitを指定または省略時の各コマンドの機能整理表

状態:commit後にfile編集+staging、さらにfile編集した状態からのコマンド入力を想定

f:id:ProgrammingForEver:20210905105850j:plain

例:最新commit (HEAD)を指定または省略時のfileの動き

f:id:ProgrammingForEver:20210908092750p:plain f:id:ProgrammingForEver:20210908093343p:plain

こちらは少し解説する。

  • git resetは、最新commitをstagingに戻す
  • git reset --hardは、最新commitをstagingと作業ディレクトリに戻す
  • git checkout filesは、staging内の指定fileを作業ディレクトリに戻す
  • git checkout HEAD filesは、最新commit内の指定fileをstagingと作業ディレクトリに戻す
  • git reset files は、最新commit内の指定fileをstagingに戻す

git reset --hard と git checkout HEAD . の結果は一見同じ様に見えるが、最新commit後に追加したファイル(図ではd.sh)がresetコマンドでは削除され、checkoutコマンドでは残る点が違う

またgit checkout HEAD. とgit reset . もよく似ているが**reset . はstagingにだけコピー、checkout HEAD . はstagingと作業ディレクトリにコピー(編集内容を失う)となる点が全く違う。

ファイルではなく行単位での操作も可能

ここで挙げた中で . または file名が付くコマンドに-pオプション(--patch)を加えると、file単位ではなく変更のあった行の塊(ハンク)単位、あるいは1行単位でreset(ステージングの修正)やDiscard(作業ディレクトリの修正)が出来る。2つのfileの差分を見ながらハンク(行の塊)単位で残すか否かを対話式で選択出来る。詳しくは「gitのハンク」記事を参照願いたい。

programmingforever.hatenablog.com

以下丸数字の番号順にfileの移動を說明

①想定する初期状態(ある開発中の状態)

  • 社内業務用のシェルプログラムのプロジェクトとする
  • 10回前のcommitでファイルはa.shとb.shがあり、b.sh内の変数名はhoge
  • 1回前のcommitでb.shの変数名をfugaに修正
  • 最新commitでc.shファイルを追加
  • 編集を再開しb.shの変数名をpiyoに変えてstaging(index)した。d.shファイルも追加&staging
  • さらにb.shの変数名をfugafugaに変えた所で、stagingと作業ディレクトリの内容が違っている
  • この状態を基本として、色々とresetやcheckoutを使って変化させてみる
  • 変化が発生した部分を朱書きで表示

f:id:ProgrammingForEver:20210902080348p:plain

②git reset --soft

  • HEAD: 移動しない(元の位置を指すため *commi未指定時はHEAD)
  • staging: 変化なし
  • 作業ディレクトリ: 変化なし

③git reset (--mixed)

  • HEAD: 移動しない(元の位置を指すため *commi未指定時はHEAD)
  • staging: 最新commitの内容に戻す
  • 作業ディレクトリ: 変化なし

④git reset --hard

  • HEAD: 移動しない(元の位置を指すため *commi未指定時はHEAD)
  • staging: 最新commitの内容に戻す
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

git reset .

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: HEAD/masterのファイルが一式コピーされる。同一名のファイルは上書きされる。staging内のみ存在するファイルは削除されず残る
  • 作業ディレクトリ: 変化なし

git reset file名

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: HEAD/masterから指名したファイルだけがコピーされる。同一名のファイルは上書きされる。他は影響されない
  • 作業ディレクトリ: 変化なし

f:id:ProgrammingForEver:20210902080529p:plain

⑤git checkout または git checkout HEAD

  • HEAD: 移動しない(commit指定がない、あるいは元の位置を指しているため)
  • staging: 変化なし
  • 作業ディレクトリ: 変化なし

⑥git checkout .

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: 変化なし(commit指定がないためコピー出来ない)
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

⑦git checkout HEAD .

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: HEAD/masterのファイルが一式コピーされる。同一名のファイルは上書きされる。staging内のみ存在するファイルは削除されず残る
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

⑧git checkout HEAD file名

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: HEAD/masterから指名したファイルだけがコピーされる。同一名のファイルは上書きされる。他は影響されない
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

f:id:ProgrammingForEver:20210902080616p:plain

⑨git reset --soft HEAD~10

  • HEAD: 指定された10個前のcommitまで戻り、それまでのcommit履歴を削除する
  • staging: 変化なし
  • 作業ディレクトリ: 変化なし

⑩git reset (--mixed) HEAD~10

  • HEAD: 指定された10個前のcommitまで戻り、それまでのcommit履歴を削除する
  • staging: 指定commitの内容に戻す
  • 作業ディレクトリ: 変化なし

⑪git reset --hard HEAD~10

  • HEAD: 指定された10個前のcommitまで戻り、それまでのcommit履歴を削除する
  • staging: 指定commitの内容に戻す
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

git reset HEAD~10 .

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: 指定commitからファイルが一式コピーされる。同一名のファイルは上書きされる。staging内のみ存在するファイルは削除されず残る
  • 作業ディレクトリ: 変化なし

git reset HEAD~10 file名

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: 指定commitから指名したファイルだけがコピーされる。同一名のファイルは上書きされる。他は影響されない
  • 作業ディレクトリ: 変化なし

f:id:ProgrammingForEver:20210902080704p:plain

⑫git checkout HEAD~10

  • HEAD: 指定されたcommitに移動する(Detouch状態)
  • staging: 指定commitの内容に戻す
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

⑬git checkout HEAD~10 .

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: 指定commitからファイルが一式コピーされる。同一名のファイルは上書きされる。staging内のみ存在するファイルは削除されず残る
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)

⑭git checkout HEAD~10 file名

  • HEAD: 移動しない(ファイルコピー動作)
  • staging: 指定commitから指名したファイルだけがコピーされる。同一名のファイルは上書きされる。他は影響されない
  • 作業ディレクトリ: stagingと同一(管理対象外ファイルを除く)