gitで○○する前のソースを取得する
gitを使って過去の作業ツリーを取得する方法を紹介します。
注意事項
以下の説明中には git checkout
でブランチを離れる手順があります。ブランチを離れることに慣れていない方(普段 git switch
を使っていて -d
オプションを使ったことがない方など)は、お試しの際、ブランチを離れた時点で表示されるメッセージ[1]をよく読むことをおすすめします。
コミットする前
git commit
でコミットする前のソースを取得するには
$ git checkout HEAD~
とします。HEAD~
は今居るブランチの最新コミット HEAD
の親コミットを指します。
マージする前
git merge
で作成されるマージコミットの場合には親コミットが複数あるのでその中から取得対象を選択します。例えば
$ git checkout HEAD^
(HEAD~
でも同じ)とすれば HEAD
の1番目の親を選択して、マージ先ブランチのマージ前のソースを取得でき、
$ git checkout HEAD^2
のように2番目の親を選択すれば、マージ元ブランチの最終コミットのソースを取得できます。
もっと前のコミット
もっと前のコミットのソースを取得するには、~
や ^
を複数組み合わせて辿る(例えば git checkout HEAD~~~
)か、あるいは git log
や git blame
で対象のコミットハッシュを特定した上で
$ git checkout コミットハッシュ
とコミットを指定してソースを取得します。
リセットする前
git reset --hard
で HEAD
を書き換えた直後に
$ git checkout HEAD@{1}
とすると reset 前のソースを取得できます。ただし git reset --hard
で失われた未コミットの変更があったとしてもそれらは戻ってきません。
HEAD@{N}
の形式でもっと前の作業ツリーの取得もできます。Nの値(N=0,1,2,...)ごとに何が取得されるかは git reflog
で確認できます。
リベースする前
git rebase
では reflog に複数のログが記録されるため、git reflog
して
HEAD@{N}: rebase (start):
(Nは何らかの整数)を見つけて、
$ git checkout HEAD@{N+1}
(N+1には上で見つけた整数Nに1を足した結果を入力)すると rebase する前のソースを取得できます。
チェックアウトする前
$ git checkout -
で git checkout
や git switch
する前のブランチ/コミットのソースを取得できます。
$ git checkout @{-1}
としても同じです。ブランチをチェックアウトしていた場合はブランチをチェックアウトした状態になり、detached HEAD だった場合には detached HEAD 状態でコミットを取得します。
@{-N}
の形式でもっと前のものも取得できます。Nの値(N=1,2,...)ごとに何が取得されるかは git reflog
して checkout: moving from
が見つかった順番で確認できます:
$ git reflog|sed -n "s/.* checkout: moving from \(.*\) to .*/\1/p"|awk '{ print "@{-" NR "} " $1 }'
まとめ
git checkout
で過去の作業ツリーを取得する方法をいくつか紹介しました。
最後に紹介したように git checkout -
すればチェックアウトする前の状態に戻って来れますし、チェックアウトで作業ツリーの変更が失われる可能性があれば
$ git checkout チェックアウト対象
error: Your local changes to the following files would be overwritten by checkout:
変更されていたファイル
Please commit your changes or stash them before you switch branches.
Aborting
とエラーで止めてくれる[2]ので安心です。気軽に現在と過去を行ったり来たりしてみてください。
Discussion