“git prune”コマンドが何をしてくれるものなのかを操作しながら理解する
はじめに
git prune
コマンドは掃除用の Git サブコマンドです。
Git のコミット履歴の実体はハッシュ値を一意キーとする "Git オブジェクト" の集合体です。
Git オブジェクトのうち、到達不能(不要)になったものを掃除するために使用するのが git prune
コマンドです。
ブランチ名やタグ名を起点として、コミットツリーからたどることができなくなった要素を 到達不能となった Git オブジェクト と呼びます。
git prune
は基本的に直接実行しません。
「ゴミ掃除コマンド」であり、git gc
コマンドの 子コマンド ( git gc
コマンドの中で実行されるコマング群の 1 つ ) です。
検証環境
git prune
コマンドの「お掃除機能」について
git prune
コマンドが実行されたときにどんなことが起きるかを理解するために、
実際に到達不能なコミットを作った後、実行してみましょう。
はじめに以下のいくつかのコマンドを実行してみます。
まずは git-prune-demo
という作業用ディレクトリを作成し、移動します。
次にこのディレクトリを Git 管理対象に含めた後、 hello.txt
というテキストファイルを 1 つ追加します。
hello.txt
というファイルがコミットされました。
次に、 hello.txt
を修正して 2 つ目のコミットをあげます。
リポジトリには、2 つのコミット履歴が含まれました。
履歴情報は git log
コマンドを使って確認できます。
git log
コマンドの実行結果からは 2 つのコミットが確認できます。
コミットメッセージも確認できますね。
ここからです。コミットのうちの 1 つをカレントブランチから 切り離して みます。git reset
コマンドを使用します。
git reset
を実行し、最終コミットが 1 つ目のコミットを指すようにします。( 指定するハッシュ値は git log
コマンドの表示内容から確認できます。 )
この状態で git log
コマンドを実行すれば、以下のように 1 コミットだけが表示されているはずです。
2 つ目のコミットは、カレントブランチから 切り離された 状態になっています。
"added another line to hello.txt" というメッセージの 2 つめのコミットは、今は git log
コマンドで表示されることは有りません。
一見、コミットが削除されたかのように見えますが、Git は履歴が削除されないようにしっかり管理してくれています。
切り離されたコミットに対して、 git checkout
コマンドを使用すると再度到達できます。
2 つ目のコミットを checkout
すると、再び 2 つのコミットに対して 到達可能 な状態に戻りました。
git log
コマンドでも 2 つ目のコミットが確認できます。
このように、 git reset
するとカレントブランチから切り離されたコミットができますが、Git の管理内には残っています。
( これが蓄積されてくると .git
フォルダ内のファイルが徐々に増加して、 git
コマンド実行の際の重さにつながります。 )
さて、 git checkout
を使って、もう一度 master ブランチに戻ります。
再び、2 つ目のコミットが切り離されている状態となりました。
git prune
コマンドを使って、 到達不能 なコミットを掃除するときが来ました。
確認のために --dry-run
オプションを --verboase
オプションを付けて実行します。
実行してみたは良いですが、何も表示されません。
これは、 git prune
が何も削除しないことを意味しています。
どういうことでしょうか。
Git はまだ 2 つ目のコミットに対しての「内部的な参照」を保持しています。
実はこれが、 git prune
単体で使われることがない大きな理由です。 ( 先程触れたように、 git gc
は git prune
を内部的に呼び出していますが、 git gc
はよく利用されます。 )
そうかんたんに 到達不能 なコミットは削除されない仕組みとなっています。 ( VCS としても Git の良さでもありますね。 )
Git が保持する「内部的な参照」は、 git reflog
コマンドを使って確認できます。git reflog
を使えば、今まで行ってきた一連の操作が表示されます。
Git は reflog の履歴情報に加えて、 reflog 内の 到達不能 コミットをいつ削除するかの情報 ( 有効期限 ) も持っています。
(このあたりも git gc
と git prune
の挙動の違いに関係しています。)
ようやくここまで来ました。それでは reflog の情報をクリアしてみます。
上記で実行したコマンドにより、reflog 内の現在日時( now
)よりも古いコミット履歴を強制的に有効期限切れにします。つまりすべての履歴情報をクリアしています。
(万が一のときに利用できる git reflog
情報を削除してしまうコマンドですので、あまり頻繁に利用するべきものではありませんし、使う必要もほぼありません。)
reflog が消えればようやく 到達不能 コミットへのすべての参照がなくなっています。
削除されることが確認できたので、 --dry-run
オプションを除去して正式に削除しましょう。
git prune
を手動実行する必要は殆どありません。
なぜなら、 git prune
を内包した git gc
コマンドが、 git pull
や git merge
、git rebase
、 git commit
といったコマンド実行時に、一定の条件を満たすと自動的に実行されるためです。
ひとこと
git prune
の仕組みを知ったからと言ってなにか得になるわけでもなさそうです。
ディスカッション
コメント一覧
まだ、コメントがありません