【入門編】git-filter-repoの先へ:コミットグラフを直接書き換えるためのPlumbingコマンド詳細解説 – バージョン管理・CI/CD活用バイブル

こんにちは。Gitの世界へようこそ。

普段、私たちは `git commit` や `git push` といった「Porcelain(磁器)」コマンドを使ってGitを操作しています。これらは非常に便利ですが、裏を返せば、Gitが内部でどうやってデータを保持しているのかという「本質」からは少し遠い場所にいるということです。

もし、歴史改変が必要な場面(例えば、誤ってコミットした巨大なバイナリの完全消去や、複雑に絡み合ったリポジトリの歴史の再構築)に直面したとき、`git filter-repo` のような高機能ツールですら「魔法」に見えてしまうかもしれません。

今回は、その「魔法」の正体を暴きます。Gitの心臓部である「Plumbing(配管)」コマンドを使い、コミットグラフを直接書き換える。この領域に踏み込むと、あなたはGitのマスターになります。

—

1. Gitの心臓部:Plumbingコマンドとは何か?

Gitは実は非常にシンプルな「キー・バリュー・ストア」です。すべてのデータは以下の3つのオブジェクトで管理されています。

  • Blob: ファイルの中身そのもの。
  • Tree: ディレクトリ構造。Blobや他のTreeへの参照を持つ。
  • Commit: Treeへのポインタ、親コミットへのポインタ、メタデータ。

これらを直接操作する「配管(Plumbing)」コマンドは、外科手術のような正確さを提供します。

2. 環境準備:実験場の作成

まずは、安全に破壊的な操作を行うための実験場を作りましょう。

実験用リポジトリの作成
mkdir git-lab && cd git-lab
git init
echo “Hello, Git-Plumbing!” > hello.txt
git add hello.txt
git commit -m “Initial commit”

3. 基礎セットアップ:オブジェクトを覗き見る

まず、現在のコミットがどうなっているか見てみましょう。

現在のHEADのハッシュを確認
git rev-parse HEAD

cat-fileでオブジェクトの中身を覗く (-pはpretty print)
git cat-file -p HEAD

ここで出力される `tree xxxx…` というのが、このコミットが指しているディレクトリ構造です。さらにその中身も見られます。

treeの中身を表示
git cat-file -p

—

4. HelloWorld:手動でコミットを作る

ここからが本題です。既存のコミットを無視して、手動で新しいコミットを作成してみます。

ステップ1:Blobを作成(ファイルを登録)

`hash-object` を使うと、ファイルをGitのデータベースに登録し、そのハッシュ値を得ることができます。

新しいファイルを作成してデータベースへ登録
echo “New content” > feature.txt
BLOB_HASH=$(git hash-object -w feature.txt)
echo “Blob created: $BLOB_HASH”

ステップ2:Treeを作成

`mktree` を使って、ファイル構造を定義します。

権限 100644 (通常ファイル), blobハッシュ, ファイル名
echo “100644 blob $BLOB_HASH feature.txt” | git mktree
出力されたツリーハッシュを保存
TREE_HASH=$(echo “100644 blob $BLOB_HASH feature.txt” | git mktree)

ステップ3:コミットを作成

`commit-tree` を使います。ここで親コミットを指定することで、グラフが繋がります。

親を指定してコミットを作成
COMMIT_HASH=$(echo “Manual commit from plumbing” | git commit-tree $TREE_HASH -p HEAD)
echo “New commit created: $COMMIT_HASH”

ステップ4:HEADを付け替える

最後に、作成したコミットを現在のブランチに反映させます。

git update-ref refs/heads/main $COMMIT_HASH
git reset –hard

—

5. なぜこのテクニックが最強なのか

「なぜわざわざ面倒なことを?」と思うかもしれません。しかし、この手法を知ると以下のことが可能になります。

1. 歴史の完全改竄: コミットの中身を微調整し、署名を保持したままグラフを繋ぎ変えることができます。
2. リポジトリの最適化: 肥大化したオブジェクトを手動で特定し、`filter-repo` でも消せないような深い傷跡を修正できます。
3. 自動化の極致: 複雑なマージアルゴリズムを自作し、CI上で動的なコミット生成を行うことができます。

先輩エンジニアからのアドバイス

この操作は、「Gitの仕組み」という地図を持つ者だけが許される特権です。操作を誤れば歴史が消滅しますが、`git reflog` がある限り、Gitは必ずあなたを救い出してくれます。

まずは、自分の捨ててもいいリポジトリで、今回紹介したコマンドを組み合わせて「コミットを捏造する」遊びから始めてみてください。それができれば、あなたはもうGitを「使う人」ではなく「操る人」です。

次は、これらを組み合わせて「コミットのタイムスタンプだけを書き換える」スクリプトに挑戦してみるのも面白いですよ。頑張ってくださいね!

タイトルとURLをコピーしました